mybatis基于xml方式整合二级缓存
首先,注意到,我们这里说的是基于xml的方式完成mybatis的二级缓存
1. mybatis全局开启二级缓存
在mybatis-configration当中开启二级缓存
<!--开启二级缓存 -->
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
2. 在需要开启二级缓存的mapper文件当中指定cache标签
<!-- 开启二级缓存 --> <cache></cache>
其实这里可以配置<cache type="org.apache.ibatis.cache.impl.PerpetualCache"/>,PerpetualCache这个类是mybatis默认实现缓存功能的类。我们不写type就使用mybatis默认的缓存,也可以去实现 Cache 接口来自定义缓存。所以通过这句话,我们就知道跟ehcache的结合点就在这里。
3. 二级缓存内部实现:

我们可以看到,二级缓存内部实际上也是一个hashMap
4. 额外的我们可能需要对实体类添加序列化接口

开启了二级缓存后,还需要将要缓存的pojo实现Serializable接口,为了将缓存数据取出执行反序列化操作,因为二级缓存数据存储介质多种多样,不一定只存在内存中,有可能存在硬盘中,如果我们要再取这个缓存的话,就需要反序列化了。所以mybatis中的pojo都去实现Serializable接口。
5. 代码实例 :
5.1 创建一个自己的包

