事务管理

本文详细介绍了Spring中的事务管理,包括基于注解和配置文件的事务管理方式,事务的传播行为,如PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW等,以及事务的隔离级别,如ISOLATION_READ_COMMITTED、ISOLATION_SERIALIZABLE等。此外,还讨论了事务超时和回滚规则。
摘要由CSDN通过智能技术生成

一、基于注解的事务:

<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="datasource" />
</bean>

<!-- 启用事务的注解 -->

<tx:annotation-driven transaction-manager="transactionManager" />

 

二、基于配置文件的事务:

<!-- 配置事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>

<!-- 配置事务的属性:如传播行为,隔离级别,超时,只读,回滚等属性 -->
<tx:advice id="advice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="get*" read-only="true" />
<tx:method name="update*" read-only="false" />
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>

<!-- 配置事务的切点,以及把事务切点和事务属性关联起来 -->
<aop:config>
<!-- 配置切点表达式 -->
<aop:pointcut id="txPointcut" expression="execution(* com.demo.transaction.service.*.*(..))" />
<!-- 把事务切点和事务属性关联起来 -->
<aop:advisor advice-ref="advice" pointcut-ref="txPointcut" />

</aop:config>

 

三、事务的传播行为:即当前的事务方法被另一个事务方法调用时,如何使用事务

  • TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
  • TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
  • TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
  • TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
  • TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
  • TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
  • TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。内嵌事务并不是一个独立的事务,它依赖于外部事务的存在,只有通过外部的事务提交,才能引起内部事务的提交,嵌套的子事务不能单独提交,外部事务的回滚也会导致嵌套子事务的回滚

 

四、隔离级别

 

隔离级别是指若干个并发的事务之间的隔离程度。TransactionDefinition 接口中定义了五个表示隔离级别的常量:

  • TransactionDefinition.ISOLATION_DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是TransactionDefinition.ISOLATION_READ_COMMITTED,但mysql的默认隔离级别是可重复读
  • TransactionDefinition.ISOLATION_READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读、不可重复读和幻读,因此很少使用该隔离级别。
  • TransactionDefinition.ISOLATION_READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,但是不能防止不可重复读和幻读,这也是大多数情况下的推荐值。
  • TransactionDefinition.ISOLATION_REPEATABLE_READ:重复读,就是在开始读取数据(事务开启)时,不再允许修改操作。重复读可以解决不可重复读问题。不可重复读对应的是修改,即UPDATE操作。但是可能还会有幻读问题。因为幻读问题对应的是插入INSERT操作,而不是UPDATE操作,该级别可以防止脏读和不可重复读,但是不能防止幻读
  • TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

脏读:对于两个事务T1和T2,T1读取了已经被T2更新但还没有被提交的字段,之后,若T2回滚,T1读取的内容就是临时无效的
不可重复读:对于两个事务T1和T2,T1读取了一个字段,然后T2更新了该字段,之后T1再次读取同一个字段,值就不同了
幻读:对于两个事务T1和T2,T1读取了一个字段,然后T2在该表中插入新的行,然后T1再次读取同一个字段,就会多出几行
 

 

五、事务超时

所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。

六、事务的回滚规则

通常情况下,如果在事务中抛出了未检查异常(继承自 RuntimeException 的异常),则默认将回滚事务。如果没有抛出任何异常,或者抛出了已检查异常,则仍然提交事务。这通常也是大多数开发者希望的处理方式,也是 EJB 中的默认处理方式。但是,我们可以根据需要人为控制事务在抛出某些未检查异常时任然提交事务,或者在抛出某些已检查异常时回滚事务。

 

package com.example.test2.service;

import com.example.test2.domain.User;
import com.example.test2.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

/**
 * 测试不同事务的用法
 *
 * @date 2020/5/27 16:41
 * @since
 */
@Slf4j
@Service
public class TransactionService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private TransactionTemplate transactionTemplate;

    @Autowired
    private PlatformTransactionManager transactionManager;

    /**
     * 1、使用声明式, 在同一个类中,非事务方法调用事务方法,如 test() 调用 annotationTransaction(), 会导致事务失效
     * 2、编程式事务,test()调用codeTransaction()和codeTransation2(),事务依然有效
     */
    public void test() {
        log.info("test-----------------------");

        codeTransation2();
    }


    /**
     * 声明式事务 @Transactional 注解事务
     */
    @Transactional
    public void annotationTransaction() {
        log.info("annotationTransaction---------------------------");

        saveData();

    }

    /**
     * 编程式事务1  TransactionTemplate
     */
    public void codeTransaction() {
        transactionTemplate.execute(new TransactionCallback<Boolean>() {

            @Override
            public Boolean doInTransaction(TransactionStatus status) {
                log.info("status----------------{}", status);

                saveData();

                return true;
            }
        });
    }

    /**
     * 编程式事务2  PlatformTransactionManager
     */
    public void codeTransation2() {
        TransactionDefinition transactionDefinition = new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRED);
        TransactionStatus status = transactionManager.getTransaction(transactionDefinition);

        try {
            saveData();
            transactionManager.commit(status);
        } catch (Exception e) {
            log.error("exception", e);
        } finally {
            if (!status.isCompleted()) {
                transactionManager.rollback(status);
            }
        }

    }

    /**
     * 设置数据
     */
    private void saveData() {
        User user = new User();
        user.setName("name1");
        user.setAge(12);
        user.setAddress("上海");
        user.setIphone("123");
        userMapper.insert(user);

        User user2 = new User();
        user2.setName("name2");
        user2.setAge(12);
        user2.setAddress("上海");
        user2.setIphone("123");
        userMapper.insert(user2);

        throw new RuntimeException("抛出异常");

    }


}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值