目前项目中用到Spring的地方很多,很多功能都能在sping中找到解决方案,正如我现在想要说的缓存实现,Spring Cache已经为我们提供了很好的解决方案,并且提供了默认实现,增加几个注解立刻就能使用,确实挺好,但是在实际使用过程中还是觉得不太方便,主要就是因为要保持缓存注解方法间的名称保持一致,在@CacheEvict中需要指定所有需要清除的缓存信息(通过name,key等属性),方法比较多、比较分散的时候维护难度就会随之提高,稍有不慎就会导致数据的不一致;故此引出今天分享讨论的一种缓存实现:“通过Mybatis的拦截机制实现自动缓存”。
该实现的逻辑就是参考mybatis的二级缓存,针对使用sql语句查询的dao层,思路就是拦截所有的DAO层方法,解析方法对应的sql语句,对sql语句进行分类处理,分类很简单就两类,query类和update类,query主要是指select语句,update值得就是insert、delete喝update语句了;
对于query类,方法第一次执行的时候查询数据库,将查询结果缓存到cache中,之后在此调用该方法的时候直接从cache中查询;对于update类方法,就是解析sql中的表名,当方法执行成功后,根据表名将cache中所有涉及到该表的所有存储都清除,这样当有query类的方法sql中包含该表的缓存就不存在了,需要重新从数据库查询,然后再缓存,这样也就保证了数据的一致性。
逻辑很简单,下面就说一下实现:
(以下描述内容为最初的实现,代码实现以及配置做了较大改动,但核心原理未变,具体详见代码)
下面是通过xml方式配置sqlSessionFactory的xml片段,注释部分是常规的方式,我们不用,改为指向我们自定义的Factory类:MyBatisCacheSqlSessionFactory,指定工厂方法为:getSqlSessionFactory,这个方法需要两个参数,一个就是常规方法定义的DataSource,再有一个就是cacheService,也就是一个单独的缓存服务,我这里用的redis。
<!-- 工厂类 <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="configLocation" value="classpath:mybatis-config.xml"/> <property name="mapperLocations"> <array> <value>classpath*:mapper/*.xml</value> </array> </property> <property name="typeAliasesPackage" value="com.xbniao.uc.dao.po"/> <property name="plugins"> <array> <bean class="com.github.pagehelper.PageHelper"> <property name="properties"> <value> dialect=mysql reasonable=true </value> </property> </bean> </array> </property> </bean> --> <bean id="sqlSessionFactory"