MyBatis学习总结(四)——MyBatis缓存与代码生成

目录 一、MyBatis缓存 1.0、再次封装SqlSessionFactoryUtils 1.1、MyBatis缓存概要 1.2、默认MyBatis的一级缓存是开启的 1.3、一级缓存仅在同一个会话(SQLSession)中有效 1.4、清空一级缓存 1.5、开启二级缓存 1.5.1、全局开关 1.5.2、单个Mapper XML映射文件开关 1.5.3、Mapper statement开关 1.5.4、实现可序列化接口 1.5.5、注意事项 1.6、二级缓存测试 1.7、二级缓存小结 二、MyBatis-Generator代码生成 2.1、在Intellij IDEA创建maven项目 2.2、添加依赖 2.3、配置生成参数 2.4、执行生成 2.5、使用生成的代码 三、MyBatis-GUI代码生成器mybatis-generator-gui 3.1、概要 3.2、核心特性 3.3、要求 3.4、下载 3.5、启动本软件 3.6、注意事项 3.7、文档 3.8、代码生成示例 四、示例源代码 五、视频 六、大作业 一、MyBatis缓存 缓存可以提高系统性能,可以加快访问速度,减轻服务器压力,带来更好的用户体验。缓存用空间换时间,好的缓存是缓存命中率高的且数据量小的。缓存是一种非常重要的技术。 1.0、再次封装SqlSessionFactoryUtils 为了配置缓存的学习我们将工具类再次封装。 原SqlSessionFactoryUtil工具类如下: View Code 上面的代码中当我们每次获取SQLSession时都要实例化sqlSessionFactory,效率不高。可以使用单例改进: 复制代码 package com.zhangguo.mybatis03.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; /** * MyBatis会话工具类 * */ public class SqlSessionFactoryUtils { /**会话工厂*/ private static SqlSessionFactory factory; static { try { /*获得配置文件的文件流*/ InputStream inputStream=Resources.getResourceAsStream("mybatisCfg.xml"); //初始化工厂 factory=new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } /** * 获得会话对象 * 指定是否自动提交 * */ public static SqlSession openSqlSession(boolean isAutoCommit){ return getFactory().openSession(isAutoCommit); } public static SqlSessionFactory getFactory() { return factory; } public static void setFactory(SqlSessionFactory factory) { SqlSessionFactoryUtils.factory = factory; } /** * 关闭会话 * */ public static void closeSession(SqlSession session){ if(session!=null){ session.close(); } } } 复制代码 1.1、MyBatis缓存概要 在一个系统中查询的频次远远高于增删改,据三方统计不同系统比例在9:1-7:3之间。正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持 (1)、一级缓存基于PerpetualCache 的 HashMap本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该Session中的所有 Cache 就将清空。 (2)、二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。 (3)、对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespaces)的进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。 1.2、默认MyBatis的一级缓存是开启的 测试用例: 复制代码 /**缓存测试*/ @Test public void cacheTest(){ //打开一个会话,不自动提交 SqlSession session1 = SqlSessionFactoryUtils.openSqlSession(false); //获得一个映射器 StudentMapper mapper1 = session1.getMapper(StudentMapper.class); //查询单个对象通过编号 Student student1 = mapper1.selectStudentById(1); System.out.println(student1); Student student2 = mapper1.selectStudentById(1); System.out.println(student2); //关闭 SqlSessionFactoryUtils.closeSession(session1); } 复制代码 结果: 虽然查询了二次,但只向数据库发送了一次SQL请求,因为第二次是在缓存中获得的数据。 1.3、一级缓存仅在同一个会话(SQLSession)中有效 测试用例: 复制代码 /**缓存测试*/ @Test public void cacheTest(){ //打开一个会话1,不自动提交 SqlSession session1 = SqlSessionFactoryUtils.openSqlSession(false); //获得一个映射器 StudentMapper mapper1 = session1.getMapper(StudentMapper.class); //查询单个对象通过编号 Student student1 = mapper1.selectStudentById(1); System.out.println(student1); //打开一个会话2,不自动提交 SqlSession session2 = SqlSessionFactoryUtils.openSqlSession(false); //获得一个映射器 StudentMapper mapper2 = session2.getMapper(StudentMapper.class); Student student2 = mapper2.selectStudentById(1); System.out.println(student2); //关闭 SqlSessionFactoryUtils.closeSession(session1); } 复制代码 结果: 从上图可以看出此时并没有使用缓存,向数据库查询了二次,因为第二次查询使用的是新的会话,而一级缓存必须在同一个会话中。 1.4、清空一级缓存 (1)、当对表执行增删改时缓存将清空 测试用例: 复制代码 /**缓存测试*/ @Test public void cacheTest(){ //打开一个会话1,不自动提交 SqlSession session1 = SqlSessionFactoryUtils.openSqlSession(false); //获得一个映射器 StudentMapper mapper1 = session1.getMapper(StudentMapper.class); //查询单个对象通过编号 Student student1 = mapper1.selectStudentById(1); System.out.println(student1); //执行更新 Student lili=new Student(); lili.setId(5); lili.setSex("girl"); mapper1.updateStudent(lili); Student student2 = mapper1.selectStudentById(1); System.out.println(student2); SqlSessionFactoryUtils.closeSession(session1); } 复制代码 结果: 从日志中可以看出第二次查询也发送了sql到数据库中,并没有使用缓存,是因为执行了更新操作缓存已被清空。 此时数据库中的数据其实并未真的更新,如下所示: 因为没有手动提交,可以设置自动提交 View Code 提交后的结果 (2)、手动清空 测试用例: 复制代码 /**缓存测试*/ @Test public void cacheTest(){ //打开一个会话1,不自动提交 SqlSession session1 = SqlSessionFactoryUtils.openSqlSession(false); //获得一个映射器 StudentMapper mapper1 = session1.getMapper(StudentMapper.class); //查询单个对象通过编号 Student student1 = mapper1.selectStudentById(1); System.out.println(student1); //执行手动更新 session1.clearCache(); Student student2 = mapper1.selectStudentById(1); System.out.println(student2); //提交 session1.commit(); SqlSessionFactoryUtils.closeSession(session1); } 复制代码 结果: 从日志中可以看到第二次查询并未使用缓存因为执行了手动清空缓存,没有缓存可用则再次查询数据库。 小结:当Session flush或close之后,该Session中的所有 Cache 就将清空;执行CUD也将会自动清空;手动清空; 1.5、开启二级缓存 默认二级缓存是不开启的,需要手动进行配置: 1.5.1、全局开关 默认是true,如果它配成false,其余各个Mapper XML文件配成支持cache也没用。 复制代码 复制代码 1.5.2、单个Mapper XML映射文件开关 默认Mapper XML映射文件是不采用cache。在配置文件加一行就可以支持cache: 复制代码 复制代码 可以在开启二级缓存时候,手动配置一些属性 各个属性意义如下: eviction:缓存回收策略 - LRU:最少使用原则,移除最长时间不使用的对象 - FIFO:先进先出原则,按照对象进入缓存顺序进行回收 - SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象 - WEAK:弱引用,更积极的移除移除基于垃圾回收器状态和弱引用规则的对象 flushInterval:刷新时间间隔,单位为毫秒,这里配置的100毫秒。如果不配置,那么只有在进行数据库修改操作才会被动刷新缓存区 size:引用额数目,代表缓存最多可以存储的对象个数 readOnly:是否只读,如果为true,则所有相同的sql语句返回的是同一个对象(有助于提高性能,但并发操作同一条数据时,可能不安全),如果设置为false,则相同的sql,后面访问的是cache的clone副本。 1.5.3、Mapper statement开关 Mapper XML文件配置支持cache后,文件中所有的Mapper statement就支持了。此时要个别对待某条,需要: 复制代码 复制代码 可以在Mapper的具体方法下设置对二级缓存的访问意愿: useCache配置 ​ 如果一条语句每次都需要最新的数据,就意味着每次都需要从数据库中查询数据,可以把这个属性设置为false,如: