Spring基础学习之Spring事务的实现方式

前言

小伙伴们,大家好,我是狂奔の蜗牛rz,当然你们可以叫我蜗牛君,我是一个学习Java半年多时间的小菜鸟,同时还有一个伟大的梦想,那就是有朝一日,成为一个优秀的Java架构师。

这个Spring基础学习系列是用来记录我学习Spring框架基础知识的全过程 (这个系列是参照B站狂神的Spring5最新教程来写的,由于是之前整理的,但当时没有发布出来,所以有些地方可能有错误,希望大家能够及时指正!)

之后我将会以一天一更的速度更新这个系列,还没有学习Spring5框架的小伙伴可以参照我的博客学习一下;当然学习过的小伙伴,也可以顺便跟我一起复习一下基础。
最后,希望能够和大家一同进步吧!加油吧!少年们!

废话不多说,让我们开始今天的学习内容吧,今天我们来到了Spring基础学习的第十四站:Spring事务的实现方式

14.1 Spring事务的实现方式

14.1.1 Spring事务的实现方式是什么?

事务这个概念是数据库层面的,Spring只是基于数据库中的事务进行了扩展,以及提供了一些让程序员能够更加方便操作的方式

Spring的事务管理分为两种方式,分别为编程式事务管理声明式事务管理

  • 编程式事务管理:即使用事务管理模板 (TransactionTemplate) 手动地管理事务,在实际开发中一般不使用,这里作为了解即可
  • 声明式事务管理:是Spring默认的事务管理方式,需要在配置文件中定义数据源 (DriverManagerDataSource) 和事务管理器 (DataSourceTransactionManager),然后把事务管理器注入到事务代理工厂Bean (TransactionProxyFactoryBean) 生成代理,或者使用Spring AOP XML 方式 (<基于 tx / AOP 配置的声明式事务管理方式) 进行配置,也可以使用Spring AOP Annotation 方式 (即使用@Transactional注解实现声明式事务管理)
14.1.2 使用TransactionProxyFactoryBean方式
1.编写MySQL数据库脚本和引入相关资源依赖
1-1 编写MySQL数据库脚本
-- 创建数据库MyBatis,``用来防止与MySQL关键字发生冲突
Create Database `MyBatis`;

-- 使用MyBatis数据库
Use `MyBatis`;

-- 创建数据库表User
Create table `User`(
	`id` int(10) not null primary key,
    `name` varchar(30) default null,
    `pwd` varchar(30) default null
)engine=InnoDB default charset=utf8;

-- 批量插入一些用户信息
Insert into `User`(`id`,`name`,`pwd`) values
(1,'周杰伦','zjl123456'),
(2,'方文山','fws123456'),
(3,'黄俊郎','hjl123456')
1-2 引入项目相关资源依赖
  • 前提需要创建一个Maven项目,然后在pom.xml文件中导入相应的资源依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>spring-study</artifactId>
        <groupId>com.kuang</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>spring-10-mybatis</artifactId>

    <!-- 导入资源依赖 -->
    <dependencies>
        <!-- mysql驱动资源依赖 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <!-- mybatis资源依赖 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.2</version>
        </dependency>
        <!-- spring资源依赖 -->
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.0.RELEASE</version>
        </dependency>
        <!-- spring要操作数据库,还需腰一个spring-jdbc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.0.RELEASE</version>
        </dependency>
        <!-- junit单元测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <!-- log4j资源依赖 -->
        <!-- https://mvnrepository.com/artifact/log4j/log4j -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <!-- aop织入资源依赖 -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.13</version>
        </dependency>
        <!-- mybatis-spring资源依赖 -->
        <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.3</version>
        </dependency>
        <!-- lombok资源依赖 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.10</version>
        </dependency>
    </dependencies>
    
    <!-- 在build中配置resources,来防止我们资源导出失败的问题 -->
    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
        </resources>
    </build>
    
