Spring框架整合MyBatis框架

事务隔离级别,并发事务会导致发生以下三种类型的问题

事务隔离级别是数据库并发控制中的一个重要概念,它定义了事务在并发执行时相互之间的隔离程度。脏读、不可重复读和幻读是数据库并发控制中常见的三种问题,它们分别代表了不同的事务隔离级别下可能出现的数据不一致性现象。
一、脏读(Dirty Read)
定义:脏读是指一个事务读取了另一个未提交事务的数据。在这种情况下,由于未提交事务的数据可能会因为各种原因(如回滚)而被撤销,因此读取到的数据可能是不正确的。
示例:假设有两个事务A和B,事务A正在修改某个数据项但尚未提交,此时事务B读取了这个数据项。如果事务A因为某些原因回滚了,那么事务B读取到的数据就是“脏”的,因为它读取了一个从未真正提交的数据。
影响:脏读会破坏数据的完整性,因为它允许事务读取到未提交的数据,这些数据可能在后续被撤销。
二、不可重复读(Non-repeatable Read)
定义:不可重复读是指在一个事务内多次读取同一数据时,结果可能不一致。这通常是因为在事务执行期间,另一个事务对数据进行了修改并提交。
示例:事务A两次读取同一个数据项,但在两次读取之间,事务B修改了该数据项并提交。因此,事务A在第二次读取时得到了与第一次不同的数据。
影响:不可重复读会破坏事务的一致性,因为它允许在同一个事务中多次读取到的数据不一致。
三、幻读(Phantom Read)
定义:幻读是指当事务不是独立执行时发生的一种现象,即一个事务在读取某个范围内的记录后,另一个事务在该范围内插入了新的记录,当第一个事务再次读取该范围时,会“看到”这个新插入的记录,就像发生了幻觉一样。
示例:事务A查询了某个范围内的记录,然后事务B在该范围内插入了新的记录并提交。之后,事务A再次查询同一范围时,会发现多了一些之前没有的记录。
影响:幻读会破坏事务的隔离性,因为它允许一个事务看到其他事务在并发执行时所做的修改(包括插入新记录)。

7.1基本整合方式

Spring框架整合其他框架的本质其实就是把其他框架交给Spring框架管理。Spring框架通过IOC、AOP等机制实现与其他框架的连接,最终建立一个低耦合的应用架构,这大大增加了系统的灵活性,便于功能扩展。

7.1.1 整合思路梳理

MyBatis框架主要是通过SqlSession实例实现对数据的操作,而SQLSession 实例是通过SQLSessionFactory实例又是由SQLSessionFactoryBuilder依据MyBatis配置文件中的数据源,SQL映射文件等信息构建的,这些对象之间的关系如图所示

SqlSessionFactoryBuilder  
    |  
    v  
SqlSessionFactory  
    |  
    +------> SqlSession  
    |        |  
    |        +--> Mapper Interface (动态代理实现)  
    |  
    +------> Close (SqlSessionFactory 关闭资源)
  • SqlSessionFactoryBuilder 读取配置文件并构建 SqlSessionFactory
  • SqlSessionFactory 负责创建 SqlSession 实例。
  • SqlSession 用于执行SQL命令,并可以通过 getMapper 方法获取Mapper接口的动态代理实现,进而执行具体的数据库操作。
  • 所有的对象(除了 SqlSessionFactoryBuilder)在使用完毕后都应当关闭或释放资源,但 SqlSessionFactoryBuilder 通常在构建完 SqlSessionFactory 后就不需要了,因此不需要关闭。

7.1.2 整合所需的依赖及配置

以用户模块为例,在com.bdqn.pojo包下创建用户实体类sysUser。关键代码如下所示。

package com.bdqn.CH05.pojo;


public class SysUser {

  private int id;
  private String account;
  private String realName;
  private String password;
  private int sex;
  private String birthday;
  private String phone;
  private String address;
  private int roleId;
  private String idPicPath;
  private String workPicPath;
  private int createdUserId;
  private String createdTime;
  private int updatedUserId;
  private String updatedTime;

  private int age;
  private String roleIdName;

  // 省略getter、setter方法
  
}

