一、mybatis缓存
1、mybatis一级缓存生效范围
一级缓存默认开启,关不掉。一级缓存的范围是同一个sqlSession对象
1.同一个mapper 【同一个sqlSession获取不同的mapper】。
SqlSession sqlSession=SqlSessionUtils.getSqlSession();
CacheMapper mapper1=sqlSession.getMapper(CacheMapper.class)
Emp emp1=mapper1.getEmpByEid(1);
System.out.println(emp1);
//因为一级缓存默认开启,使用缓存再查一次
Emp emp2=mapper1.getEmpByEid(2);
System.out.println(emp2);
2.不同的sqlSession.此时会打印俩条查询的sql,足以证明,一级缓存的范围就是同一个sqlSession
SqlSession sqlSession1=SqlSessionUtils.getSqlSession();
CacheMapper mapper1=sqlSession.getMapper(CacheMapper.class)
Emp emp1=mapper1.getEmpByEid(1);
System.out.println(emp1);
----------------------------------------------------
SqlSession sqlSession2=SqlSessionUtils.getSqlSession();
CacheMapper mapper2=sqlSession2.getMapper(CacheMapper.class)
Emp emp2=mapper.getEmpByEid(1);
System.out.println(emp2);
2、mybatis一级缓存失效情况
1、俩次查询之间有任意一次增删改都会清空缓存。缓存只是为了更高效的查询数据,而不能影响数据的真实性,缓存也就是把数据存到了内存中。
SqlSession sqlSession=SqlSessionUtils.getSqlSession();
CacheMapper mapper1=sqlSession.getMapper(CacheMapper.class)
Emp emp1=mapper1.getEmpByEid(1);
System.out.println(emp1);
//增加一个员工
mapper1.insert(new Emp(null,"alan","24","男"))
Emp emp2=mapper1.getEmpByEid(1);
System.out.println(emp2);
2.一级缓存失效第二种情况,自己手动清空缓存
SqlSession sqlSession=SqlSessionUtils.getSqlSession();
CacheMapper mapper1=sqlSession.getMapper(CacheMapper.class)
Emp emp1=mapper1.getEmpByEid(1);
System.out.println(emp1);
//手动清空缓存
sqlSession.clearCache();
Emp emp2=mapper1.getEmpByEid(1);
System.out.println(emp2);
3、mybatis二级缓存范围
二级缓存是SqlSessionFactory级别。同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存,此后再执行相同的查询语句,就会从缓存中获取。
二级缓存开启需要手动配置开启
1.在mybatis-config.xml中设置全局配置属性cacheEnabled="true",默认true,不需要设置
2.在mapper映射文件中设置标签<cache/>
3.在关闭或者提交了sqlSession之后才会保存到二级缓存
sqlSession.close(); sqlSession.commit();
4.查询的数据所转换的实体类类型必须实现序列化
public class User implements Serializable {}
5.先查询二级缓存,二级缓存没有命中再查询一级缓存
4、mybatis二级缓存生效范围测试
public void testMyBatis(){
try {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
//二级缓存有效前提是在同一个工厂
SqlSession sqlSession1 = sqlSessionFactory.openSession(true);
CacheMapper mapper1= sqlSession1.getMapper(CacheMapper.class);
System.out.println(mapper1.getEmpByEid(1))
//必须关闭了sqlSession二级缓存才能生效
sqlSession1.close();
--------------------------------------------------------------------------
SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
CacheMapper mapper2= sqlSession2.getMapper(CacheMapper.class);
System.out.println(mapper2.getEmpByEid(1))
sqlSession2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
5、mybatis二级缓存失效的情况
在俩次查询之间执行了任意的增删改,会使一级和二级缓存同时失效
二级缓存默认的缓存回收策略:LRU
LRU:移除最近最少使用的,即从缓存里移除长时间不被使用的对象
FIFO:先进先出策略,按照对象进入缓存的顺序来移除。
readOnly,默认false
为true就是只读缓存,会给所有调用者返回缓存对象的相同实例。这些对象不能被修改,有性能优势。
为false则是读写缓存,会返回缓存对象的拷贝(通过序列化),慢但是安全。
flushInterval,缓存刷新间隔,单位毫秒。
默认不设置即没有刷新间隔,仅在调用增删改语句的时候缓存刷新。
6、mybatis缓存查询机制
- 先查询二级缓存,二级缓存没有命中再查询一级缓存。
- 一级缓存也没有命中,则查询数据库。
一级缓存和二级缓存联系
sqlsession没有关闭之前,我们查出来的数据是默认保存在一级缓存中的。只有当sqlsession关闭之后,一级缓存中的数据会写入二级缓存。
7、整合第三方缓存 EHCache
可以使用第三方技术来代替mybatis二级缓存,但是一级缓存是没办法代替的。
<!--指定二级缓存的类型,不设置的话默认是mybatis自带的二级缓存-->
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
二、mybatis逆向工程
逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成如下资源:
Java实体类、Mapper接口、Mapper映射文件
只能简化单表的增删改查。
具体的做法很简单,搭建过程基本都是复制,使用就更简单了
1.添加依赖和插件
<!-- 控制Maven在构建过程中相关配置 -->
<build>
<!-- 构建过程中用到的插件 -->
<plugins>
<!-- 具体插件,逆向工程的操作是以构建过程中插件形式出现的 -->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.0</version>
<!-- 插件的依赖 -->
<dependencies>
<!-- 逆向工程的核心依赖 -->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.2</version>
</dependency>
<!-- 数据库连接池 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.2</version>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
2.resources下创建逆向工程的配置文件generatorConfig.xml
注意修改 <jdbcConnection>数据库的连接信息
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!--
targetRuntime: 执行生成的逆向工程的版本
MyBatis3Simple: 生成基本的CRUD(清新简洁版)
MyBatis3: 生成带条件的CRUD(奢华尊享版)
-->
<context id="DB2Tables" targetRuntime="MyBatis3">
<!-- 数据库的连接信息 -->
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/test?serverTimezone=UTC"
userId="root"
password="123456">
</jdbcConnection>
<!-- javaBean的生成策略-->
<javaModelGenerator targetPackage="com.atguigu.mybatis.pojo" targetProject=".\src\main\java">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- SQL映射文件的生成策略 -->
<sqlMapGenerator targetPackage="com.atguigu.mybatis.mapper" targetProject=".\src\main\resources">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<!-- Mapper接口的生成策略 -->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.atguigu.mybatis.mapper" targetProject=".\src\main\java">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<!-- 逆向分析的表 -->
<!-- tableName设置为*号,可以对应所有表,此时不写domainObjectName -->
<!-- domainObjectName属性指定生成出来的实体类的类名 -->
<table tableName="t_order" domainObjectName="Order"/>
<!-- <table tableName="t_dept" domainObjectName="Dept"/>-->
</context>
</generatorConfiguration>
3.执行逆向工程,双击MBG插件。(mybatis.generator)
targetRuntime生成不同的版本 MyBatis3Simple: 生成基本的CRUD(清新简洁版) MyBatis3: 生成带条件的CRUD(奢华尊享版)
清新简洁版就是只有增删改查5个方法,根据id修改,根据id查询 和查询所有数据
奢华尊享版就很牛了,OrderExample设置条件
着重讲一下OrderExample的使用
1、查询所有的信息,把条件设置为null
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
//查询所有数据
List<Order> orderList = orderMapper.selectByExample(null);
orderList.forEach(System.out::println);
2.查询order_name是AA或者JJ的订单信息
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
//查询order_name是AA或者JJ的订单信息
OrderExample orderExample = new OrderExample();
orderExample.createCriteria().andOrderNameEqualTo("AA");
orderExample.or().andOrderNameEqualTo("JJ");
List<Order> orders = orderMapper.selectByExample(orderExample);
orders.forEach(System.out::println);
3.查询订单id大于等于3的订单信息
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
//查询订单id大于等于3的订单信息
OrderExample orderExample = new OrderExample();
orderExample.createCriteria().andOrderIdGreaterThanOrEqualTo(3);
List<Order> orders = orderMapper.selectByExample(orderExample);
orders.forEach(System.out::println);
4.选择性添加
普通的添加,哪怕是null,也会添加。
Order order = new Order(7, null, new Date());
orderMapper.insert(order);
选择性添加:根据属性的值,来决定是否给这个字段赋值。
Order order = new Order(8, null, new Date());
orderMapper.insertSelective(order);
不设置默认值,普通添加和选择性添加一样。
设置了默认值,普通添加就是null,选择性添加就是默认值
5.选择性修改
根据主键修改,orderDate为null,也会修改数据库
Order order = new Order(5, "JJ", null);
orderMapper.updateByPrimaryKey(order);
选择性修改:orderDate为null,这个字段在数据表里不会被修改
Order order = new Order(6, "J2", null);
orderMapper.updateByPrimaryKeySelective(order);
三、mybatis分页插件
limit 4,其实就是limit 0,4
limlit((当前页数-1)*每页页数,每页页数)
limit(index,pageSize)
index:当前页的起始索引
pageSize:当前页条数index=(pageNum-1)*pageSize
totalCount:总记录数
总页数:totalPage=totalCount/pageSize
if(totalCount%pageSize!=0){
totalPage+=1;
}
分页插件的使用步骤
1.pom.xm添加依赖
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.0</version>
</dependency>
2.在mybatis-config.xml中配置插件
<plugins>
<!--设置分页插件-->
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
3.在查询之前开启分页功能
PageHelper.startPage();写在查询之前
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
//在查询之前开启分页功能
Page<Object> page = PageHelper.startPage(2, 2);
List<Order> orderList = orderMapper.selectByExample(null);
System.out.println(page);
会执行2条sql,第一条查询总记录数,第二条才是我们正真的查询功能
Page对象,简单的封装,继承了ArrayList。可以用来存储数据,再细致就得用PageInfo了
//Page{count=true, pageNum=2, pageSize=2, startRow=2, endRow=4, total=7, pages=4,
//reasonable=false, pageSizeZero=false}
//Order{orderId=4, orderName='GG', orderDate=Tue Jun 28 08:00:00 CST 1994},
//Order{orderId=5, orderName='JJ', orderDate=null}]
4.在查询获取list集合之后,获取分页相关数据
PageInfo必须写在查询之后。
PageInfo<T> pageInfo = new PageInfo<>(List<T> list, int navigatePages)
list:分页之后的数据
navigatePages:导航分页的页码数
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
Page<Object> page = PageHelper.startPage(2, 2);
List<Order> orderList = orderMapper.selectByExample(null);
PageInfo<Order> pageInfo = new PageInfo(orderList,5);
System.out.println(pageInfo);
此时打印得pageInfo那信息量就多了。其中得list属性就是上面所打印得page信息