Mybatis一级缓存和结合Spring Framework后失效的源码探究

下面是“Mybatis一级缓存和结合Spring Framework后失效的源码探究”的攻略:

Mybatis一级缓存

Mybatis自身提供了一级缓存的支持,即在同一次会话中多次查询同一条记录时,第一次查询时会将该数据缓存下来,后续再次查询时直接从缓存中取出,避免了重复的数据库查询操作,提升了性能。

对于一级缓存的使用,需要注意以下几点:

  1. 一级缓存的作用域是SqlSession,在同一个SqlSession中查询到的数据可以直接从缓存中获取。

  2. 默认情况下SqlSession开启一级缓存,即开启自动提交(autoCommit=false)情况下,每次执行查询语句后,查询结果都会被缓存起来。

  3. 如果缓存的数据被修改或删除,那么缓存数据会被清空。

Mybatis一级缓存与Spring Framework结合后失效的原因及解决方法

结合Spring Framework后,每个Mapper接口都会被Spring所代理,即每次调用Mapper接口时会生成一个新的代理类,因此Mapper接口的代理类是不同的,即使两个Mapper接口里的方法名和参数都一样。

这样导致了两个问题:

  1. 每个Mapper接口的代理类都有自己的SqlSession实例,不属于同一个SqlSession,因此会有多个缓存实例。

  2. 不同的Mapper接口的代理类中可能涉及同一个数据库表的数据,但这两个代理类实际上是不同的,因此可能出现一级缓存污染的现象。

解决以上问题,有3种方案:

  1. 方案一:使用Spring的事务管理机制,每次操作,保证只使用一个SqlSession。在Spring的配置文件中开启事务,使用@Transactional注解对需要使用SqlSession的方法进行标注。

  2. 方案二:使用Mybatis-Spring,Mybatis-Spring是Mybatis官方提供的与Spring集成的插件包,其中包含了SqlSessionTemplate,它提供统一的SqlSession操作入口,保证在同一事务中所有的操作只使用同一SqlSession实例。

  3. 方案三:关闭一级缓存。如果不想开启一级缓存,可以在配置文件中将localCacheScope设置为SESSION,即关闭一级缓存。

示例1

接下来的示例展示了如何基于Spring Framework和Mybatis-Spring来实现上述第二种方案中的解决方法。

  1. 首先,在applicationContext.xml中引入Mybatis-Spring。
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
    <constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
  1. 在Spring的配置文件中加入事务管理器的配置,使用tx:annotation-driven开启Spring事务注解支持。将SqlSessionFactory注入到事务管理器中。
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    ...
</bean>

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
    <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>

<tx:annotation-driven transaction-manager="transactionManager"/>
  1. 在Mapper接口中使用SqlSessionTemplate操作数据库。
@Repository
public class UserMapper {
    @Autowired
    private SqlSessionTemplate sqlSessionTemplate;

    public User findUserById(int id) {
        return sqlSessionTemplate.selectOne("com.example.UserMapper.findUserById", id);
    }
}
  1. 在Service实现类中使用@Transactional注解实现事务的控制。
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;

    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public User findUserById(int id) {
        return userMapper.findUserById(id);
    }
}

示例2

下面的示例演示了开启自动提交的情况下,Mybatis一级缓存如何生效。

  1. 在SqlSessionFactory中开启自动提交(autoCommit=true)功能,设置缓存类型(cacheEnabled=true)。
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="typeAliasesPackage" value="com.example.po"/>
    <property name="mapperLocations" value="classpath*:com/example/mapper/*.xml"/>
    <property name="configuration">
        <bean class="org.apache.ibatis.session.Configuration">
            <property name="cacheEnabled" value="true"/>
        </bean>
    </property>
    <property name="plugins">
        <array>
            <bean class="com.github.pagehelper.PageInterceptor">
                <property name="properties">
                    <value>
                        helperDialect=mysql
                    </value>
                </property>
            </bean>
        </array>
    </property>
    <property name="autoCommit" value="true"/>
</bean>
  1. 在Mapper接口中使用@Select注解进行查询操作。
public interface UserMapper {
    @Select("SELECT * FROM tb_user WHERE id = #{id}")
    User findUserById(int id);
}
  1. 在Service中进行测试。
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;

    @Override
    public User findUserById(int id) {
        User user = userMapper.findUserById(id);
        User user2 = userMapper.findUserById(id);
        return user;
    }
}

