每一秒钟的时间都值得铭记

0%

Spring的事务管理

什么是事务?

所谓事务,就是指数据库中的一组操作,这些操作要么全部都执行成功,要么全部都执行失败,执行成功的事务提交到数据库中,执行失败的事务则回滚。

事务的四大特性

  • 原子性(Atomicity)
    原子是最小的单位,代表了不可分割。原子性表明,事务是数据库中操作的最小单元,事务中的操作要么全部成功,要么全部失败。
  • 一致性(Consistency)
    事务的执行前后,数据库的状态必须保持一致。
  • 隔离性(Isolation)
    一个事务的执行不能被另外的事务所干扰,事务执行的过程对于其他事务而言是隔离的。也就是说,另外的事务查看的数据,要么是一个事务提交前的数据,要么就是一个事务提交后的数据,事务执行的中间过程是隔离的。
  • 持久性(Durability)
    一个事务成功提交后,那么这个事务所做的操作引起的数据变化,会被持久化到数据库中。

数据库的读问题

事务的四大特性中,隔离性是保证事务安全的一个重要特性,如果不考虑事务的隔离性,就会引发数据库的读问题。

  • 脏读:一个事务读到另一个事务未提交的数据。【解决方案:读已提交】
  • 不可重复读:一个事务读到另一个事务已提交的update数据,导致一个事务前后两次读取的数据不一致。【解决方案:重复读】
  • 幻读:一个事务读到另一个事务已提交的insert数据,导致一个事务中多次查询结果不一致。【解决方案:序列化读】

数据库的隔离级别

为了解决数据库的读问题,于是设立了数据的隔离级别。

  • Read uncommitted:读未提交,任何读问题解决不了。
  • Read committed:读已提交,这个事务的隔离级别,在事务开启时,要等另一个事务提交后才能读取数据,可以解决脏读问题,但是不可重复读和幻读有可能发生。
  • Repeatableread:重复读,这个的隔离级别,在事务开启式,不允许其它事务进行update操作,可以解决脏读和不可重复读,但是幻读有可能发生。
  • Serializable:序列化读,所有事务串行化顺序执行,解决所有读问题。不过这个事务的隔离级别会严重拖慢数据库性能。

Spring的事务管理

有了以上的事务知识,那么我们就可以来看一看Spring的事务管理了。
在Spring中,PlatformTransactionManager接口是事务平台管理器,是Spring中用于真正管理事务的对象,它有两个具体的实现类,底层分别使用不同的事务管理方式。

  • DataSourceTransactionManager:底层使用JDBC管理事务
  • HibernateTransactionManager:底层使用Hibernate管理事务

Spring一共定义了七种事务的传播行为

保证多个操作在同一个事务中

  1. PROPAGATION_REQUIRED:默认值,如果A中有事务,使用A中的事务,如果A没有,创建一个新的事务,将操作包含进来。
  2. PROPAGATION_SUPPORTS:支持事务,如果A中有事务,使用A中的事务。如果A没有事务,不使用事务。
  3. PROPAGATION_MANDATORY:如果A中有事务,使用A中的事务。如果A没有事务,抛出异常。

保证多个操作不在同一个事务中

  1. PROPAGATION_REQUIRES_NEW:如果A中有事务,将A的事务挂起(暂停),创建新事务,只包含自身操作。如果A中没有事务,创建一个新事务,包含自身操作。
  2. PROPAGATION_NOT_SUPPORTED :如果A中有事务,将A的事务挂起。不使用事务管理。
  3. PROPAGATION_NEVER :如果A中有事务,报异常。

嵌套式事务

  1. PROPAGATION_NESTED:嵌套事务,如果A中有事务,按照A的事务执行,执行完成后,设置一个保存点,执行B中的操作,如果没有异常,执行通过,如果有异常,可以选择回滚到最初始位置,也可以回滚到保存点。

Spring编程式事务管理(了解)

spring编程式事务管理,由于代码书写多,在正式开发中几乎不会使用,该知识点仅限于了解。

1
2
3
4
5
6
7
8
9
<!-- 第一步:在spring的配置文件中配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>

<!-- 第二步:在spring的配置文件中配置事务模板 -->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"></property>
</bean>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Autowired
private UserDao userDao;

/**
*第三步,在service层中注入事务模板
*/
@Autowired
private TransactionTemplate transactionTemplate;

@Override
public void deleteUser(Integer id) throws Exception {
/**
*第四步:使用事务模板中的execute方式,传入一个匿名内部借口,
*并实现接口中的方法,将所有代码放在这个方法中
*/
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@SneakyThrows
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
userDao.deleteUser(id);
int i = 1/0;
}
});
}

Spring的声明式事务管理

基于xml配置文件的方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!--spring提供的事务管理器,注入dataSource-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>

<!--声明式事务管理,事务的通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--事务的传播行为,所有的保存方法使用save打头,事务的传播行为为REQUIRED-->
<tx:method name="save*" propagation="REQUIRED" />
<!--所有的删除方法使用delete打头,事务的传播行为为REQUIRED-->
<tx:method name="delete*" propagation="REQUIRED" />
<!--所有的更新方法使用update打头,事务的传播行为为REQUIRED-->
<tx:method name="update*" propagation="REQUIRED" />
<!--所有的查询方法使用find打头,事务的传播行为为SUPPORTS,事务只读-->
<tx:method name="find*" propagation="SUPPORTS" read-only="true" />
</tx:attributes>
</tx:advice>

<!--配置切面,service.impl包下的所有类所有方法都进行切面拦截-->
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.hrp.service.impl.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut" />
</aop:config>

基于@Transactional注解方式

1
2
<!--开启spring的基于注解的的事务管理-->
<tx:annotation-driven transaction-manager="transactionManager"/>
1
2
3
4
5
6
@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
@Override
public void deleteUser(Integer id) throws Exception {
userDao.deleteUser(id);
int i = 1/0;
}

基于@Transactional注解方式的事务管理,也可以通过注解中属性来定义事务管理的方式。

  • rollbackFor :(值为异常的字节码对象)遇到该异常时回滚
  • noRollbackFor:(值为异常的字节码对象)遇到该异常时不回滚
  • propagation :(值为Propagation枚举对象)事务的传播行为
  • readOnly:(值为true或者false)事务是否只读

Spring事务的回滚规则:在Spring的事务管理中,默认只有遇到运行时异常才会回滚事务,遇到编译期异常默认不回滚事务。
当然,开发者也可以通过自己指定遇到某种异常回滚或者不回滚。

坚持原创技术分享,您的支持将鼓励我继续创作!
-------------这是我的底线^_^-------------