mybatis的复习01
1、MyBatis是手动提交事务
测试1:
@Test
public void testInsert() throws Exception {
// 1.创建SqlSession对象
SqlSession session = MyBatisUtil.openSession();
// 2.创建UserMapper接口的代理对象
UserMapper userMapper = session.getMapper(UserMapper.class);
// 3. 执行UserMapper的insert方法
User user = new User(null, "张无忌1111", "123", 25);
System.err.println("执行之前 :" + user);
userMapper.insert(user);
System.out.println("执行之后 :" + user);
// 4.提交事务(MyBatis是手动提交事务)
session.commit();
// 5.关闭Session
session.close();
}
结果:
数据库有记录
测试2:
将 session.commit();去掉后,数据库没有记录了。
--------------------------------------------------------------------------------
2、mybatis缓存
1、mybatis自带的二级缓存:
<cache type="org.apache.ibatis.cache.impl.PerpetualCache"/>,PerpetualCache这个类是mybatis默认实现缓存功能的类。我们不写type就使用mybatis默认的缓存
参阅:(建议去看这个blog,比下面的好看)
https://www.cnblogs.com/ysocean/p/7342498.html
2、二级缓存的原理及配置
二级缓存的原理和一级缓存原理一样,第一次查询,会将数据放入缓存中,然后第二次查询则会直接去缓存中取。但是一级缓存是基于 sqlSession 的,而 二级缓存是基于 mapper文件的namespace的,也就是说多个sqlSession可以共享一个mapper中的二级缓存区域,并且如果两个mapper的namespace相同,即使是两个mapper,那么这两个mapper中执行sql查询到的数据也将存在相同的二级缓存区域中。
那么二级缓存是如何使用的呢?
①、开启二级缓存
和一级缓存默认开启不一样,二级缓存需要我们手动开启
首先在全局配置文件 mybatis-configuration.xml 文件中加入如下代码:
1234 <!--开启二级缓存 --><settings> <setting name="cacheEnabled" value="true"/></settings>
其次在 UserMapper.xml 文件中开启缓存
12 <!-- 开启二级缓存 --><cache></cache>
我们可以看到 mapper.xml 文件中就这么一个空标签<cache/>,其实这里可以配置<cache type="org.apache.ibatis.cache.impl.PerpetualCache"/>,PerpetualCache这个类是mybatis默认实现缓存功能的类。我们不写type就使用mybatis默认的缓存,也可以去实现 Cache 接口来自定义缓存。
我们可以看到 二级缓存 底层还是 HashMap 架构。
②、po 类实现 Serializable 序列化接口
开启了二级缓存后,还需要将要缓存的pojo实现Serializable接口,为了将缓存数据取出执行反序列化操作,因为二级缓存数据存储介质多种多样,不一定只存在内存中,有可能存在硬盘中,如果我们要再取这个缓存的话,就需要反序列化了。所以mybatis中的pojo都去实现Serializable接口。
③、测试
一、测试二级缓存和sqlSession 无关
12345678910111213141516171819 @Testpublic void testTwoCache(){ //根据 sqlSessionFactory 产生 session SqlSession sqlSession1 = sessionFactory.openSession(); SqlSession sqlSession2 = sessionFactory.openSession(); String statement = "com.ys.twocache.UserMapper.selectUserByUserId"; UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class); UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class); //第一次查询,发出sql语句,并将查询的结果放入缓存中 User u1 = userMapper1.selectUserByUserId(1); System.out.println(u1); sqlSession1.close();//第一次查询完后关闭sqlSession //第二次查询,即使sqlSession1已经关闭了,这次查询依然不发出sql语句 User u2 = userMapper2.selectUserByUserId(1); System.out.println(u2); sqlSession2.close();}
可以看出上面两个不同的sqlSession,第一个关闭了,第二次查询依然不发出sql查询语句。
二、测试执行 commit() 操作,二级缓存数据清空
1234567891011121314151617181920212223242526 @Testpublic void testTwoCache(){ //根据 sqlSessionFactory 产生 session SqlSession sqlSession1 = sessionFactory.openSession(); SqlSession sqlSession2 = sessionFactory.openSession(); SqlSession sqlSession3 = sessionFactory.openSession(); String statement = "com.ys.twocache.UserMapper.selectUserByUserId"; UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class); UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class); UserMapper userMapper3 = sqlSession2.getMapper(UserMapper.class); //第一次查询,发出sql语句,并将查询的结果放入缓存中 User u1 = userMapper1.selectUserByUserId(1); System.out.println(u1); sqlSession1.close();//第一次查询完后关闭sqlSession //执行更新操作,commit() u1.setUsername("aaa"); userMapper3.updateUserByUserId(u1); sqlSession3.commit(); //第二次查询,由于上次更新操作,缓存数据已经清空(防止数据脏读),这里必须再次发出sql语句 User u2 = userMapper2.selectUserByUserId(1); System.out.println(u2); sqlSession2.close();}
查看控制台情况:
3、二级缓存整合ehcache
mybatis自带的二级缓存,但是这个缓存是单服务器工作,无法实现分布式缓存。那么什么是分布式缓存呢?假设现在有两个服务器1和2,用户访问的时候访问了1服务器,查询后的缓存就会放在1服务器上,假设现在有个用户访问的是2服务器,那么他在2服务器上就无法获取刚刚那个缓存,如下图所示:
为了解决这个问题,就得找一个分布式的缓存,专门用来存储缓存数据的,这样不同的服务器要缓存数据都往它那里存,取缓存数据也从它那里取,如下图所示:
上文一开始提到过,mybatis提供了一个cache接口,如果要实现自己的缓存逻辑,实现cache接口开发即可。mybatis本身默认实现了一个,但是这个缓存的实现无法实现分布式缓存,所以我们要自己来实现。ehcache分布式缓存就可以,mybatis提供了一个针对cache接口的ehcache实现类,这个类在mybatis和ehcache的整合包中。
①、导入 mybatis-ehcache 整合包(最上面的源代码中包含有)
②、在全局配置文件 mybatis-configuration.xml 开启缓存
1234 <!--开启二级缓存 --><settings> <setting name="cacheEnabled" value="true"/></settings>
③、在 xxxMapper.xml 文件中整合 ehcache 缓存
将如下的类的全类名写入<cache type="" ></cache>的type属性中
12345 <!-- 开启本mapper的namespace下的二级缓存 type:指定cache接口的实现类的类型,不写type属性,mybatis默认使用PerpetualCache 要和ehcache整合,需要配置type为ehcache实现cache接口的类型--><cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
④、配置缓存参数
在 classpath 目录下新建一个 ehcache.xml 文件,并增加如下配置:
123456789101112131415161718 <?xml version="1.0" encoding="UTF-8"?><ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd"> <diskStore path="F:\develop\ehcache"/> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" maxElementsOnDisk="10000000" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> <persistence strategy="localTempSwap"/> </defaultCache> </ehcache>
diskStore:指定数据在磁盘中的存储位置。
defaultCache:当借助CacheManager.add("demoCache")创建Cache时,EhCache便会采用<defalutCache/>指定的的管理策略
以下属性是必须的:
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(先进先出)