spring事务管理
作者:互联网
spring事务管理
spring的事务管理
事务:指单个逻辑操作单元的集合
在操作数据库时(增删改),如果同时操作多次数据,我们从业务希望,要不全部成功,要不全部失败。这种情况称为事务处理。
A转账给B。
第一步,扣除A君账号要转的金额
第二步,增加B君账号的金额
事务的ACID:
原子性(Atomicity)
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
一致性(Consistency)
事务前后数据的完整性必须保持一致。-一荣俱荣,一损俱损
隔离性(Isolation)
事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
持久性(Durability)
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响
spring事务控制我们要明确的
1.JavaEE体系进行分层开发,事务处理位于业务层,所以,一般情况下我们使用事务代理(事务管理器),一般放在分层设计业务层。
2.spring框架为我们提供了一组事务控制的应用程序接口(API)。
3.spring的事务控制都是基于AOP的,它既可以使用编程的方式实现,也可以使用配置的方式实现。我们学习的重点是使用配置的方式实现。
比如转账问题,当A转账给B时,如果从A上扣完钱后,突然就出现了异常,钱并没有转到B中,但是A的钱扣了,可想而知事务是多么重要。
数据库并发问题:
什么是数据库并发问题?
并发: 多个客户端同时同时访问数据库中某一条数据(秒杀)
数据库可以拥有多个访问客户端,若多个客户端并发地访问数据库中相同的资源,如果没有采取必要的隔离措施,则会导致各种并发问题,破坏数据的完整性。
这些问题归结为5类
包括3类数据读问题(脏读,不可重复读,幻读)
和2类数据更新问题(第一类丢失更新,第二类丢失更新)
第一类数据丢失问题
两个事务更新相同数据,如果一个事务提交,另一个事务回滚,第一个事务的更新会被回滚
第二类数据丢失问题
多个事务同时读取相同数据,并完成各自的事务提交,导致最后一个事务提交会覆盖前面所有事务对数据的改变
脏读
第二个事务查询到第一个事务未提交的更新数据,第二个事务根据该数据执行,但第一个事务回滚,第二个事务操作脏数据
幻读/虚读
一个事务查询到了另一个事务已经提交的新数据,导致多次查询数据不一致
不可重复读
一个事务查询到另一个事务已经修改的数据,导致多次查询数据不一致
事务的隔离级别
问题:上述问题理论上如果出现了应该如何解决?
答:一般情况,数据库都会处理一些事务并发的问题,数据库提供了不同的事务隔离级别来处理不同的事务并发问题,事务隔离级别定义如下
隔离级别 | 说明 |
---|---|
READ_UNCOMMITED | 允许你读取还未提交的改变了的数据。可能导致脏、幻、不可重复读(相当于没有做任何事务隔离) |
READ_COMMITTED | 允许在并发事务已经提交后读取。可防止脏读,但幻读和 不可重复读仍可发生(ORACLE默认级别) |
REPEATABLE_READ | 对相同字段的多次读取是一致的,除非数据被事务本身改变。可防止脏、不可重复读,但幻读仍可能发生。(MYSQL默认级别) |
SERIALIZABLE | 完全服从ACID的隔离级别,确保不发生脏、幻、不可重复读。这在所有的隔离级别中是最慢的,它是典型的通过完全锁定在事务中涉及的数据表来完成的。(ORACLE支持) |
针对不同隔离级别可以解决的的如下五类问题
解决数据丢失的两种方案:
1.悲观锁
(1) 在操作当前数据的事务开启事务就使用for update 锁住当前数据(会导致其他的事务对这个数据库的增删改进行阻塞,等锁释放了就会执行)
(2) Hibernate和MyBatis都有悲观锁对应的解决方案
2.乐观锁
(1) 为表添加一个version字段。当前事务操作的时候都会比对当前事务情况的多次操作的版本号是否一致,如果不一致认为数据已经被更新
(2) Hibernate和MyBatis都有乐观锁对应的解决方案
spring对事务的支持
\1. 为什么需要使用Spring是事务
答:使用Spring是事务代理(事务管理器),已经将事务的具体代码封装好,只需要在spring配置文件中配置一次,不用重复编写事务处理代码!!
Spring框架针对事务处理提供专门的解决方案
Spring的事务管理主要包括3个接口
Spring事务处理接口 | 描述 |
---|---|
TransactionDefinition | 封装事务的隔离级别超时时间,是否为只读事务和事务的隔离级别和传播规则等事务属性,可通过XML配置具体信息1,事务的隔离级别2,事务的超时时间管理3,事务的传播规则4,设置是否是只读事务(DQL是只读事务,DML是非只读事务) |
PlatformTransactionManager | 根据TransactionDefinition提供的事务属性配置信息,创建事务。事物管理器 |
TransactionStatus | 封装了事务的具体运行状态。比如,是否是新开启事务,是否已经提交事务,设置当前事务为rollback-only等 |
1.TransactionDefinition
该接口主要定义了:事务的传播行为(规则),事务的隔离级别,获得事务信息的方法。所以在配置事务的传播行为,事务的隔离级别已经需要获得事务信息时,可以通过查阅该类的代码获得相关信息。
public interface TransactionDefinition {
//事务的传播行为(规则)
int PROPAGATION_REQUIRED = 0;
int PROPAGATION_SUPPORTS = 1;
int PROPAGATION_MANDATORY = 2;
int PROPAGATION_REQUIRES_NEW = 3;
int PROPAGATION_NOT_SUPPORTED = 4;
int PROPAGATION_NEVER = 5;
int PROPAGATION_NESTED = 6;
//事务的隔离级别
int ISOLATION_DEFAULT = -1;
int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;
int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;
int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;
int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;
//事务超时管理
int TIMEOUT_DEFAULT = -1;
//获得事务信息
int getPropagationBehavior();
int getIsolationLevel();
int getTimeout();
boolean isReadOnly();
String getName();
}
事务传播规则
Spring在TransactionDefinition接口中定义了七种事务传播规则,规定了事务方法和事务方法发生嵌套调用时事务该如何进行传播
事务传播规则类型 | 描述 |
---|---|
PROPAGATION_REQUIRED | 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务(最常用操作)-Spring默认使用的就是此规则 |
PROPAGATION_REQUIRES_NEW | 创建一个新的事务,如果当前存在事务,则把当前事务挂起 |
PROPAGATION_SUPPORTS | 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行 |
PROPAGATION_NOT_SUPPORTED | 以非事务方式运行,如果当前存在事务,则把当前事务挂起 |
PROPAGATION_NEVER | 以非事务方式运行,如果当前存在事务,则抛出异常 |
PROPAGATION_MANDATORY | 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常 |
PROPAGATION_NESTED | 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED |
2.PlatformTransactionManager事务管理器
PlatformTransactionManager接口主要定义事务的处理方法,获取事务,开启事务,提交事务,回滚事务,在实际开发中不同的框架有不同的实现类
Spring的事务管理:
1,PlatformTransactionManager:接口统一抽象处理事务操作相关的方法;
1):TransactionStatus getTransaction(TransactionDefinition definition):
根据事务定义信息从事务环境中返回一个已存在的事务,或者创建一个新的事务,并用TransactionStatus描述该事务的状态。
ü 2):void commit(TransactionStatus status):
根据事务的状态提交事务,如果事务状态已经标识为rollback-only,该方法执行回滚事务的操作。
ü 3):void rollback(TransactionStatus status):
将事务回滚,当commit方法抛出异常时,rollback会被隐式调用
2,在使用spring管理事务的时候,首先得告诉spring使用哪一个事务管理器,使用不同的框架(JdbcTemplate,MyBatis,Hibernate/JPA )使用事务管理器都不同
继承体系
常用的事务管理器:
DataSourceTransactionManager:使用JDBC,MyBatis的事务管理器;
spring事务的配置
Spring支持编程式事务管理和声明式事务管理。
\1. 编程式事务管理:事务和业务代码耦合度太高。
2. 声明式事务管理:侵入性小,把事务从业务代码中抽离出来,使用AOP配置到配置文件中,提高维护性。
声明式事务-xml配置
引入tx命名空间
<!-- 事务处理:拷架包 -->
<!-- 事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--需要数据源 -->
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 事务通知(增强) -->
<!--
name:作用的方法,可以使用通配符*
isolation:配置事务的等级
read-only:配置是否只读,默认只读true
propagation:事务的传播规则
timeout:设置超时,-1默认
-->
<!-- 开启事务的注解配置 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
注解配置
@Configuration
@ComponentScan("cn.zj.spring")//扫描包
@PropertySource("classpath:db.properties")//加载db配置文件
@EnableTransactionManagement //开启支持事务的注解
public class SpringConfig {
@Value("${jdbc.driverClassName}")
private String driverClassName;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Value("${jdbc.maxActive}")
private int maxActive;
//配置数据库驱动
@Bean
public DataSource getDataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(this.driverClassName);
dataSource.setUrl(this.url);
dataSource.setUsername(this.username);
dataSource.setPassword(this.password);
dataSource.setMaxActive(this.maxActive);
return dataSource;
}
//配置jdbcTemplate,多例的
@Bean
@Scope("prototype")
public JdbcTemplate getJdbcTemplate() {
JdbcTemplate jdbcTemplate = new JdbcTemplate(getDataSource());
return jdbcTemplate;
}
//配置事务管理器
@Bean
public DataSourceTransactionManager getTransactionManager() {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(getDataSource());
return transactionManager;
}
}
标签:事务管理,事务,管理器,隔离,int,spring,PROPAGATION 来源: https://www.cnblogs.com/lgxdev/p/16113844.html