在这个示例中,第一次查询后,查询结果被缓存在了一级缓存中,第二次查询时直接从缓存中取出,而不是再次查询数据库。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Mybatis一级缓存和结合Spring Framework后失效的源码探究 - Python技术站

(0)
上一篇 2023年5月19日
下一篇 2023年5月19日

相关文章

  • Java log4j详细教程

    Java log4j详细教程 什么是log4j log4j是一种用于记录Java日志的流行框架,它允许开发人员在应用程序中添加灵活的、可配置的日志记录,并支持若干输出目标。 如何使用log4j 步骤一:将log4j库添加到项目中 在项目中添加log4j库有以下两种方法: 将log4j包含在项目的Classpath路径下 在Maven或Gradle等构建工具中…

    Java 2023年5月19日
    00
  • Java基于余弦方法实现的计算相似度算法示例

    Java基于余弦方法实现的计算相似度算法示例 在这个示例中,我们将介绍如何使用Java基于余弦方法实现计算相似度算法。这里我们主要使用了文本相似度算法,可以在多个领域中应用,例如自然语言处理、信息检索、推荐系统等。 什么是文本相似度算法? 文本相似度算法是指通过计算两个文本之间的相似度值来判断它们之间的相关性。在这个示例中,我们主要使用了余弦相似度算法来计算…

    Java 2023年5月19日
    00
  • Maven中pom.xml配置文件详细介绍

    Maven 是 Java 项目中管理项目构建、依赖管理、打包、发布等方面非常优秀的工具。pom.xml 是 Maven 建立项目的核心文件,它可以用来描述项目相关的各种元素。本攻略将详细讲解 pom.xml 配置文件的各个部分及其对 Maven 项目的影响,希望能为 Maven 初学者提供帮助。 1. 项目基本信息 首先,打开 pom.xml 文件,你会看到…

    Java 2023年5月20日
    00
  • Struts2 Result 返回JSON对象详解

    下面我为你详细讲解“Struts2 Result 返回JSON对象详解”的完整攻略。 什么是 JSON JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人类阅读和编写,也易于计算机解析和生成。 JSON 是一种基于文本的格式,可用于在不同程序之间传递数据。JSON 格式类似于 XML,但是相比之下更加简洁和易于…

    Java 2023年5月20日
    00
  • PHP与Java对比学习日期时间函数

    PHP与Java对比学习日期时间函数 介绍 在Web开发中,常常需要处理日期时间相关的操作,包括获取当前时间、格式化输出时间、计算时间差等。PHP和Java是两个常用的Web编程语言,都提供了日期时间相关的内置函数。本篇文章将介绍PHP和Java的日期时间函数,并对比讲解它们的异同点。 PHP日期时间函数 获取当前时间 PHP提供了几个函数可以获取当前时间:…

    Java 2023年5月20日
    00
  • 什么是类卸载?

    类卸载是Java虚拟机(JVM)中的一项重要功能,它可以卸载运行时的类。在Java应用程序中,当一个类没有被引用时,JVM会自动释放该类所占用的内存。这个过程称为“类卸载”。 类卸载的实现是通过垃圾收集器完成的。在JVM中,垃圾收集器会判断一个类是否完全没有被引用,如果没有引用,则该类不再被使用。当该类不再被使用时,JVM会卸载该类,释放其内存,并将该类从方…

    Java 2023年5月11日
    00
  • JSP中out对象的实例详解

    下面是本人为大家准备的详细讲解“JSP中out对象的实例详解”的攻略。 JSP中out对象的实例详解 1. out对象简介 在JSP页面中,out对象是一个内置对象,用于向客户端输出内容。 2. out对象的创建 当在JSP页面中使用语句 out.print(“hello, world”) 时,就会自动创建一个名为 “out” 的输出流对象。 3. out对…

    Java 2023年6月15日
    00
  • Java方法引用原理实例解析

    Java方法引用原理实例解析 Java 8 中引入了方法引用(Method reference)的概念,可以使用方法引用来简化 lambda 表达式的书写。方法引用是指在 lambda 表达式中直接调用一个已经存在的函数或者对象方法,从而可以简化代码,提升程序的可读性和可维护性。 方法引用的语法 方法引用的语法如下: 对象名::方法名 类名::静态方法名 类…

    Java 2023年5月26日
    00
合作推广
合作推广
分享本页
返回顶部