MyBatis的其他操作
1、MyBatis的缓存
1.1、MyBatis的一级缓存
- 一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问
 使一级缓存失效的四种情况:
- 不同的SqlSession对应不同的一级缓存
 - 同一个SqlSession但是查询条件不同
 - 同一个SqlSession两次查询期间执行了任何一次增删改操作
 - 同一个SqlSession两次查询期间手动清空了缓存
 
1.2、MyBatis的二级缓存
- 二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取
 二级缓存开启的条件
- 在核心配置文件中,设置全局配置属性cacheEnabled=”true”,默认为true,不需要设置
 - 在映射文件中设置标签
 - 二级缓存必须在SqlSession关闭或提交之后有效
 - 查询的数据所转换的实体类类型必须实现序列化的接口
 
使二级缓存失效的情况:两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效
1.3、二级缓存的相关配置
- 在mapper配置文件中添加的cache标签可以设置一些属性
 - eviction属性:缓存回收策略  
- LRU(Least Recently Used) – 最近最少使用的:移除最长时间不被使用的对象。
 - FIFO(First in First out) – 先进先出:按对象进入缓存的顺序来移除它们。
 - SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
 - WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
 - 默认的是 LRU
 
 - flushInterval属性:刷新间隔,单位毫秒,默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句(增删改)时刷新
 - size属性:引用数目,正整数代表缓存最多可以存储多少个对象,太大容易导致内存溢出
 - readOnly属性:只读,true/false
- true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。
 - false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false
 
 
1.4、MyBatis缓存查询的顺序
- 先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用
 - 如果二级缓存没有命中,再查询一级缓存
 - 如果一级缓存也没有命中,则查询数据库
 - SqlSession关闭之后,一级缓存中的数据会写入二级缓存
 
1.5整合第三方缓存EHCache(了解)
添加依赖
1  | <!-- Mybatis EHCache整合包 -->  | 
各个jar包的功能
| jar包名称 | 作用 | 
|---|---|
| mybatis-ehcache | Mybatis和EHCache的整合包 | 
| ehcache | EHCache核心包 | 
| slf4j-api | SLF4J日志门面包 | 
| logback-classic | 支持SLF4J门面接口的一个具体实现 | 
创建EHCache的配置文件ehcache.xml
- 名字必须叫
ehcache.xml 
1  | 
  | 
设置二级缓存的类型
- 在xxxMapper.xml文件中设置二级缓存类型
 
1  | <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>  | 
加入logback日志
- 存在SLF4J时,作为简易日志的log4j将失效,此时我们需要借助SLF4J的具体实现logback来打印日志。创建logback的配置文件
logback.xml,名字固定,不可改变 
1  | 
  | 
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(先进先出 | 
2、MyBatis的逆向工程
- 正向工程:先创建Java实体类,由框架负责根据实体类生成数据库表。Hibernate是支持正向工程的
 - 逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成如下资源:  
- Java实体类
 - Mapper接口
 - Mapper映射文件
 
 
2.1、创建逆向工程的步骤
添加依赖和插件
1  | <dependencies>  | 
创建MyBatis的核心配置文件
1  | 
  | 
创建逆向工程的配置文件
- 文件名必须是:
generatorConfig.xml 
1  | 
  | 
执行MBG插件的generate目标

如果出现报错:Exception getting JDBC Driver,可能是pom.xml中,数据库驱动配置错误
dependency中的驱动

mybatis-generator-maven-plugin插件中的驱动

两者的驱动版本应该相同
执行结果

2.2、QBC
2.2.1、查询
selectByExample:按条件查询,需要传入一个example对象或者null;如果传入一个null,则表示没有条件,也就是查询所有数据example.createCriteria().xxx:创建条件对象,通过andXXX方法为SQL添加查询添加,每个条件之间是and关系example.or().xxx:将之前添加的条件通过or拼接其他条件
1  | public void testMBG() throws IOException {  | 

2.2.2、增改
updateByPrimaryKey:通过主键进行数据修改,如果某一个值为null,也会将对应的字段改为nullmapper.updateByPrimaryKey(new Emp(1,"admin",22,null,"456@qq.com",3));
updateByPrimaryKeySelective():通过主键进行选择性数据修改,如果某个值为null,则不修改这个字段mapper.updateByPrimaryKeySelective(new Emp(2,"admin2",22,null,"456@qq.com",3));
3、分页插件
3.1、分页插件使用步骤
添加依赖
1  | <!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->  | 
配置分页插件
在MyBatis的核心配置文件(mybatis-config.xml)中配置插件

1  | <plugins>  | 
3.2、分页插件的使用
3.2.1开启分页功能
- 在查询功能之前使用
PageHelper.startPage(int pageNum, int pageSize)开启分页功能- pageNum:当前页的页码
 - pageSize:每页显示的条数
 
 
1  | 
  | 

3.2.2、分页相关数据
方法一:直接输出
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
- 在查询获取list集合之后,使用
PageInfo<T> pageInfo = new PageInfo<>(List<T> list, intnavigatePages)获取分页相关数据- list:分页之后的数据  
- navigatePages:导航分页的页码数
 
 
 - list:分页之后的数据  
 
1  | 
  | 
分页相关数据:
1
2
3
4PageInfo{
pageNum=1, pageSize=4, size=4, startRow=1, endRow=4, total=8, pages=2,
list=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}],
prePage=0, nextPage=2, isFirstPage=true, isLastPage=false, hasPreviousPage=false, hasNextPage=true, navigatePages=5, navigateFirstPage=1, navigateLastPage=2, navigatepageNums=[1, 2]}其中list中的数据等同于方法一中直接输出的page数据
3.2.3、常用数据:
- pageNum:当前页的页码
 - pageSize:每页显示的条数
 - size:当前页显示的真实条数
 - total:总记录数
 - pages:总页数
 - prePage:上一页的页码
 - nextPage:下一页的页码
 - isFirstPage/isLastPage:是否为第一页/最后一页
 - hasPreviousPage/hasNextPage:是否存在上一页/下一页
 - navigatePages:导航分页的页码数
 - navigatepageNums:导航分页的页码,[1,2,3,4,5]
 
 评论
GitalkDisqus





