一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问
使一级缓存失效的四种情况:
1、不同的SqlSession对应不同的一级缓存
2、同一个SqlSession但是查询条件不同
3、同一个SqlSession两次查询期间执行了任何一次增删改操作
4、同一个SqlSession两次查询期间调用 clearCache()方法 手动清空了缓存
@Test
public void testGetEmpById(){
SqlSession sqlSession1 = SqlSessionUtil.getSqlSession();
CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
Emp emp1 = mapper1.getEmpById(1);
System.out.println(emp1);
sqlSession1.clearCache();//手动清空一级缓存
//mapper1.insertEmp(new Emp(null, "小红", 25, "男"));
Emp emp2 = mapper1.getEmpById(1);
System.out.println(emp2);
/*SqlSession sqlSession2 = SqlSessionUtil.getSqlSession();
CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);
Emp emp3 = mapper2.getEmpById(1);
System.out.println(emp3);*/
}
二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取
二级缓存开启的条件:
1、在核心配置文件中,设置全局配置属性cacheEnabled="true",默认为true,不需要设置
2、在映射文件中设置
3、二级缓存必须在SqlSession关闭或提交之后有效
4、查询的数据所转换的实体类类型必须实现序列化的接口 Serializable
使二级缓存失效的情况:
两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效
@Test
public void testCache() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession1 = sqlSessionFactory.openSession(true);
CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
Emp emp1 = mapper1.getEmpById(1);
System.out.println(emp1);
sqlSession1.close();
SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);
Emp emp2 = mapper2.getEmpById(1);
System.out.println(emp2);
sqlSession2.close();
}
在mapper配置文件中添加的cache标签可以设置一些属性:
1、eviction属性:缓存回收策略,默认的是 LRU。
LRU(Least Recently Used)– 最近最少使用的:移除最长时间不被使用的对象。
FIFO(First in First out)– 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
2、flushInterval属性:刷新间隔,单位毫秒
默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新(增删改)
3、size属性:引用数目,正整数
代表缓存最多可以存储多少个对象,太大容易导致内存溢出
4、readOnly属性:只读, true / false
true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。
false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是 false。
先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用。
如果二级缓存没有命中,再查询一级缓存
如果一级缓存也没有命中,则查询数据库
SqlSession关闭之后,一级缓存中的数据会写入二级缓存
org.mybatis.caches
mybatis-ehcache
1.2.1
ch.qos.logback
logback-classic
1.2.3
存在SLF4J时,作为简易日志的log4j将失效,此时我们需要借助SLF4J的具体实现logback来打印日 志。 创建logback的配置文件logback.xml
[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger]
[%msg]%n
正向工程:先创建Java实体类,由框架负责根据实体类生成数据库表。 Hibernate是支持正向工 程的。
逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成如下资源:
- Java实体类
- Mapper接口
- Mapper映射文件
①添加依赖和插件
org.mybatis
mybatis
3.5.13
junit
junit
4.12
test
mysql
mysql-connector-java
5.1.32
log4j
log4j
1.2.17
org.mybatis.generator
mybatis-generator-maven-plugin
1.3.0
org.mybatis.generator
mybatis-generator-core
1.3.2
mysql
mysql-connector-java
5.1.32
②创建MyBatis的核心配置文件
③创建逆向工程的配置文件
文件名必须是:generatorConfig.xml
④执行MBG插件的generate目标
⑤效果
@Test
public void testMBG(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
//根据id查询数据
/*Emp emp = mapper.selectByPrimaryKey(1);
System.out.println(emp);*/
//查询所有数据
/*List list = mapper.selectByExample(null);
list.forEach(System.out::println);*/
//根据条件查询数据
/*EmpExample example = new EmpExample();
example.createCriteria().andEmpNameEqualTo("张三").andAgeGreaterThanOrEqualTo(20);
example.or().andGenderEqualTo("男");
List list = mapper.selectByExample(example);
list.forEach(System.out::println);*/
Emp emp = new Emp(1, "小黑", null, "女");
//测试普通修改功能
//mapper.updateByPrimaryKey(emp);
//测试选择性修改
mapper.updateByPrimaryKeySelective(emp);
}
①添加依赖
com.github.pagehelper
pagehelper
5.2.0
②配置分页插件
在MyBatis的核心配置文件中配置插件
1、在查询功能之前使用 PageHelper.startPage(int pageNum, int pageSize) 开启分页功能
pageNum:当前页的页码
pageSize:每页显示的条数
2、在查询获取list集合之后,使用 PageInfo pageInfo = new PageInfo<>(List list, int navigatePages) 获取分页相关数据
list:分页之后的数据
navigatePages:导航分页的页码数
3、分页相关数据
public class PageTest {
/**
* PageInfo{
* pageNum=1, pageSize=4, size=4,
* startRow=1, endRow=4, total=30,
* pages=8,
* list=Page{count=true, pageNum=1, pageSize=4, startRow=0, endRow=4, total=30, pages=8, reasonable=false, pageSizeZero=false}[Emp{empId=1, empName='aaa', age=null, gender='null', deptId=null}, Emp{empId=2, empName='a', age=null, gender='null', deptId=null}, Emp{empId=3, empName='a', age=null, gender='null', deptId=null}, Emp{empId=4, empName='a', age=null, gender='null', deptId=null}],
* prePage=0, nextPage=2, isFirstPage=true,
* isLastPage=false, hasPreviousPage=false,
* hasNextPage=true, navigatePages=5,
* navigateFirstPage=1, navigateLastPage=5, navigatepageNums=[1, 2, 3, 4, 5]}
*/
@Test
public void testPage(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
//查询功能之前开启分页功能
Page
pageNum:当前页的页码
pageSize:每页显示的条数
size:当前页显示的真实条数
total:总记录数
pages:总页数
prePage:上一页的页码
nextPage:下一页的页码
isFirstPage/isLastPage:是否为第一页/最后一页
hasPreviousPage/hasNextPage:是否存在上一页/下一页
navigatePages:导航分页的页码数
navigatepageNums:导航分页的页码,[1,2,3,4,5]