什么是事务?
保证业务操作完整性的一种数据库机制
事务的四大特定:ACID
A :原子性:
原子性确保一个事务中的所有操作要么全部成功,要么全部失败。如果事务的任何部分失败,整个事务将被回滚到初始状态,不会留下部分更改。这意味着事务是不可分割的单元,要么完全执行,要么完全不执行。
C : 一致性
一致性确保事务将数据库从一个一致的状态变为另一个一致的状态。在事务开始和结束时,数据库必须满足一组预定义的规则(业务规则、约束等)。如果事务执行过程中违反了这些规则,事务将被回滚。
I : 隔离性
隔离性确保多个事务同时执行时,每个事务都不会受到其他事务的影响。每个事务都应该以一种独立的方式执行,就好像其他事务不存在一样。这防止了并发事务之间可能出现的问题,如脏读、不可重复读和幻读。 D: 持久性
持久性确保一旦事务成功提交,其结果将在数据库中永久存储,即使在系统发生故障或重启后也不会丢失。这通常涉及将事务的更改写入稳定的存储介质(如硬盘)。
如何来控制事务
JDBC:
Connection.setAutoCommit(false);
Connection.commit();
Connection.rollback();
Mybatis:
Mybatis自动开启事务(sqlSession底层封装了Connection)
sqlSession.commit();
sqlSession.rollback();
结论:
控制事务的底层都是Connection对象完成的
Spring控制事务开发
- Spring是通过AOP的方式进行事务开发的
- 原始对象
kotlin
public class XXXUserServiceImpl{
private xxxDAO xxxDAO;
set /get
1.原始对象--->原始方法--->核心功能(业务处理+DAO调用)
2. DAO 作为Service的成员变量,通过依赖注入的方式赋值
}
- 额外功能(事务)
scss
Spring封装了这个事务(DataSoureceTranactionManager)
我们要为它注入Connection ===注入连接池
1.MethodInterceptor
invoke(MehodInvocation invocation){
try {
Connection.setAutoCommit(false)
Object ret=invocation.proceed();
Connection.commit();
}catch(Excetion e){
Connection.rollback();
}
return ret;
}
2.@Aspect
- 切入点
markdown
@Transational
事务的额外功能加给哪些业务方法
1. 类上:这个类中,所以的方法加入事务
2. 方法上:这个方法会加入事务
- 切面
<tx:annotiaion-driven transaction-manager=""/>
Spring控制事务的编码
- 搭建开发环境
xml
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>6.0.8</version>
</dependency>
xml
<bean id="userService" class="com.huy.service.UserServiceImpl">
<property name="userDAO" ref="userDAO"></property>
</bean>
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSourse"></property>
</bean>
<!--组合切入点和事务-->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
Spring中的事务属性
1. 什么是事务属性
描述物体特征的一系列值
事务属性:描述事务特征的一系列值
- 隔离属性
- 传播属性
- 只读属性
- 超时属性
- 异常属性
2. 如何添加事务属性
ini
@Transactional(isloation= ,propagation= ,redaOnly= ,timeout= ,
rollbackFor=,noRollbackFor=)
3. 事务属性详解
3.1. 隔离属性
概念:它描述了事务解决并发问题的特征
- 什么是并发
多个事务或者用户在同一时间,访问或操作了相同数据
同一时间:0.000几秒的 微小前 微小后的差异
- 并发产生的哪些问题
-
- 脏读
- 不可重复读
- 幻读
- 并发问题如何解决
-
- 通过隔离属性来解决,隔离属性设置不同的值,处理并发处理过程中的问题
- 事务并发的问题
脏读:
指的是,一个事务读取了另一个事务没有提交的数据。会在事务中产生数据不一致的问题
账户本来有1000块,suns媳妇先去取了700,但没提交,这时候suns取取钱,发现里面是700,取了 200,但suns媳妇最后回滚了,suns取钱提交了,这时候账户就只剩500了,少了300块钱。这就是
一个事务读取到另一个事务还没提交的事务,产生数据不一致的问题
解决方案:
@Transactional(isolation=Isolation.READ.COMMITTED)
改为读已提交
不可重复读:
指的是:一个事务中,多次读取相同数据,但是读取结果不一样。会在事务中产生数据不一致的问题
suns媳妇开启事务,先查询了余额1000,然后进行一系列操作,suns这时候取了200,并且已经提交,这时候suns媳妇又查询了余额发现为800,两次读取余额不一致
注意:1 不是脏读 2 他是在一个事务中读了两次不一样
解决方案: @Transactional(isolation=Isolation.REPEATABLE_TABLE)
本质:一把行锁
也就是suns媳妇开启了事务操作那一行数据的时候,suns去操作那行数据,就得登suns媳妇提交事务才能去操作,这样suns媳妇拿到的数据就会是一致的
幻影读:
一个事务中,多次对整表进行查询统计,但是结果不一样,会在本事务中产生的数据不一致的问题
解决方案:
@Transactional(isolation=Isolation.SERIALIZEABLE)
本质:数据库底层的表锁
t1统计表的时候,给整表加上表锁,只有等t1提交事务,t2才能进行操作
- 总结
并发安全: SERIALIZABLE>REPEATABLE_READ>READ_COMMITTED
运行效率: SERIALIZABLE<REPEATABLE_READ<READ_COMMITTED
- 数据库对于隔离属性的支持
- 默认的隔离属性
ISOLATION_DEFAULT:会调用不同数据所设置的默认隔离属性
MYSQL: REPEATABLE_READ
Oracle: READ_COMMITTED
查看你默认隔离属性
MySQL:
SELECT @@global.transaction_isolation;
Oracle:
- 隔离属性推荐实战中
推荐使用Spring指定的默认隔离级别
MySQL :repeatable_read 可重复读
如果真遇到并发的问题,我们会通过乐观锁
Hibernate(JPA) Version
Mybatis 通过拦截器自定义开发
3.2. 传播属性
- 概念
描述了事务解决嵌套问题的特征
什么是事务的嵌套
它指的是一个大的事务其中包含一个小的事务
问题: 大事务中融入了很多小的事务,他们彼此影响,最终就会导致外部大的大事务,失去了事务的原子性。
- 传播属性的值以及其用法
less
@Transactional(Propagation=Propagation.REQUIRED)
REQUIRED
1. 外部不存在事务,开启新的
2. 外部存在事务,融合
一般增删改方法使用这个传播属性,REQUIRED
@Transactional(Propagation=Propagation.SUPPORTS)
SUPPORTS
1. 外部不存在事务,不开启事务
2. 外部存在事务 融合
一般会运用在查询方法中,SUPPORTS
- 默认的传播属性
REQUIRED是传播属性的默认值
- 推荐传播属性的使用方法
增删改:使用默认值 REQUIED
查询: 操作:显示的指定传播属性的值为SUPPORTS
- 其他传播属性
REQUIREDS_NEW 外部不存在事务,开启新事务,
外部存在事务,挂起外部事物,开启新的事务,
新的事务执行完后,在执行外部事务
3.3. 只读属性(readOnly)
针对于只进行查询操作的业务方法,可以加入只读属性,提供运行效率
@Transation(readOnly=true)
默认值 false
所以在查询操作的过程中就加上只读属性
3.4. 超时属性(timeout)
指定了事务等待的最长时间
- 为什么事务进行等待?
当前事务访问数据时,有可能访问的数据被其他的事务进入加锁的处理,那么此时本事务就必须等待
- 等待时间 秒
- 如何使用
@Transation(timeout=2)
- 超时属性的默认值 -1
最终由对应的数据来指定
3.5. 异常属性
Spring事务处理过程中
默认 对于RuntimeException以及其子类 采用的是回滚的策略
对于Exception以及其子类 采用的是提交的策略
rollbackFor ={java.lang.Exception.class} 抛出.Exception回滚
noRollbackFor={java.lang.RuntimeException.class} 抛出RuntimeException提交
建议:实战中使用RuntimeException回滚,也就是spring默认的异常属性
4. 事务属性常见配置总结
- 隔离属性 默认值
- 传播属性 REQUIRED(默认值) 增删改 Supports 查询操作
- 只读属性 readOnly 默认 false 查询操作 true
- 超时属性 timeout -1
- 异常属性 默认值 RuntimeException 回滚 Exception 提交
增删改操作 @Transactional
查询操作 @Transactional(propagation=supports,redaOnly=true)