</project>
2.编写数据库配置文件和Mybatis核心配置文件
2-1 编写db.properties数据库配置文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssmbuild?useSSL=true&useUnicode=true&characterEncoding=UTF-8
jdbc.username=root
jdbc.password=123456
2-2 编写mybatis-config.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:核心配置文件 -->
<configuration>

    <!-- 设置标准日志输出 -->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

    <!-- 使用别名:通过包起别名 -->
    <typeAliases>
        <package name="com.kuang.pojo"/>
    </typeAliases>

</configuration>
3.编写User实体类和UserMapper接口
3-1 编写User实体类
package com.kuang.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data // 引入无参构造,get和set方法以及toString方法
@AllArgsConstructor // 引入有参构造
@NoArgsConstructor // 再次引入无参构造,防止引入有参构造时覆盖无参构造
public class User {
    
    private int id; // 用户编号
    private String name; // 用户名
    private String pwd; // 密码
    
}
3-2 编写UserMapper接口
package com.kuang.mapper;

import com.kuang.pojo.User;
import java.util.List;

public interface UserMapper {
    
    // 获取所有用户信息
    public List<User> getUsers();
    
    // 增加用户信息
    public int insertUser(User user);
    
    // 删除用户信息
    public int deleteUser(int id);
    
    // 修改用户信息
    public int UpdateUser(User user);
    
}
4.编写UserMapper.xml映射文件和UserMapperImpl实现类
4-1 编写UserMapper.xml映射文件
  • resources资源路径下创建与UserMapper相同包路径,存放UserMapper.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">
<!--namespace=绑定一个对应的Dao/Mapper接口-->
<mapper namespace="com.kuang.mapper.UserMapper">

    <!-- 查询所有用户信息 -->
    <!-- 当通过包起别名后,resultType(结果类型)直接使用对应实体类名即可,不需要写全类名 -->
    <select id="getUsers" resultType="user">
        Select * from mybatis.user
    </select>

    <!-- 增加用户信息 -->
    <insert id="insertUser" parameterType="com.kuang.pojo.User">
        Insert into mybatis.user(id, name, pwd)
        values(#{id} ,#{name}, #{pwd})
    </insert>

    <!-- 删除用户信息 -->
    <delete id="deleteUser" parameterType="int">
        Delete  from mybatis.user where id = #{id}
    </delete>

    <!-- 修改用户信息 -->
    <update id="UpdateUser" parameterType="com.kuang.pojo.User">
        Update mybatis.user
        set name = #{name}, pwd = #{pwd}
        where id = #{id}
    </update>

</mapper>
4-2 编写UserMapperImpl实现类
package com.kuang.mapper;

import com.kuang.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;
import java.util.List;

public class UserMapperImpl implements UserMapper {
    
    // 引入SqlSessionTemplate对象
    private SqlSessionTemplate sqlSessionTemplate; 

    // 使用set方法动态注入SqlSessionTemplate对象
    public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
        this.sqlSessionTemplate = sqlSessionTemplate;
    }

    // 重写getUsers方法
    public List<User> getUsers() {
        // 获取UserMapper对象
        UserMapper userMapper = sqlSessionTemplate.getMapper(UserMapper.class);
        // 返回UserMapper对象的getUsers方法
        return userMapper.getUsers();
    }
    
}

为了节省篇幅,这里就不编写UserService类UserServiceImpl实现类