在com.bdqn.dao.sysUser包下创建用户映射器SysUserMapper接口及SysUserMapper.xml映射文件。映射文件关键代码如下

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bdqn.CH05.mapper.SysUserMapper">
    <resultMap type="com.bdqn.CH05.pojo.SysUser" id="SysUserResult">
        <result property="roleIdName" column="roleName"/>
    </resultMap>
    <insert id="add">
        insert into t_sys_user (account, realName, password, sex, birthday, phone, address, roleId, idPicPath,
                                workPicPath, createdUserId, createdTime, updatedUserId, updatedTime)
        values (#{account}, #{realName}, #{password}, #{sex}, #{birthday}, #{phone}, #{address}, #{roleId},
                #{idPicPath}, #{workPicPath}, #{createdUserId}, #{createdTime}, #{updatedUserId}, #{updatedTime})
    </insert>
    <select id="selectSysUserList" resultType="com.bdqn.CH05.pojo.SysUser" resultMap="SysUserResult">
        select u.*, r.roleName
        from t_sys_user u,
             t_sys_role r
        where u.roleId = r.id
          and u.roleId = #{roleId}
          and u.realName like CONCAT('%', #{realName}, '%')
    </select>
</mapper>

Spring框架整合MyBatis框架之后,相关的数据源配置就可以从Mybatis配置文件移动到Spring配置文件中。如此,Mybatis配置文件将变得非常简单,如下所示。

<?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>
    <typeAliases>
        <package name="com.bdqn.CH05.pojo"/>
    </typeAliases>
</configuration>

7.1.3使用Spring配置文件配置数据源

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://127.0.0.1.3306/cvs_db?useUnicode=true&amp;characterEncoding=utf8&amp;serviceTimezone=Asia/Shanghai"/>
        <property name="username" value="root"/>
        <property name="password" value="liuyuhan"/>
    </bean>

7.1.4 通过Spring配置文件创建SqlSessionFactory

在Spring配置文件中创建SqlSessionFactory通常是通过SqlSessionFactoryBean来完成的。SqlSessionFactoryBean是一个Spring工厂bean,它负责创建SqlSessionFactory实例。以下是一个基本的示例,展示了如何在Spring的XML配置文件中配置SqlSessionFactoryBean来创建SqlSessionFactory

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations">
            <list>
                <value>classpath:com/bdqn/CH05/dao/*/*</value>
            </list>
        </property>
    </bean>

7.2 映射器整合方式

在Spring与MyBatis的整合中,映射器(Mapper)的整合方式主要有以下几种,每种方式都有其特点和适用场景:

1. 使用MapperFactoryBean

MapperFactoryBean是MyBatis-Spring提供的一个类,用于创建Mapper接口的代理对象。这种方式不需要编写MyBatis的映射文件(XML文件),而是通过注解(如@Select@Insert等)在Mapper接口中直接定义SQL语句。

配置示例

<!-- Spring配置文件中的MapperFactoryBean配置 -->  
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">  
    <property name="mapperInterface" value="com.example.mapper.UserMapper"/>  
    <property name="sqlSessionFactory" ref="sqlSessionFactory"/>  
</bean>

在上面的配置中,mapperInterface属性指定了Mapper接口的全路径名,sqlSessionFactory属性引用了之前配置的SqlSessionFactory bean。

2. 使用MapperScannerConfigurer

MapperScannerConfigurer是Spring提供的一个Bean,用于自动扫描指定包下的Mapper接口,并将它们动态地注册为Spring容器中的Bean。这种方式需要Mapper接口和对应的MyBatis映射文件(XML文件)存在,但不需要在Spring配置文件中显式地声明每一个Mapper Bean。

配置示例:

<!-- Spring配置文件中的MapperScannerConfigurer配置 -->  
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">  
    <property name="basePackage" value="com.example.mapper"/>  
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>  
</bean>

3. 使用SqlSessionTemplate

SqlSessionTemplate是MyBatis-Spring提供的一个类,它实现了MyBatis的SqlSession接口,并且可以在Spring事务管理下工作。虽然SqlSessionTemplate本身不是直接用于Mapper的整合,但它可以与Mapper接口结合使用,通过getMapper方法获取Mapper接口的代理对象。

使用方式

通常,在使用SqlSessionTemplate时,会先配置一个SqlSessionTemplate bean,然后在需要的地方注入这个bean,并通过它来获取Mapper接口的代理对象。但是,更常见的做法是直接使用MapperScannerConfigurer或MapperFactoryBean来自动管理Mapper接口的代理对象,因为这样做可以更加简洁和方便。

7.3声明式事务

声明式事务(Declarative Transaction Management)是一种通过声明(而非编程)方式管理事务的方法。在Spring框架中,声明式事务管理是一种非常流行且强大的特性,它允许开发者通过简单的声明性注解或XML配置来管理事务,而无需在代码中显式地编写事务管理代码。这种方式不仅简化了事务管理的复杂性,还提高了代码的可读性和可维护性。

声明式事务的核心概念

  1. 事务管理器(TransactionManager):负责定义事务的边界,并管理事务的生命周期(如开始、提交、回滚等)。Spring提供了多种事务管理器实现,用于支持不同的数据源和事务管理API(如JDBC、JPA、Hibernate等)。

  2. 事务属性(Transaction Attributes):定义了事务的各个方面,如传播行为(Propagation)、隔离级别(Isolation)、超时时间(Timeout)、只读标志(ReadOnly)以及回滚规则(Rollback Rules)等。

  3. 声明方式

    • 基于注解的声明式事务:通过@Transactional注解在方法或类级别上声明事务。这是Spring 2.0及以后版本中引入的,并且是最常用的声明事务方式。
    • 基于XML的声明式事务:通过在Spring配置文件中使用<tx:advice><tx:attributes>等标签来声明事务。这种方式在Spring的早期版本中较为常见,但在现代Spring应用中,基于注解的方式更为流行。

@Transactional注解的使用

@Transactional注解可以应用于接口定义、接口方法、类定义或类的公共方法上。当事务方法被调用时,Spring容器会自动创建一个代理对象来包装目标对象,并在调用事务方法时启动一个事务。如果在事务方法执行过程中抛出了异常,并且该异常符合指定的回滚规则(默认情况下,RuntimeException和Error及其子类会导致事务回滚),则Spring会回滚事务。

@Service  
public class UserService {  
  
    @Autowired  
    private UserRepository userRepository;  
  
    @Transactional  
    public void addUser(User user) {  
        userRepository.save(user);  
        // 假设这里发生了异常,由于@Transactional的存在,该操作会被回滚  
        throw new RuntimeException("Something went wrong!");  
    }  
}

在上面的示例中,addUser方法被@Transactional注解标记,表示该方法执行时将被事务管理。如果在方法执行过程中抛出了RuntimeException(或其子类)异常,则Spring会回滚该事务,以确保数据的一致性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值