Spring的事务管理
什么是事务
事务
:访问并可能操作各种数据项的一个数据库操作序列,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。事务由事务开始与事务结束之间执行的全部数据库操作组成。
事务的特性(ACID):
原子性
(Atomicity):一个事务是一个不可分割的整体,是一个操作序列,当数据修改时,这些操作序列要么全都执行,要么全都不执行。即,不允许事务部分地完成,避免了只执行这些操作的一部分而带来的错误。
一致性
(Consistency):整个数据库的状态在事务执行前后必须保持一致性状态。比如银行转账,A账户转到B账户,不管转几次,A和B账户的总额不能变。
隔离性
(Isolation):如果有多个并发事务,任意一个事务所做的操作不能被任何其它事务所作的修改干扰,事务与事务之间应该是透明的。
持久性
(Durability):持久性是指事务的操作,一旦提交,对于数据库中数据状态的改变是永久性的,即使数据库发生故障也不能丢失已提交事务所完成的改变。
数据库事务的隔离级别
级别由低到高分为4种
:级别越高,越能保证数据的越能保证数据的完整性
和统一性
,但是对并发性能
的影响也越大。
read uncommitted:
读未提交.
顾名思义:其他事务可以读取到当前事务未提交的数据。-》会导致“脏读”
,实际应用中很少应用此隔离级别。
read committed:
读已提交
其他事务可以读取到当前事务已提交的数据。-》可能会出现“不可重复读”
问题,该问题是一个事务执行过程中,另一事务提交并修改了当前事务正在读取的数据。向上提高隔离级别可解决。
repeatable read:
可重复读
读取数据的事务将会禁止写事务,但允许读事务,写数据事务则禁止任何其他事务,解决了"不可重复读"
,但是会出现"幻读"
问题
serializable:
可串行化
提供严格的事务隔离。要求实施序列化执行,事务只能一个接一个地执行,不能并发执行,严重影响性能。
Spring中的事务
Spring
抽象出一种default
隔离级别,根据数据设置来变动。
read uncommitted
(未提交读)
read committed
(提交读、不可重复读)
repeatable read
(可重复读)
serializable
(可串行化)
default
(PlatformTransactionManager
默认的隔离级别,使用的就是数据库默认
的)
Spring的事务隔离级别比数据库的多出一个,这是因为Spring只提供统一事务管理接口,具体实现都是由各数据库自己
实现(如MySQL,PostgreSql)。Spring会在事务开始时,根据当前环境中设置的隔离级别,调整数据库隔离级别
,由此保持一致。
具体采用哪种隔离级别分三种情况
:
1.当Spring没有指定事务隔离级别,则会采用数据库默认的事务隔离级别;
2.当Spring指定了事务隔离级别,则会在代码里将事务隔离级别修改为指定值;
3.当数据库不支持这种隔离级别,效果则以数据库的为准(比如采用了MyISAM引擎);
在Spring中开启事务管理和声明式事务
在Spring
可以通过@Transactional来指定隔离级别和传播行为
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
但是,如果不是有性能和需求问题,就最好不要改动隔离级别。事务处理弄不好是会锁表的,而锁表在大并发的情况下服务就崩了。
开启事务管理
和声明式事务
注解(xml方式),
<bean id="transactionManager" class="com.hikvision.cms.vms.common.frame.spring.transaction.BaseTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>//增加对@Transactional的支持
在Spring Boot中开启事务管理:
@Configuration
@EnableTransactionManagement
public class TransactionConfiguration {
@Bean
@Qualifier("transactionManager")
public PlatformTransactionManager txManager(@Qualifier("dataSource") DataSource dataSource){
return new DataSourceTransactionManager(dataSource);
}
}
开启后在需要使用事务的类或方法上标注@Transactional即可。
在查询用不用开启事务呢?
https://juejin.im/post/5ea66ca66fb9a03c4c5be52e
单条SQL语句
一般来说,开启事务是会影响数据库读写性能的,在单条sql语句查询时,没有必要开启事务,数据库默认的配置就能满足需求。
多条SQL查询语句
但如果你一次执行多条查询语句,例如统计查询,报表查询,在这种场景下,多条查询SQL必须保证整体的读一致性,否则,在前条SQL查询之后,后条SQL查询之前,数据被其他用户改变,就会造成数据的前后不一。
也仅有在这种情况下,要开启读事务
对于事务的使用要谨慎,判断是否一定要使用,如非必要,不要使用。