5.编写spring-dao.xml和ApplicationContext.xml配置文件
5-1 编写spring-dao.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">
    
    <!-- 1.关联数据库配置文件 -->
    <context:property-placeholder location="classpath:db.properties"/>
    
    <!-- 2.配置DataSource数据源:读取数据库配置文件,这里使用的Spring默认的数据源JDBC -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    
    <!-- 3.配置sqlSessionFactory工厂对象 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 2.1 引用dataSource数据源 -->
        <property name="dataSource" ref="dataSource"/>
        <!-- 2.2 绑定Mybatis的核心配置文件 -->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <!-- 2.3 在核心配置文件中注册Mapper.xml文件 -->
        <property name="mapperLocations" value="classpath*:com/kuang/mapper/*.xml"/>
    </bean>
    
    <!-- 4.配置SqlSessionTemplate模板对象 -->
    <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
        <!-- 只能使用构造器注入sqlSessionFactory:因为它没有set方法 -->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>
    
    <!-- 5.配置transactionManager事务管理器:依赖于dataSource数据源 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    
    <!-- 6.生成代理类(userDaoProxy):让代理管理事务,依赖于事务管理类 -->
    <bean id="userDaoProxy"  class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <!-- #6.1 提供事务管理器(transactionManager) -->
        <property name="transactionManager" ref="transactionManager"/>
        <!-- #6.2 配置目标类userMapper -->
        <property name="target" ref="userMapper"/>
        <!-- #6.3 提供UserMapper接口-->
        <property name="proxyInterfaces" value="com.kuang.mapper.UserMapper"/>
        <!-- #6.4 事务的详情配置,给事务定义对象(TransactionDefinition)进行赋值 -->
        <property name="transactionAttributes">
            <props>
                <!-- 配置增强目标类的所有的方法(*表示所有),并且设置传播行为和隔离级别 -->
                <prop key="*">PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ</prop>
            </props>
        </property>
    </bean>
    
</beans>

通过设置prop标签中的key属性,用来配置对目标类内的哪些方法进行增强

key表示方法名称,如果使用 “*”,表示所有的方法;如果使用get *,表示以get开头的方法
prop标签中的text文本按照固定的格式,编写事务详情及TransactionDefinition的内容

  • 传播行为(propagation_required) 表示支持当前事务,如果没有将创建新事务
  • 隔离级别(isolation_repeatable_read) 表示可重复读级别等,值之间使用逗号进行分隔
5-2 编写ApplicationContext.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <!-- 在主配置文件中导入spring-dao.xml配置文件 -->
    <import resource="spring-dao.xml"/>
    
    <!-- 注入userMapperImpl实现类 -->
    <bean id="userMapper" class="com.kuang.mapper.UserMapperImpl">
        <property name="sqlSessionTemplate" ref="sqlSessionTemplate"/>
    </bean>
    
</beans>
6.测试结果和优缺点总结
6-1 测试结果
  • 编写MyTest测试类
package com.kuang.mapper;

import com.kuang.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;

public class MyTest {
    
    @Test
    public void getUsers() {
        // 读取上下文信息,获取Spring的IOC容器
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 通过Spring的IOC容器获取userDaoProxy代理对象的Bean信息
        UserMapper userMapper = (UserMapper) context.getBean("userDaoProxy");
        // 调用userMapper的getUsers方法。获取所有用户信息,然后进行遍历
        for (User user : userMapper.getUsers()) {
            // 打印用户信息
            System.out.println(user);
        }
    }
    
}
  • 测试结果

在这里插入图片描述

6-2 优缺点总结

优势在代码中无须关注业务逻辑,而是交给Spring容器进行事务控制

缺点配置文件过于臃肿,难以阅读

14.1.3 使用Spring AOP XML 方式

只需修改spring-dao.xml配置文件内容,其他与12.2.2中使用TransactionProxyFactoryBean方式一致

