Spring的事务

1、事务的概念

事务就是对于数据库数据的一组不可分割的操作,这些操作要么全部执行,要么全部不执行。

2、事务的特性

事务具有四大特性:ACID

2.1、原子性(Automicity)

一个事务的所有操作要么全部执行,要么全部不执行,不会结束在某个中间环节。事务如果在执行过程发生错误,就会被回滚(Rollback)到事务开始前的状态,就好像这个事务从来没有执行过。

2.2、一致性(Consistency)

一个事务执行前后,数据库的状态都要保持一致。

比如一个事务对数据a执行加一的操作,在事务成功执行后数据库中的这个数据a的值必须是加了一。或者两个人互相转账,转账前后的总金额都是不变的。

2.3、隔离性(Isolation)

主要指的是在并发环境下,一个事务的操作不受其他并发事务的影响,在一个独立隔离的环境中进行操作。事务查看数据更新时,要么看到的是其他并发事务对数据更新后的状态,要么是其他并发事务对数据更新前的状态,不会看到其他事务具体操作过程中数据的状态。

2.3、持久性(Durability)

指的是事务成功结束后,它对于数据库的更新会保存到磁盘当中实现一个持久化的存储。即使数据库崩溃或者重启,都能恢复到事务成功结束时的状态。

3、编程式事务

事务功能的相关操作都能通过自己编写代码实现

Connection conn = ...;
    
try {
    
    // 开启事务:关闭事务的自动提交
    conn.setAutoCommit(false);
    
    // 核心操作
    
    // 提交事务
    conn.commit();
    
}catch(Exception e){
    
    // 回滚事务
    conn.rollBack();
    
}finally{
    
    // 释放数据库连接
    conn.close();
    
}

缺点:

  1. 细节没有被屏蔽,所有操作细节都需要开发人员自己去实现,比较繁琐。
  2. 代码的复用性比较差,如果对其中的一些功能有效抽离出来,每次实现都需要开发人员自己编写代码,效率低。

4、声明式事务概念

框架将对于事务的一些相关操作抽取出来进行封装,封装好后,只需要在配置文件中进行简单的配置就能完成操作。

优点:

  1. 提高了开发效率。
  2. 减少了冗余的代码。
  3. 框架会综合考虑实际开发中的各种问题,进行健壮性和性能等各个方面的优化。

所以,我们可以总结下面两个概念:

  • 编程式自己写代码实现功能

  • 声明式:通过配置框架实现功能

5、声明式事务实现

两种方式:基于注解实现和基于XML实现,第一种使用比较多,所以这里着重介绍第一种实现方式。

6、基于注解实现声明式事务

6.1、添加事务配置

在Spring的配置文件中添加相关配置,开启事务的注解驱动。

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="druidDataSource"></property>
</bean>

<!--
    开启事务的注解驱动
    通过注解@Transactional所标识的方法或标识的类中所有的方法,都会被事务管理器管理事务
-->
<!-- transaction-manager属性的默认值是transactionManager,如果事务管理器bean的id正好就是这个默认值,则可以省略这个属性 -->
<tx:annotation-driven transaction-manager="transactionManager" />

6.2、添加事务注解

因为service层是处理业务逻辑的,因此事务的处理一般在service层进行。

 在业务层添加@Transactional注解。

7、@Transactional注解

7.1、标注位置

标注到方法上,则只会影响这个方法。

标注到类上,则会影响这个类中的所有方法。

7.2、事务属性

1、只读

对一个查询操作来说,如果把它设置为只读,就能明确的告诉数据库,这个操作不涉及写操作,进行写操作时会抛出异常。

@Transactional(readOnly = true)
public void buyBook(Integer bookId, Integer userId) {
    //查询图书的价格
    Integer price = bookDao.getPriceByBookId(bookId);
    //更新图书的库存
    bookDao.updateStock(bookId);
    //更新用户的余额
    bookDao.updateBalance(userId, price);
    //System.out.println(1/0);
}

2、超时

事务在执行过程中可能遇到某些问题卡住,从而长时间的占用资源,因此需要设置一个超时时间,让事务回滚,释放资源。

//超时时间单位秒
@Transactional(timeout = 3)

3、回滚策略

声明式事务默认是针对运行时异常回滚,编译时异常不回滚。

相关属性:

  • rollbackFor属性:需要设置一个Class类型的对象

  • rollbackForClassName属性:需要设置一个字符串类型的全类名

  • noRollbackFor属性:需要设置一个Class类型的对象

  • rollbackFor属性:需要设置一个字符串类型的全类名

@Transactional(noRollbackFor = ArithmeticException.class)

4、隔离级别

隔离级别一共有四种:

  • 读未提交:READ UNCOMMITTED

    允许Transaction01读取Transaction02未提交的修改。

  • 读已提交:READ COMMITTED、

    要求Transaction01只能读取Transaction02已提交的修改。

  • 可重复读:REPEATABLE READ

    确保Transaction01可以多次从一个字段中读取到相同的值,即Transaction01执行期间禁止其它事务对这个字段进行更新。

  • 串行化:SERIALIZABLE

    确保Transaction01可以多次从一个表中读取到相同的行,在Transaction01执行期间,禁止其它事务对这个表进行添加、更新、删除操作。可以避免任何并发问题,但性能十分低下。

@Transactional(isolation = Isolation.DEFAULT)//使用数据库默认的隔离级别
@Transactional(isolation = Isolation.READ_UNCOMMITTED)//读未提交
@Transactional(isolation = Isolation.READ_COMMITTED)//读已提交
@Transactional(isolation = Isolation.REPEATABLE_READ)//可重复读
@Transactional(isolation = Isolation.SERIALIZABLE)//串行化

5、传播行为

什么是事务的传播行为?

在一个类中有a()方法和b()方法,a()方法上有事务,b()方法上也有事务,当a()方法执行过程中调用了b()方法,事务是如何传递的?合并到一个事务里?还是开启一个新的事务?这就是事务传播行为。

可以通过@Transactional中的propagation属性设置事务传播行为。

一共有七种传播行为:

  • REQUIRED:支持当前事务,如果不存在就新建一个(默认)【没有就新建,有就加入】

  • SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行【有就加入,没有就不管了】

  • MANDATORY:必须运行在一个事务中,如果当前没有事务正在发生,将抛出一个异常【有就加入,没有就抛异常】

  • REQUIRES_NEW:开启一个新的事务,如果一个事务已经存在,则将这个存在的事务挂起【不管有没有,直接开启一个新事务,开启的新事务和之前的事务不存在嵌套关系,之前事务被挂起】

  • NOT_SUPPORTED:以非事务方式运行,如果有事务存在,挂起当前事务【不支持事务,存在就挂起】

  • NEVER:以非事务方式运行,如果有事务存在,抛出异常【不支持事务,存在就抛异常】

  • NESTED:如果当前正有一个事务在进行中,则该方法应当运行在一个嵌套式事务中。被嵌套的事务可以独立于外层事务进行提交或回滚。如果外层事务不存在,行为就像REQUIRED一样。【有事务的话,就在这个事务里再嵌套一个完全独立的事务,嵌套的事务可以独立的提交和回滚。没有事务就和REQUIRED一样。】

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值