5.2 configuration.xml 配置如下 :
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 注意dtd 是引用mybatis的,而不是sprinh的 --> <!-- 指定properties配置文件, 我这里面配置的是数据库相关 ,注意 文件夹路径,我这里存放的是同级的这里 --> <properties resource="resource.properties"></properties> <!-- 指定Mybatis使用log4j --> <settings> <setting name="logImpl" value="LOG4J" /> <!-- <setting name="cacheEnabled" value="true" /> --> </settings> <environments default="development"> <!-- 可以配置多个environment 来达到多数据源的配置,或者说能达到 生产、测试、开发环境的切换 --> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <!-- 上面指定了数据库配置文件, 配置文件里面也是对应的这四个属性 一定要跟resource.properties当中的属性对应上 --> <property name="driver" value="${jdbc.driverClass}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.userName}" /> <property name="password" value="${jdbc.password}" /> </dataSource> </environment> </environments> <!-- 映射文件,mybatis精髓, 后面才会细讲 ,扫描mybatis的mapper映射文件,一定要放在resource文件夹下 --> <!-- mapper resource= 的值 必须是resource文件夹下的路径值 --> <mappers> <mapper resource="UserMapper.xml"/> </mappers> </configuration>
<setting name="cacheEnabled" value="true" /> 注意到这句话在springboot应用当中可不加,springboot默认帮我们开启了,但是为了明确功能,我们还是加上吧,即便
是要去掉二级缓存,那我们就写false,上面我注释了,希望大家看得到。
5.3 resource.properties 配置数据库信息
# 数据库配置文件 jdbc.driverClass=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/form?serverTimezone=UTC&useSSL=true&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&rewriteBatchedStatements=true jdbc.userName=root jdbc.password=root # 我这里连接的是form本地库
5.4 UserMapper 接口的编写
import org.apache.ibatis.annotations.Mapper; import java.util.List; import java.util.Map; /** * @Auther: lxf * @Date: 2018/11/7 10:19 * @Description: */ @Mapper public interface UserMapper { Map<String,Object> findUserById(int id); List<Map<String,Object>> callProcTest(int dict_id); Map<String,Object> findUserByIdForCache(int id); }
5.5 main测试方法的编写
public class TestMybatis { public static void main(String[] args) throws IOException { // testEhcache(); testUserMapper(); // executeTest(); // showEhcache(); } public static void testUserMapper() throws IOException { SqlSessionFactory sessionFactory = null; String resource = "configuration.xml"; sessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader(resource)); //从类路径中加载资源 SqlSession sqlSessionOne = sessionFactory.openSession(); SqlSession sqlSessionTwo = sessionFactory.openSession(); SqlSession sqlSessionThree = sessionFactory.openSession(); UserMapper userMapperOne = sqlSessionOne.getMapper(UserMapper.class); UserMapper userMapperTwo = sqlSessionTwo.getMapper(UserMapper.class); UserMapper userMapperThree = sqlSessionThree.getMapper(UserMapper.class); int id = 502; Map<String,Object> mapOne = userMapperOne.findUserByIdForCache(id); printMap(mapOne); mapOne = userMapperOne.findUserByIdForCache(id); printMap(mapOne); sqlSessionOne.commit(); Map<String,Object> mapTwo = userMapperTwo.findUserByIdForCache(id); printMap(mapTwo); Map<String,Object> mapThree = userMapperThree.findUserByIdForCache(id); printMap(mapThree); } public static void printMap(Map<String,Object> map){ for(String str : map.keySet()){ System.out.println(str+"-->"+map.get(str)); } } }
5.6 UserMapper.xml的配置
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="UserMapper">
<!-- 二级缓存+ ehcache 下面两个选一个就好,一个有日志,一个没有 -->
<!-- type="org.mybatis.caches.ehcache.EhcacheCache" -->
<!-- <cache type="org.mybatis.caches.ehcache.LoggingEhcache" /> -->
<!-- 开启二级缓存 -->
<cache></cache>
<select id="findUserById" parameterType="int" resultType="Map">
select user_id,user_name,CREATION_DATE from fnd_user where _id=#{id,jdbcType=INTEGER}
</select>
<!-- 测试能否执行存储过程 -->
<select id="callProcTest" parameterType="int" resultType="Map" statementType="CALLABLE">
{ call myfuncdictproc2(#{p_dict_id,mode=IN,jdbcType=INTEGER}) }
</select>
<!-- useCache="false" 是用来禁止二级缓存的 -->
<select id="findUserByIdForCache" parameterType="int" resultType="Map" useCache="true">
select user_id,user_name,CREATION_DATE from fnd_user where _id=#{id,jdbcType=INTEGER}
</select>
</mapper>
5.6 控制台查看最终显示结果

可以看到二级缓存已经生效了。这里为什么是这样子的?可以看到我的代码当中第一次跟第二次是使用同一个sqlSession,然后才commit掉的,所以后面的2个都是二级缓存查询出来的,
所以第三次查询打印是在二级缓存上命中了1次,是三分之一,第四次命中了2此,是二分之一;而第二次是1级缓存生效。
6. 额外注意事项
6.1 useCache和flushCache
mybatis中还可以配置userCache和flushCache等配置项,userCache是用来设置是否禁用二级缓存的,在statement中设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,默认情况是true,即该sql使用二级缓存。
<select id="selectUserByUserId" useCache="false" resultType="com.ys.twocache.User" parameterType="int"> select * from user where id=#{id} </select>
这种情况是针对每次查询都需要最新的数据sql,要设置成useCache=false,禁用二级缓存,直接从数据库中获取。
在mapper的同一个namespace中,如果有其它insert、update、delete操作数据后需要刷新缓存,如果不执行刷新缓存会出现脏读。
设置statement配置中的flushCache=”true” 属性,默认情况下为true,即刷新缓存,如果改成false则不会刷新。使用缓存时如果手动修改数据库表中的查询数据会出现脏读。
<select id="selectUserByUserId" flushCache="true" useCache="false" resultType="com.ys.twocache.User" parameterType="int"> select * from user where id=#{id} </select> <!-- 不建议使用 flushCache="false" -->
6.2 注意到多个sqlSession来做测试的时候,一定要知道 是上一个sqlSession commit之后,才丢到缓存了,所以看我上面的main测试类,其他的sqlSession缓存名字是因为第一个sqlSession的查询
已经commit了,我们要知道使用的时机。

浙公网安备 33010602011771号