1.修改spring-dao.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context 
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd">
    
       <!-- 1.关联数据库配置文件 -->
       <context:property-placeholder location="classpath:db.properties"/>
    
        <!-- 2.配置DataSource数据源:读取数据库配置文件,这里使用的Spring默认的数据源JDBC -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClass" value="${jdbc.driver}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    
    <!-- 3.配置sqlSessionFactory工厂对象 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 2.1 引用dataSource数据源 -->
        <property name="dataSource" ref="dataSource"/>
        <!-- 2.2 绑定Mybatis的核心配置文件 -->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <!-- 2.3 在核心配置文件中注册Mapper.xml文件 -->
        <property name="mapperLocations" value="classpath*:com/kuang/mapper/*.xml"/>
    </bean>
    
    <!-- 4.配置SqlSessionTemplate模板对象 -->
    <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
        <!-- 只能使用构造器注入sqlSessionFactory:因为它没有set方法 -->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>
    
    <!-- 5.配置transactionManager事务管理器:依赖于dataSource数据源 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    
    <!-- 6.结合AOP实现事务的织入:配置事务的通知 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!-- 给方法配置事务,配置事务的传播特性:propagation -->
        <tx:attributes>
            <!-- #1 分别给插入、删除和修改用户的方法,配置propagation事务属性,其值为REQUIRED -->
            <tx:method name="insert" propagation="REQUIRED"/>
            <tx:method name="delete" propagation="REQUIRED"/>
            <tx:method name="update" propagation="REQUIRED"/>
            <!--#2 给查询用户方法设置只读-->
            <tx:method name="select" read-only="true"/>
            <!-- #3 给所有方法(*指所有方法)配置propagation事务属性,值也设为REQUIRED -->
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    
     <!-- 7.配置业务切入 -->
    <aop:config>
        <!-- #7.1 设置切入点,增强com.kuang.mapper包及其子包下的类所有类型的全部方法 -->
        <!-- 使用pointcut:设置切面通知执行的“地点”
             使用expression:定义切入点表达式,execution(* com.kuang.mapper..*.*(..)) -->
        <aop:pointcut id="txPointCut" expression="execution(* com.kuang.mapper..*.*(..))"/>
        <!-- #7.2 执行环绕增加(把txAdvice(事务通知)与txPointCut(切入点的方法)相结合)-->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
    </aop:config>
    
</beans>    
2. 事务传播行为和切入点表达式
2-1 propagation事务传播行为

propagation七种事务传播行为,默认是REQUIRED

  • REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务,则是常见的选择
  • SUPPORTS:支持当前事务,如果当前没有事务,就以非实物方式执行
  • MANDATORY:支持当前事务,如果当前没有事务,就抛出异常
  • REQUIRED_NEW:新建事务,如果当前存在事务,把当前事务挂起
  • NO_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
  • NEVER:以非事务方式执行,如果当前存在事务,则抛出异常
  • NESTED:支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务
2-2 expression切入点表达式

pointcut:表示切入点,即切面通知执行的“地点”

expression:表示定义切入点表达式,即execution(* com.kuang.mapper….(…))

  • execution():表达式主体

  • 第一个 * 号:表示返回类型,*号表示所有的类型

  • com.kuang.mapper…:表示要拦截的包名,后面的两个.号表示当前包和当前包的所有子包

  • 第二个 * 号:表示类名,*号表示所有的类

  • (…):最后这个*号表示方法名, * 号表示所有的方法,后面的()表示方法的参数,两个.号表示任何参数

3.测试结果和使用总结
3-1 测试结果
  • 编写MyTest测试类
package com.kuang.mapper;

import com.kuang.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;

public class MyTest {
    
    @Test
    public void getUsers() {
        // 读取上下文信息,获取Spring的IOC容器
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 通过Spring的IOC容器获取UserMapper对象的Bean信息
        UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
        // 调用userMapper的getUsers方法。获取所有用户信息,然后进行遍历
        for (User user : userMapper.getUsers()) {
            // 打印用户信息
            System.out.println(user);
        }
    }
    
}
  • 测试结果

在这里插入图片描述

3-2 优缺点总结
  • Spring提供了基于tx / AOP 配置的声明式事务管理方式,也是实际开发中最常用的事务管理方式之一
  • 与使用TransactionProxyFactoryBean方式相比,使用Spring AOP XML方式的实现就简单了许多
14.1.4 使用 Spring AOP Annotation 方式
1.修改spring-dao.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context 
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd">
    
       <!-- 1.关联数据库配置文件 -->
       <context:property-placeholder location="classpath:db.properties"/>
    
        <!-- 2.配置DataSource数据源:读取数据库配置文件,这里使用的Spring默认的数据源JDBC -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClass" value="${jdbc.driver}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    
    <!-- 3.配置sqlSessionFactory工厂对象 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 2.1 引用dataSource数据源 -->
        <property name="dataSource" ref="dataSource"/>
        <!-- 2.2 绑定Mybatis的核心配置文件 -->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <!-- 2.3 在核心配置文件中注册Mapper.xml文件 -->
        <property name="mapperLocations" value="classpath*:com/kuang/mapper/*.xml"/>
    </bean>
    
    <!-- 4.配置SqlSessionTemplate模板对象 -->
    <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
        <!-- 只能使用构造器注入sqlSessionFactory:因为它没有set方法 -->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>
    
    <!-- 5.配置transactionManager事务管理器:依赖于dataSource数据源 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    
    <!-- 6.注册事务管理驱动 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>
    
