MyBatis教程

MyBatis教程
Mr.Chen一、Mybatis简介
1.1 MyBatis历史
1 | MyBatis最初是Apache的一个开源项目iBatis, 2010年6月这个项目由Apache Software Foundation迁移到了Google Code。随着开发团队转投Google Code旗下,iBatis3.x正式更名为MyBatis。代码于2013年11月迁移到Github。 |
1.2 MyBatis特性
1 | 1. MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架 |
1.3 MyBatis下载
1.4 和其它持久化层技术对比
1 | JDBC |
二、搭建MyBatis
2.1 开发环境
1 | IDE:idea 2019.2 |
2.2 创建maven工程
- 打包方式:jar
- 引入依赖
1 | <dependencies> |
2.3 创建MyBatis的核心配置文件
1 | 习惯上命名为mybatis-config.xml,这个文件名仅仅只是建议,并非强制要求。将来整合Spring之后,这个配置文件可以省略,所以大家操作时可以直接复制、粘贴。 |
1 |
|
2.4 创建mapper接口
1 | MyBatis中的mapper接口相当于以前的dao。但是区别在于,mapper仅仅是接口,我们不需要提供实现类 |
1 | package com.atguigu.mybatis.mapper; |
2.5 创建MyBatis的映射文件
1 | 相关概念:ORM(Object Relationship Mapping)对象关系映射。 |
| Java概念 | 数据库概念 |
|---|---|
| 类 | 表 |
| 属性 | 字段/列 |
| 对象 | 记录/行 |
1 | 映射文件的命名规则 |
1 |
|
2.6 通过junit测试功能
1 | SqlSession:代表Java程序和数据库之间的会话。(HttpSession是Java程序和浏览器之间的会话) |
1 | public class UserMapperTest { |
1 | 此时需要手动提交事务,如果要自动提交事务,则在获取sqlSession对象时,使用`SqlSession sqlSession = sqlSessionFactory.openSession(true);`,传入一个Boolean类型的参数,值为true,这样就可以自动提交 |
2.7 加入log4j日志功能
2.7.1 加入依赖
1 | <!-- log4j日志 --> |
2.7.2 加入log4j的配置文件
1 | log4j的配置文件名为log4j.xml,存放的位置是src/main/resources目录下 |
1 |
|
三、核心配置文件详解
1 | 核心配置文件中的标签必须按照固定的顺序(有的标签可以不写,但顺序一定不能乱): |
1 |
|
四、默认的类型别名
五、MyBatis的增删改查
5.1 添加
1 | <!--int insertUser();--> |
5.2 删除
1 | <!--int deleteUser();--> |
5.3 修改
1 | <!--int updateUser();--> |
5.4 查询
5.4.1 查询一个实体类对象
1 | <!--User getUserById();--> |
5.4.2 查询集合
1 | <!--List<User> getUserList();--> |
1 | 注意: |
六、MyBatis获取参数值的两种方式(重点)
1 | MyBatis获取参数值的两种方式:${}和#{} |
6.1 单个字面量类型的参数
1 | 若mapper接口中的方法参数为单个的字面量类型,此时可以使用\${}和#{}以任意的名称(最好见名识意)获取参数的值,注意${}需要手动加单引号 |
1 | <!--User getUserByUsername(String username);--> |
1 | <!--User getUserByUsername(String username);--> |
6.2 多个字面量类型的参数
1 | 若mapper接口中的方法参数为多个时,此时MyBatis会自动将这些参数放在一个map集合中 |
1 | <!--User checkLogin(String username,String password);--> |
1 | <!--User checkLogin(String username,String password);--> |
6.3 map集合类型的参数
1 | 若mapper接口中的方法需要的参数为多个时,此时可以手动创建map集合,将这些数据放在map中只需要通过\${}和#{}访问map集合的键就可以获取相对应的值,注意${}需要手动加单引号 |
1 | <!--User checkLoginByMap(Map<String,Object> map);--> |
1 |
|
6.4 实体类类型的参数
1 | 若mapper接口中的方法参数为实体类对象时此时可以使用\${}和#{},通过访问实体类对象中的属性名获取属性值,注意${}需要手动加单引号 |
1 | <!--int insertUser(User user);--> |
1 |
|
6.5 使用@Param标识参数
1 | 可以通过@Param注解标识mapper接口中的方法参数,此时,会将这些参数放在map集合中 |
1 | <!--User CheckLoginByParam(@Param("username") String username, @Param("password") String password);--> |
1 |
|
总结
1 | 建议分成两种情况进行处理 |
七、MyBatis的各种查询功能
1 | 如果查询出的数据只有一条,可以通过 |
7.1 查询一个实体类对象
1 | /** |
1 | <!--User getUserById(@Param("id") int id);--> |
7.2 查询一个List集合
1 | /** |
1 | <!--List<User> getUserList();--> |
7.3 查询单个数据
1 | /** |
1 | <!--int getCount();--> |
7.4 查询一条数据为map集合
1 | /** |
1 | <!--Map<String, Object> getUserToMap(@Param("id") int id);--> |
7.5 查询多条数据为map集合
7.5.1 方法一
1 | /** |
1 | <!--Map<String, Object> getAllUserToMap();--> |
7.5.2 方法二
1 | /** |
1 | <!--Map<String, Object> getAllUserToMap();--> |
八、特殊SQL的执行
8.1 模糊查询
1 | /** |
1 | <!--List<User> getUserByLike(@Param("username") String username);--> |
1 | 其中`select * from t_user where username like "%"#{mohu}"%"`是最常用的 |
8.2 批量删除
1 | 只能使用\${},如果使用#{},则解析后的sql语句为`delete from t_user where id in ('1,2,3')`,这样是将`1,2,3`看做是一个整体,只有id为`1,2,3`的数据会被删除。正确的语句应该是`delete from t_user where id in (1,2,3)`,或者`delete from t_user where id in ('1','2','3')` |
1 | /** |
1 | <delete id="deleteMore"> |
1 | //测试类 |
8.3 动态设置表名
1 | 只能使用${},因为表名不能加单引号 |
1 | /** |
1 | <!--List<User> getUserByTable(@Param("tableName") String tableName);--> |
8.4 添加功能获取自增的主键
1 | 使用场景 |
1 | /** |
1 | <!--void insertUser(User user);--> |
1 | //测试类 |
九、自定义映射resultMap
9.1 resultMap处理字段和属性的映射关系
1 | resultMap:设置自定义映射 |
1 | 若字段名和实体类中的属性名不一致,则可以通过resultMap设置自定义映射,即使字段名和属性名一致的属性也要映射,也就是全部属性都要列出来 |
1 | <resultMap id="empResultMap" type="Emp"> |
1 | 若字段名和实体类中的属性名不一致,但是字段名符合数据库的规则(使用_),实体类中的属性名符合Java的规则(使用驼峰)。此时也可通过以下两种方式处理字段名和实体类中的属性的映射关系: |
1 | <!--List<Emp> getAllEmp();--> |
1 | <settings> |
9.2 多对一映射处理
1 | public class Emp { |
9.2.1 级联方式处理映射关系
1 | <resultMap id="empAndDeptResultMapOne" type="Emp"> |
9.2.2 使用association处理映射关系
1 | association:处理多对一的映射关系 |
1 | <resultMap id="empAndDeptResultMapTwo" type="Emp"> |
9.2.3 分步查询
9.2.3.1 查询员工信息
1 | select:设置分布查询的sql的唯一标识(namespace.SQLId或mapper接口的全类名.方法名) |
1 | /** |
1 | <resultMap id="empAndDeptByStepResultMap" type="Emp"> |
9.2.3.2 查询部门信息
1 | /** |
1 | <!--此处的resultMap仅是处理字段和属性的映射关系--> |
9.3 一对多映射处理
1 | public class Dept { |
9.3.1 collection
1 | collection:用来处理一对多的映射关系 |
1 | <resultMap id="DeptAndEmpResultMap" type="Dept"> |
9.3.2 分步查询
9.3.2.1 查询部门信息
1 | /** |
1 | <resultMap id="DeptAndEmpByStepOneResultMap" type="Dept"> |
9.3.2.2 根据部门id查询部门中的所有员工
1 | /** |
1 | <!--List<Emp> getDeptAndEmpByStepTwo(@Param("did") Integer did);--> |
9.4 延迟加载
1 | 分步查询的优点:可以实现延迟加载,但是必须在核心配置文件中设置全局配置信息: |
1 | <settings> |
1 |
|
1 | 关闭延迟加载,两条SQL语句都运行了 |
1 | 开启延迟加载,只运行获取emp的SQL语句 |
1 |
|
1 | 开启后,需要用到查询dept的时候才会调用相应的SQL语句 |
1 | fetchType:当开启了全局的延迟加载之后,可以通过该属性手动控制延迟加载的效果,fetchType="lazy(延迟加载)|eager(立即加载)" |
1 | <resultMap id="empAndDeptByStepResultMap" type="Emp"> |
十、动态SQL
1 | Mybatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能,它存在的意义是为了解决拼接SQL语句字符串时的痛点问题 |
10.1 if
1 | if标签可通过test属性(即传递过来的数据)的表达式进行判断,若表达式的结果为true,则标签中的内容会执行;反之标签中的内容不会执行 |
1 | <!--List<Emp> getEmpByCondition(Emp emp);--> |
10.2 where
1 | where和if一般结合使用: |
1 | <!--List<Emp> getEmpByCondition(Emp emp);--> |
1 | 注意:where标签不能去掉条件后多余的and/or |
1 | <!--这种用法是错误的,只能去掉条件前面的and/or,条件后面的不行--> |
10.3 trim
1 | trim用于去掉或添加标签中的内容 |
1 | <!--List<Emp> getEmpByCondition(Emp emp);--> |
1 | //测试类 |
10.4 choose、when、otherwise
1 | choose、when、otherwise相当于if...else if..else |
1 | <select id="getEmpByChoose" resultType="Emp"> |
1 |
|
1 | 相当于if a else if b else if c else d,只会执行其中一个 |
10.5 foreach
1 | 属性: |
10.5.1 批量删除
1 | <!--int deleteMoreByArray(Integer[] eids);--> |
1 |
|
10.5.2 批量添加
1 | <!--int insertMoreByList(@Param("emps") List<Emp> emps);--> |
1 |
|
10.6 SQL片段
1 | sql片段,可以记录一段公共sql片段,在使用的地方通过include标签进行引入 |
1 | <sql id="empColumns">eid,emp_name,age,sex,email</sql> |
1 | 引用sql片段:<include>标签 |
1 | <!--List<Emp> getEmpByCondition(Emp emp);--> |
十一、MyBatis的缓存
11.1 MyBatis的一级缓存
1 | 一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问 |
11.2 MyBatis的二级缓存
1 | 二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取 |
11.3 二级缓存的相关配置
1 | 在mapper配置文件中添加的cache标签可以设置一些属性 |
11.4 MyBatis缓存查询的顺序
1 | 先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用 |
11.5 整合第三方缓存EHCache(了解)
11.5.1 添加依赖
1 | <!-- Mybatis EHCache整合包 --> |
11.5.2 各个jar包的功能
| jar包名称 | 作用 |
|---|---|
| mybatis-ehcache | Mybatis和EHCache的整合包 |
| ehcache | EHCache核心包 |
| slf4j-api | SLF4J日志门面包 |
| logback-classic | 支持SLF4J门面接口的一个具体实现 |
11.5.3 创建EHCache的配置文件ehcache.xml
1 | 名字必须叫ehcache.xml |
1 |
|
11.5.4 设置二级缓存的类型
1 | 在xxxMapper.xml文件中设置二级缓存类型 |
1 | <cache type="org.mybatis.caches.ehcache.EhcacheCache"/> |
11.5.5 加入logback日志
1 | 存在SLF4J时,作为简易日志的log4j将失效,此时我们需要借助SLF4J的具体实现logback来打印日志。创建logback的配置文件logback.xml,名字固定,不可改变 |
1 |
|
11.5.6 EHCache配置文件说明
| 属性名 | 是否必须 | 作用 |
|---|---|---|
| maxElementsInMemory | 是 | 在内存中缓存的element的最大数目 |
| maxElementsOnDisk | 是 | 在磁盘上缓存的element的最大数目,若是0表示无穷大 |
| eternal | 是 | 设定缓存的elements是否永远不过期。 如果为true,则缓存的数据始终有效, 如果为false那么还要根据timeToIdleSeconds、timeToLiveSeconds判断 |
| overflowToDisk | 是 | 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上 |
| timeToIdleSeconds | 否 | 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时, 这些数据便会删除,默认值是0,也就是可闲置时间无穷大 |
| timeToLiveSeconds | 否 | 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大 |
| diskSpoolBufferSizeMB | 否 | DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区 |
| diskPersistent | 否 | 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false |
| diskExpiryThreadIntervalSeconds | 否 | 磁盘缓存的清理线程运行间隔,默认是120秒。每个120s, 相应的线程会进行一次EhCache中数据的清理工作 |
| memoryStoreEvictionPolicy | 否 | 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。 默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出 |
十二、MyBatis的逆向工程
1 | 正向工程:先创建Java实体类,由框架负责根据实体类生成数据库表。Hibernate是支持正向工程的 |
12.1 创建逆向工程的步骤
12.1.1 添加依赖和插件
1 | <dependencies> |
12.1.2 创建MyBatis的核心配置文件
1 |
|
12.1.3 创建逆向工程的配置文件
1 | 文件名必须是:generatorConfig.xml |
1 |
|
12.1.4 执行MBG插件的generate目标
1 | 如果出现报错:Exception getting JDBC Driver,可能是pom.xml中,数据库驱动配置错误.两者的驱动版本应该相同 |
1 | mybatis-generator-maven-plugin插件中的驱动 |
12.2 QBC
12.2.1 查询
1 | selectByExample:按条件查询,需要传入一个example对象或者null;如果传入一个null,则表示没有条件,也就是查询所有数据 |
1 | public void testMBG() throws IOException { |
12.2.2 增改
1 | updateByPrimaryKey:通过主键进行数据修改,如果某一个值为null,也会将对应的字段改为null |
1 | updateByPrimaryKeySelective():通过主键进行选择性数据修改,如果某个值为null,则不修改这个字段 |
十三、分页插件
13.1 分页插件使用步骤
13.1.1 添加依赖
1 | <!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper --> |
13.1.2 配置分页插件
1 | 在MyBatis的核心配置文件(mybatis-config.xml)中配置插件 |
1 | <plugins> |
13.2 分页插件的使用
13.2.1 开启分页功能
1 | 在查询功能之前使用`PageHelper.startPage(int pageNum, int pageSize)`开启分页功能 |
1 |
|
13.2.2 分页相关数据
方法一:直接输出
1 |
|
1 | 分页相关数据: |
1 | Page{count=true, pageNum=1, pageSize=4, startRow=0, endRow=4, total=8, pages=2, reasonable=false, pageSizeZero=false}[Emp{eid=1, empName='admin', age=22, sex='男', email='456@qq.com', did=3}, Emp{eid=2, empName='admin2', age=22, sex='男', email='456@qq.com', did=3}, Emp{eid=3, empName='王五', age=12, sex='女', email='123@qq.com', did=3}, Emp{eid=4, empName='赵六', age=32, sex='男', email='123@qq.com', did=1}] |
方法二:使用PageInfo
1 | 在查询获取list集合之后,使用`PageInfo<T> pageInfo = new PageInfo<>(List<T> list, intnavigatePages)`获取分页相关数据 |
1 |
|
1 | 分页相关数据: |
1 | PageInfo{ |
1 | 其中list中的数据等同于方法一中直接输出的page数据 |
常用数据:
1 | pageNum:当前页的页码 |
评论
匿名评论隐私政策
✅ 你无需删除空行,直接评论以获取最佳展示效果










































