Spring Transaction

Java框架

浏览数:145

2019-8-23

AD:资源代下载服务

目录说明

1 概述

是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。事务可以分为编程式事务声明式事务

编程式事务控制又叫细粒度事务的控制,可以针对指定的方法以及方法中具体的某一行代码添加事务控制。需要自己每次手动的去添加,开发比较繁琐,每次都要开启、提交、回滚。

  • jdbc 代码:conn.setAutoCommite(false) //设置手动控制事务
  • hibernate 代码:session.beginTransaction() //开启一个事务

声明式事务又叫粗粒度事务的控制,只能给方法添加事务控制。Spring 提供了对事务的管理,我们需要使用事务时只需要在配置文件中配置即可,不使用时直接移除,这样便大大的降低了事务控制的耦合。Spring 事务控制的实现是依赖与 Aop。

2 事务控制的几种方式

2.1 xml 实现

【1】步骤

  1. 引入 Spring-aop 相关的4个 jar
  2. 引入 aop 名称空间
  3. 引入 tx 名称空间
  4. 引入 Spring-jdbc 相关 jar(使用到spring jabcTemplate)

【2】实现
模拟: 在service中调用2次dao, 希望其中一个dao执行失败,整个操作回滚

bean.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:p="http://www.springframework.org/schema/p"
    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
        http://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. 数据源对象: C3P0连接池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
        <property name="user" value="root"></property>
        <property name="password" value="root"></property>
        <property name="initialPoolSize" value="3"></property>
        <property name="maxPoolSize" value="10"></property>
        <property name="maxStatements" value="100"></property>
        <property name="acquireIncrement" value="2"></property>
    </bean>
    
    <!-- 2. 创建JdbcTemplate对象 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 3.创建 Dao、Service -->
    <bean id="userDao" class="com.acey.tx.a_xml_tx.UserDao">
        <property name="jdbcTemplate" ref="jdbcTemplate"/>
    </bean>
    <bean id="userService" class="com.acey.tx.a_xml_tx.UserService">
        <property name="userDao" ref="userDao"/>
    </bean>

    <!-- 4. 声明式事务管理配置-->
    <!-- 4.1 配置事务管理器类-->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!-- 4.2 配置事务增强(如何管理)-->
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <!--(1)方法名中包含 find 的方法只读-->
            <tx:method name="*find*" read-only="true"/>
            <!--(2)方法名中以 get 开头的方法只读-->
            <tx:method name="get*" read-only="true"/>
            <!--除了(1)和(2)其它的方法进行读写-->
            <tx:method name="*" read-only="false"/>
        </tx:attributes>
    </tx:advice>
    <!-- 4.3 aop 配置,拦截哪些方法应用事务管理-->
    <aop:config>
        <aop:pointcut id="pt" expression="execution(* com.acey.tx.a_xml_tx.*Service.*(..))" />
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
    </aop:config>
</beans>

由于我们使用的是 jdbc 技术,所以我们在配置事务管理器类时使用的是
DataSourceTransactionManager,如果我们使用的是 hibernate 技术,我们需要使用
HibernateTransactionManager

2.2 注解实现

【1】步骤

  1. 引入 Aop 相关 jar
  2. bean.xml 中配置事务管理器类以及指定 注解方式实现声明式事务
  3. 在需要添加事务控制的地方加上 @Transactional

@Transactional注解

  • 定义到方法上,当前方法使用 Spring 的声明式事务
  • 定义在类上,当前类的所有方法使用 Spring 的声明式事务
  • 定义到父类上,当执行父类的方法时应用事务

【2】实现(核心代码)

bean.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:p="http://www.springframework.org/schema/p"
       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
        http://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. 数据源对象: C3P0连接池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
        <property name="user" value="root"></property>
        <property name="password" value="root"></property>
        <property name="initialPoolSize" value="3"></property>
        <property name="maxPoolSize" value="10"></property>
        <property name="maxStatements" value="100"></property>
        <property name="acquireIncrement" value="2"></property>
    </bean>
    
    <!-- 2. 创建JdbcTemplate对象 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 3. 开启注解扫描-->
    <context:component-scan base-package="com.acey.tx.b_anno_tx"/>
    <!-- 4.创建事务管理器-->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 5.开启事务注解-->
    <tx:annotation-driven transaction-manager="txManager"></tx:annotation-driven>
</beans>

UserDao.class

@Repository
public class UserDao {
    @Resource
    private JdbcTemplate jdbcTemplate;

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

//    @Transactional(
//            readOnly = false,   //读写事务
//            timeout = -1,       //事务的超时时间(-1(默认值)表示不限制)
//            noRollbackFor = ArithmeticException.class,    //遇到数学类异常不回滚
//            propagation = Propagation.REQUIRED      //事务的传播行为
//    )
    @Transactional
    public void save(String name) {
        String sql = "insert into t_user (name) values(?)";
        jdbcTemplate.update(sql, name);
        int i = 1 / 0;//异常
        jdbcTemplate.update(sql, name);
    }
}

3 事务属性

@Transactional(
            readOnly = false,   //读写事务
            timeout = -1,       //事务的超时时间(-1(默认值)表示不限制)
            noRollbackFor = ArithmeticException.class,    //遇到数学类异常不回滚
            propagation = Propagation.REQUIRED      //事务的传播行为
    )

其中事务传播行分为:

  • Propagation.REQUIRED
    指定当前的方法必须在事务的环境下执行;
    如果当前运行的方法,已经存在事务, 就会加入当前的事务;
  • Propagation.REQUIRED_NEW
    指定当前的方法必须在事务的环境下执行;
    如果当前运行的方法,已经存在事务: 事务会挂起; 会始终开启一个新的事务,执行完后;
    刚才挂起的事务才继续运行。

所有实例代码地址 https://github.com/Aceysx/SpringDemo

作者:司鑫