最初是一个Apache的开源项目iBatis,2010年迁移至了Google Code,从3.x开始 更名为MyBatis,2013年迁移至GitHub
iBatis == internet + abatis
是一个基于java的持久层框架,提供 SQL Maps & Data Access Object(DAO)
IDE:idea 2019.2
构建工具:maven 3.5.4
MySQL版本:MySQL 8
MyBatis版本:MyBatis 3.5.7
首先创建主工程SSM,
再添加子工程MyBatis
可以直接在主工程中添加这个打包方式
jar
在maven中指定打包的方式
org.mybatis
mybatis
3.5.7
junit
junit
4.12
test
mysql
mysql-connector-java
8.0.16
src/main/resource
用于配制数据库连接环境 & Mybatis 全局配置信息
习惯上命名为mybatis-config.xml
相当于之前的dao
区别:mapper仅仅是interface ,不需要实例化
public interface UserMapper {
/**
* 添加用户信息 */
int insertUser();
}
ORM:Object Releationship Mapping 对象映射关系
Java概念 | 数据库概念 |
---|---|
类 | 表 |
属性 | 字段/列 |
对象 | 记录/行 |
1、映射文件的命名规则:
表所对应的实体类的类名+Mapper.xml
例如:表t_user,映射的实体类为User,所对应的映射文件为UserMapper.xml
因此一个映射文件对应一个实体类,对应一张表的操作 MyBatis映射文件用于编写SQL,访问以及操作表中的数据 MyBatis映射文件存放的位置是src/main/resources/mappers目录下
2、 MyBatis中可以面向接口操作数据,要保证两个一致:
insert into User (username,password,age,gender,email) values('admin2','123456',23,'男','12345@qq.com')
CREATE TABLE `User` (
`id` BIGINT(19) AUTO_INCREMENT primary key NOT NULL,
`username` VARCHAR(64) NOT NULL,
`password` VARCHAR(64) NOT NULL,
`age` VARCHAR(64) NOT NULL,
`gender` VARCHAR(64) NOT NULL,
`email` VARCHAR(64) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
package org.example.mybatis.test;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.example.mybatis.mapper.UserMapper;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
public class MybatisTest {
@Test
public void testInsert() throws IOException {
//TODO 1 获取核心配置文件的输入流
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
//TODO 2 sqlSessionFactoryBuilder 对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
//TODO 3 获取SqlSessionBuilder 对象
SqlSessionFactory SqlSessionBuilder = sqlSessionFactoryBuilder.build(is);
//TODO 4 获取sqlSession,是Mybatis提供的操作数据库表的对象
// SqlSession sqlSession = SqlSessionBuilder.openSession(); 不会自动提交
SqlSession sqlSession = SqlSessionBuilder.openSession(true);
//TODO 5 获取UserMapper接口的实现类对象 (代理模式)
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//TODO 6 调用mapper接口中的方法,实现添加用户信息的功能
int result = mapper.insertUser();
//TODO 7 也可以直接用sqlSession 通过唯一标识(namespace.sqlId) 来找到sql
int result2 = sqlSession.insert("org.example.mybatis.mapper.UserMapper.insertUser");
System.out.println("result = " + result);
System.out.println("result2 = " + result2);
sqlSession.commit();//提交事务
sqlSession.close();
}
}
resource/log4j.xml
日志的级别
FATAL(致命)>ERROR(错误)>WARN(警告)>INFO(信息)>DEBUG(调试) 从左到右打印的内容越来越详细
package org.example.mybatis.utils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
public class SqlSessionUtil {
public static SqlSession getSqlSession(){
SqlSession sqlSession = null;
try {
//获取核心配置文件的输入流
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
//获取sqlSessionFactoryBuilder
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
//获取sqlSessionFactory
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
//获取sqlSession 对象
sqlSession = sqlSessionFactory.openSession(true);
} catch (IOException e) {
throw new RuntimeException(e);
}
return sqlSession;
}
}
@Test
public void testUpdate(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.updateUser();
sqlSession.close();
}
The content of element type "configuration" must match "
(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,
objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?)".
可以将一些基本的 username password 配置到 jdbc.properties中,然后在
mybatis-config.xml中进行引用
就需要用到了 properties标签
在 UserMapper.xml中 ,这个resultType 用全类名难免有点繁琐
可以在 mybatis-config.xml 中起别名
批量引入mapper
${} 的本质 字符串拼接
若为字符串类型或日期类型的字段进行赋值,需要手动加单引号
#{} 的本质 占位符赋值
为字符串或日期类型的字段进行赋值,会自动加单引号
mapper 接口有多个接口,Mybatis会将参数放到map 集合中,以两种方式存储数据
arg0 , arg1
param1 , param2
手动放入集合,可以通过自己定义的key访问
List checkLoginByMap(Map map);
@Test
public void testCheckLoginByMap(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
HashMap map = new HashMap<>();
map.put("username","admin2");
map.put("password","123456");
List users = mapper.checkLoginByMap(map);
Iterator iterator = users.iterator();
while (iterator.hasNext()){
User next = iterator.next();
System.out.println(next);
}
}
直接访问属性名
相当于指定 map 的key
方式一
/**
* 查询所有用户信息为map集合
* @return
* 将表中的数据以map集合的方式查询,一条数据对应一个map;若有多条数据,就会产生多个map集合,此 时可以将这些map放在一个list集合中获取
*/
List
方式二
/**
* 查询所有用户信息为map集合
* @return
* 将表中的数据以map集合的方式查询,一条数据对应一个map;若有多条数据,就会产生多个map集合,并 且最终要以一个map的方式返回数据,此时需要通过@MapKey注解设置map集合的键,值是每条数据所对应的 map集合
*/
@MapKey("id")
Map getAllUserToMap();
/**
* 测试模糊查询 * @param mohu * @return
*/
List testMohu(@Param("mohu") String mohu);
/**
* 动态设置表名,查询所有的用户信息 * @param tableName
* @return
*/
List getAllUser(@Param("tableName") String tableName);
CREATE TABLE MyBatis.t_emp (
emp_id BIGINT(19) AUTO_INCREMENT primary key NOT NULL,
emp_name varchar(100) NULL,
age INT NULL,
gender varchar(100) NULL,
dept_id INT NULL
)
ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_0900_ai_ci;
CREATE TABLE MyBatis.t_dept (
dept_id BIGINT(19) AUTO_INCREMENT primary key NOT NULL,
dept_name varchar(100) NULL
)
ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_0900_ai_ci;
问题分析
字段名 和 属性名字 不一致的情况
如何处理这种关系
当字段名符合MySQL的要求 _ , 属性名 驼峰,可以在mybatis的核心配置文件设置一个全局配置,可以将 _ 自动映射为驼峰
resultType 写的是一个具体的类型
resultMap 写的是一个自定义的映射关系
在emp中加入dept 属性
/**
* 通过分步查询查询员工信息 * @param eid
* @return
*/
Emp getEmpByStep(@Param("eid") int eid);
/**
* 分步查询的第二步: 根据员工所对应的did查询部门信息 * @param did
* @return
*/
Dept getEmpDeptByStep(@Param("did") int did);
分步查询的优点:可以实现延迟加载
但是必须在核心配置文件中设置全局配置信息:
lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载
aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属 性会按需加载
此时就可以实现按需加载,获取的数据是什么,就只会执行相应的sql。此时可通过association和 collection中的fetchType属性设置当前的分步查询是否使用延迟加载, fetchType=“lazy(延迟加 载)|eager(立即加载)”
在resultMap中进行设置
也可以通过分步查询来解决
根据特定条件,动态拼装SQL语句的功能
批量添加 批量删除
insert into t_emp (emp_name,age,gender,dept_id) values
('admin2',23,'男',1)
(#{emp.empName},#{emp.age},#{emp.gender})
@Test
public void testInsertMoreEmp(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
Emp emp1 = new Emp(null, "Tom1", 20, "男");
Emp emp2 = new Emp(null, "Tom2", 20, "男");
Emp emp3 = new Emp(null, "Tom3", 20, "男");
List emps = Arrays.asList(emp1, emp2, emp3);
int i = mapper.insertMoreEmp(emps);
System.out.println("result = " + i);
}
eid,ename,age,sex,did
select from t_emp
正向工程:先创建Java实体类,由框架负责根据实体类生成数据库表。 Hibernate是支持正向工程的。
逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成如下资源:
org.mybatis
mybatis
3.5.7
junit
junit
4.12
test
log4j
log4j
1.2.17
mysql
mysql-connector-java
8.0.16
org.mybatis.generator
mybatis-generator-maven-plugin
1.3.0
org.mybatis.generator
mybatis-generator-core
1.3.2
mysql
mysql-connector-java
8.0.16
名字必须是 generatorConfig.xml
targetRuntime: 执行生成的逆向工程的版本 MyBatis3Simple: 生成基本的CRUD(清新简洁版) MyBatis3: 生成带条件的CRUD
limit index,pageSize
pageSize:每页显示的条数
pageNum:当前页的页码 index:当前页的起始索引,index=(pageNum-1)*pageSize count:总记录数
totalPage:总页数
totalPage = count / pageSize;
if(count % pageSize != 0){
totalPage += 1;
}
pageSize=4,pageNum=1,index=0 limit 0,4 pageSize=4,pageNum=3,index=8 limit 8,4 pageSize=4,pageNum=6,index=20 limit 8,4
首页 上一页 2 3 4 5 6 下一页 末页
com.github.pagehelper
pagehelper
5.2.0
@Test void testPage(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//查询之前开启分页功能
Page list = PageHelper.startPage(1, 4);
List users = mapper.selectByExample(null);
//查询之后可以获取分页相关的所有数据
PageInfo userPageInfo = new PageInfo<>(users, 5);
}
可以根据这个userPageInfo 做更多的处理,提供的方法如下
PageInfo{
pageNum=8, pageSize=4, size=2, startRow=29, endRow=30, total=30, pages=8, list=Page{count=true, pageNum=8, pageSize=4, startRow=28, endRow=32, total=30, pages=8, reasonable=false, pageSizeZero=false},
prePage=7, nextPage=0, isFirstPage=false, isLastPage=true, hasPreviousPage=true, hasNextPage=false, navigatePages=5, navigateFirstPage4, navigateLastPage8, navigatepageNums=[4, 5, 6, 7, 8]
}
pageNum:当前页的页码
pageSize:每页显示的条数
size:当前页显示的真实条数
total:总记录数
pages:总页数
prePage:上一页的页码
nextPage:下一页的页码
isFirstPage/isLastPage:是否为第一页/最后一页 hasPreviousPage/hasNextPage:是否存在上一页/下一页 navigatePages:导航分页的页码数
navigatepageNums:导航分页的页码,[1,2,3,4,5]