</beans>    
2. 修改UserMapperImpl实现类
package com.kuang.mapper;

import com.kuang.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;
import java.util.List;

public class UserMapperImpl implements UserMapper {
    
    // 引入SqlSessionTemplate对象
    private SqlSessionTemplate sqlSessionTemplate; 

    // 使用set方法动态注入SqlSessionTemplate对象
    public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
        this.sqlSessionTemplate = sqlSessionTemplate;
    }
    
    // 使用@Transactional注解,设置事务传播行为,隔离级别和是否只读
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT,readOnly = true)
    // 重写getUsers方法
    public List<User> getUsers() {
        // 获取UserMapper对象
        UserMapper userMapper = sqlSessionTemplate.getMapper(UserMapper.class);
        // 返回UserMapper对象的getUsers方法
        return userMapper.getUsers();
    }
    
    @Override
    public int insertUser(User user) {
        // 获取UserMapper对象
        UserMapper userMapper = sqlSessionTemplate.getMapper(UserMapper.class);
        // 返回UserMapper对象的insertUser方法
        return userMapper.insertUser(user);
    }

    @Override
    public int deleteUser(int id) {
        // 获取UserMapper对象
        UserMapper userMapper = sqlSessionTemplate.getMapper(UserMapper.class);
        // 返回UserMapper对象的deleteUser方法
        return userMapper.deleteUser(id);
    }

    @Override
    public int UpdateUser(User user) {
        // 获取UserMapper对象
        UserMapper userMapper = sqlSessionTemplate.getMapper(UserMapper.class);
        // 返回UserMapper对象的UpdateUser方法
        return userMapper.UpdateUser(user);
    }
    
}
3.编写测试类和测试结果
3-1 编写测试类
package com.kuang.mapper;

import com.kuang.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;

public class MyTest {
    
    @Test
    public void getUsers() {
        // 读取上下文信息,获取Spring的IOC容器
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 通过Spring的IOC容器获取UserMapper对象的Bean信息
        UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
        // 调用userMapper的getUsers方法。获取所有用户信息,然后进行遍历
        for (User user : userMapper.getUsers()) {
            // 打印用户信息
            System.out.println(user);
        }
    }
}
3-2 测试结果

在这里插入图片描述

4.使用总结
  • 可以在Dao层或者Service层实现类上使用@Transcational注解,就可以开启事务,增删改查的每个方法中的所有SQL都会一个事务中执行,即要么都成功,要么都失败
  • 在一个方法上加了@Transcational注解后,Spring会基于这个类生成一个代理对象,会将这个代理对象作为Bean
  • 当在使用这个代理对象的方法时,如果这个方法上存在@Transcational注解,那么代理逻辑会先把事务的自动提交设置为false,然后再去执行原本的业务逻辑方法
  • 如果执行业务逻辑的方法没有出现异常,那么代理逻辑就会将事务进行提交;如果执行业务逻辑方法出现了异常,那么则会将事务进行回滚
5.优缺点总结
  • 使用@Transcational注解形式相比前两种方式,不需要去编写事务相关的繁琐的配置文件
  • 只需要使用@Transcational注解,然后在注解中配置事务传播行为和隔离级别即可,开发效率得到了提升

好了,今天的有关Spring事务的实现方式的学习就到此结束啦,欢迎小伙伴们积极学习和讨论,喜欢的可以给蜗牛君点个关注,顺便来个一键三连,我们下期见,拜拜啦!


参考视频链接:https://www.bilibili.com/video/BV1WE411d7Dv(【狂神说Java】Spring5最新教程IDEA版通俗易懂)

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

狂奔の蜗牛rz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值