Java 事务

大家好呀,我是小笙,本节我分享一些事务有关的知识点

事务

概述

编程式事务

Connection connection = JdbcUtils.getConnection(); 
try {
    //1. 先设置事务不要自动提交 
    connection.setAutoCommint(false); 
    //2. 进行各种多个表的操作
    // ...
    //3. 提交 
    connection.commit(); 
} catch (Exception e) { 
    //4. 回滚
	conection.rollback(); 
}

优点:简单,好理解

缺点::代码冗余,效率低,不利于扩展

声明式事务

需要配置声明式注解

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

<!-- 开启基于注解的声明式事务功能 -->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>

我们如果需要 service 中某个方法执行事务的语句加上注解即可

@Transactional
public void serviceMethod(){}

底层依旧是走了编程式事务的那一套,只是用 AOP 的方式嵌入事务开启、事务提交以及事务回滚

// dataSourceTransactionManager 底层源码
protected void doBegin(Object transaction, TransactionDefinition definition) {
    // ......
    // 核心代码 不开启自动提交事务
    if (con.getAutoCommit()) {
        txObject.setMustRestoreAutoCommit(true);
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
        }

        con.setAutoCommit(false);
    }
    // ......
}

// 提交事务
protected void doCommit(DefaultTransactionStatus status) {
    DataSourceTransactionManager.DataSourceTransactionObject txObject = (DataSourceTransactionManager.DataSourceTransactionObject)status.getTransaction();
    Connection con = txObject.getConnectionHolder().getConnection();
    if (status.isDebug()) {
        this.logger.debug("Committing JDBC transaction on Connection [" + con + "]");
    }

    try {
        con.commit();
    } catch (SQLException var5) {
        throw this.translateException("JDBC commit", var5);
    }
}

// 回滚事务
protected void doRollback(DefaultTransactionStatus status) {
    DataSourceTransactionManager.DataSourceTransactionObject txObject = (DataSourceTransactionManager.DataSourceTransactionObject)status.getTransaction();
    Connection con = txObject.getConnectionHolder().getConnection();
    if (status.isDebug()) {
        this.logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");
    }

    try {
        con.rollback();
    } catch (SQLException var5) {
        throw this.translateException("JDBC rollback", var5);
    }
}

优点:无代码冗余,效率高,扩展方便

缺点:理解较困难

事务的传播的属性/种类

最主要的是 REQUIRED 和 REQUIRES_NEW,主要区别就是在当前运行的事务包裹的情况下是在该事务内部运行还是创建独立的事务运行

传播属性描述
*REQUIRED(默认)如果有事务在运行,当前的方法就在这个事务内运行;否则,就启动一个新的事务,并在自己的事务内运行
*REQUIRES_NEW当前的方法必须启动新事务,并在它自己的事务内运行;如果有事务正在运行,应该将它挂起
SUPPORTS如果有事务在运行,当前的方法就在这个事务内运行;否则它可以不运行在事务中
NOT_SUPPORTEI当前的方法不应该运行在事务中,如果有运行的事务,将它挂起
MANDATORY当前的方法必须运行在事务内部,如果没有正在运行的事务,就抛出异常
NEVER当前的方法不应该运行在事务中,如果有运行的事务,就抛出异常
NESTED如果有事务在运行,当前的方法就应该在这个事务的嵌套事务内运 行;否则,就启动一个新的事务,并在它自己的事务内运行

操作

// 注解分析
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
    @AliasFor("transactionManager")
    String value() default "";

    @AliasFor("value")
    String transactionManager() default "";

    String[] label() default {};

    Propagation propagation() default Propagation.REQUIRED; // 来设置哪种传播属性

    Isolation isolation() default Isolation.DEFAULT;

    int timeout() default -1;

    String timeoutString() default "";

    boolean readOnly() default false;

    Class<? extends Throwable>[] rollbackFor() default {};

    String[] rollbackForClassName() default {};

    Class<? extends Throwable>[] noRollbackFor() default {};

    String[] noRollbackForClassName() default {};
}

// 实际代码
@Transactional(propagation = Propagation.REQUIRES_NEW)
 public void serviceMethod(){}

事务隔离级别

Java 默认的隔离级别, 就是 mysql 数据库默认的隔离级别 一般为 REPEATABLE_READ

隔离级别脏读不可重复读幻读加锁读
读未提交会发生会发生会发生不加锁
读已提交不会发生会发生会发生不加锁
可重复读不会发生不会发生不会发生不加锁
可串行化不会发生不会发生不会发生加锁
  1. 脏读:当一个事务正在访问数据并且对数据进行了修改,但是还没有提交时,另一个事务读取到了修改之后的数据,但是前面的事务进行回滚了,此时就出现了脏读
  2. 不可重复读:一个事务在查询数据时另一个修改数据的事务刚好提交,再次查询时,两次查询结果不一样。(即不能读到相同的数据内容)
  3. 幻读:在一个事务的两次查询中数据不一致,例如:一个事务查询一次数据,在此时另一个事务插入了几条数据,当再次查询时出现了几条之前没有的数据,产生幻读

不可重复读和幻读的区别

可以理解为:不可重复读重点在于update和delete (只用行锁),而幻读的重点在于insert (必须表级锁)

查看数据库默认的隔离级别

SELECT @@global.tx_isolation;

格式

@Transactional(isolation = Isolation.READ_COMMITTED)
public void serviceMethod(){}

事务的超时回滚

如果一个事务执行的时间超过某个时间限制,就让该事务回滚(单位:秒)

格式

// 通过抛出异常的形式,超时发生事务回滚
@Transactional(timeout = 2)
public void serviceMethod(){}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

罗念笙

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

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

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

打赏作者

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

抵扣说明:

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

余额充值