Spring事务 作者:哇塞大嘴好帅(我爱大嘴网)
我爱大嘴好帅(我爱大嘴网)
我爱大嘴好帥(我愛大嘴網)
1.事务的特性(ACID)
1.原子性(Atomicity)
2.一致性(Consistency)
3.隔离性(isolation)
4.持久性(Durability)
1.原子性(Atomicity)
比如张三给李四5块钱,然后李四给赵四3块钱。原子性就是这些步骤要不都执行要不都别执行,如果某一步出现问题就回滚撤销。
2.一致性(Consistency)
数据保证在业务上是正确的
3.隔离性(isolation)
两个事务的执行要互不影响,互不干扰,
4.持久性(Durability)
一旦提交事务成功,数据会到数据库持久化保存,也就是拥有保存。
Spring事务管理机制
Spring事务时在数据库事务的基础上进行封装扩展的,主要特性如下
1.支持原有的数据库事务的隔离级别,加入了事务传播的概念
2.提供国歌事务的合并或隔离的功能
3.提供声明式事务,让业务代码与事务分离,事务变得更加易用(AOP)
Spring提供了事务相关的接口
Spring事务管理高层抽象主要包含3个接口,Spring的事务主要通过他们三个共同完成
TransactionDefinition
事务定义: 事务定义信息(隔离、传播、只读、超时)
PlatformTransactionManager
事务管理器,主要用于平台相关事务的管理、
TransactionStatus
获取事务的运行状态
1.1PlatformTransactionManager 事务管理器介绍
参考文档:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/transaction/PlatformTransactionManager.html
commit方法提交事务
getTransaction获取事务状态 里面的TransactionDefinition是事务的定义 ,通过事务的定义信息去获取状态
rollback回滚
Spring为不同的持久层框架提供了不同的PlaformTransactionManaeg的接口实现
事务 | 说明 |
---|---|
org.springframework.jdbc.datasource.DataSourceTransactionManager | 使用Spring JDBC或iBatis进行持久化数据时使用 |
org.springframework.orm.hibernate5.HibernateTransactionManager | 使用Hibernate5.0半斤星星持久化数据时使用 |
org.springframework.orm.jpa.JpaTransactionManager | 使用JPA进行持久化时使用 |
org.springframework.jdo.JdoTransactionManager | 当持久化机制是Jdo时使用 |
org.springframework.trasanction.jta.JtaTransactionManager | 使用一个JTA实现来管理事务,在一个事务跨越多个资源必须使用. |
DatasourceTransactionManager针对JdbcTemplate、Mybatis事务控制,使用Connection(连接)进行事务管理
开启事务connection.setAutoCommit(false),只有这个为false时候才能进行提交事务connection.commit() 、回滚事务connection.rollback();
1.2 TransactionDefinition 事务定义信息
参考文档:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/transaction/TransactionDefinition.html
**getIsolationLevel ** 获取隔离级别
getName 获取当前事务的昵称
getPropagationBehavior 获取事务传播行为
getTimeout 获取超时时间,默认值是-1.-1就是不超时
isReadOnly 判断事务是否只读
常用的事务隔离级别
Isolation Leavel | meaning |
---|---|
DEFAULT | 使用后端数据库默认的隔离别(Spring中的选择项) |
READ_UNCOMMITED | 允许你读取还未提交的未改变的数据。可能导致脏读、幻读、不可重复读 |
READ_COMMITTED | 允许在并发事务已经提交后读取。可防止脏读,但幻读和不重复读依然可以发生 |
REPEATABLE_READ | 对相同子弹的多次读取是一致的,除非数据被事务本身改变。可防止脏、不可重复读,但幻读依然可能发生. |
SERIALIZABLE | 100%服从ACID的隔离级别,确保不发生脏读、幻读、不可重复读。这在所有的隔离级别中是最慢的,他是典型的通过完全锁定在事务张设计的数据表来完成的。 |
DEFAULT是基于你选择的数据库,来选择你数据库的默认隔离级别
如:Mysql默认隔离级别为REPEATABLE_READ
Oracle默认隔离级别 READ_COMMITTED
propagation behavior事务传播行为
7种事务传播级别
事务传播行为类型 | 说明 |
---|---|
PROPAGATION_REQUIRED | 支持当前事务,如果不存在就创建一个 |
PROPAGATION_SUPPORTS | 支持当前事务,如果不存在,就不使用事务 |
PROPAGATION_MANDATORY | 支持当前事务,如果不存在,抛出异常 |
PROPAGATION_REQUIRES_NEW | 如果有事务存在,挂起当前事务,创建一个新的事务 |
PROPAGATION_NOT_SUPPORTED | 以非事务方式运行,如果有事务存在,挂起当前事务 |
PROPAGATION_NEVER | 以非事务方法运行,如果有事务存在,抛出异常 |
PROPAGATION_NESTED | 如果当前事务存在,则嵌套事务执行,只针对DataSourceTransactionManager |
主要分为三大类:
PROPAGATION_REQUIRED(default) ,PROPAGATION_SUPPORTS ,PROPAGATION_MANDATORY
支持当前事务,A调用B,如果A事务还存在,那么A and B就处于同一个事务,事务默认的传播级别为REQUIRED
PROPAGATION_REQUIRES_NEW,PROPAGATION_NOT_SUPPORTED,PROPAGATION_NEVER
不会支持原来的事务,如A调用B,如果A事务存在,B肯定不会和A处于一个事务。
常用的事务传播行为:REQUIRES_NEW
PROPAGATION_NESTED 不常用
嵌套事务,只对DatasourcetransactionManager有效,底层使用JDBC的SavePoint机制,允许在同一个事务设置保存点,回滚保存点
常用的事务传播行为:NESTED
REQUIRED NESTED REQUIRES_NEW的区分
required 只有一个事务(默认,推荐)
requires_new 存在两个事务,如果事务存在,挂起事务,重新又开启一个新的事务
nested 嵌套事务,事务可以设置保存点,回滚到保存点,选择提交or回滚
2.Spring事务管理
2.1编程式事务
编程式事务就是通过纯代码控制事务,手动提交手动回滚
2.1.1 xml配置
<!--事务管理器-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--事务管理的模板-->
<bean id="transactionTemplate" class="org.springframework.transaction,support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"></property>
</bean>
2.1.2 注解配置
@ComponentScan("com.dazuizui")
public class TransactionConfig{
/**
* 事务管理器
*/
@Bean
public TransactionTemple transactionTemplate(DataSourceTransactionManager dataSourceTransactionManager){
TransactionTemplate transactionTemplate = new TransactionTemplate();
transactionTemplate.setTransactionManager(transactionTemplate);
return transactionTemplate;
}
@Bean
public DataSourceTransactionManager transactionManager(DataSource dataSource){
DataSourceTransactionManager dm = new DataSourceTransactionManager();
dm.setDataSource(dataSource);
return dm;
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource){
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDtaSource(dataSource);
return jdbcTemplate;
}
@Bean
public DtaSource dataSource(){
BasicDataSource ds = new BasicDataSource();
ds.seturl("url");
ds.setDriverClassName("com.mysql.jdbc.Driver")
ds.setUsername("username");
ds.setPassowrd("password");
return ds;
}
}
2.1.3 实现
/**
* 通过xml配置使用
*/
@Test
public void test1(){
ApplicationContext ca = new CLassPathXmlApplicationContext("applicationContext.xml");
UserSerivce userBean = ca.getBean(UserSerivce.class);
bean.test1();//执行数据库操作
}
/**
* 执行注解配置文件模式
*/
public void test2(){
AnnotationConfigApplicationContext ac= new AnnotationConfigApplicationContext(TransactionConfig.class);
UserSerivce userBean = ca.getBean(UserSerivce.class);
bean.test1();//执行数据库操作
}
将调用数据库事务通过Lambda表达式写在transactiontemplate.execute()方法内进行事务事务管理
@Autowired
private TransactionTemplate transactiontemplate //事务管理器
public void test1(){
transactiontemplate.execute(status - > {
userMapper.zhuanqian(); //调用数据库小张转钱给小明
int x = 10086;
if(x==10086)
throw new RuntimeException("error");
userDao.income(); //小明收入小张转的钱
return null;
});
}
2.2 申明式事务
2.2.1基于AspectJ xml的配置方式
使用该申明式定要删除配置文件中的事务管理模板中的配置。
也就是这个
<!--事务管理器-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
添加一个事务定义的配置和AOP的配置
<!--事务管理器-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--增强事务的属性配置-->
<td:attributes>
<!--
isolation: default,事务隔离级别
propagation: 事务传播行为
read-onlu: fase,是否只读
timeout: -1, 超时-1为默认值
no-rollback-for: 发生那些异常不回滚
rollback-for: 发生哪些异常滚事务
-->
<tx:method name="方法名" isolation="DEFAULT" propagation="REQUIRED">
<!--save开头的方法全部增强-->
<tx:method name="save*" isolation="DEFAULT" propagation="REQUIRED">
</tx:method>
</td:attributes>
</tx:advice>
<!--aop配置定义切面和切点信息-->
<aop:config>
<!--定义切点:那些类的方法应用加强-->
<aop:pointct expression="excution(* com.dazuizui.beans.service..*.*(..))"
id="mypointct"/>
<!--定义切面-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="mypointcut"></aop:advisor>
</aop:config>
说一下Spring事务的配置:
第一种方法基于XML的配置方法,需要配置事务管理器,然后在配置事务的增强
事务定义主要配置,事务隔离级别、事务传播行为、是否只读、超时时间、发生那些异常不回滚、发生哪些异常滚事务
再通过aop:config设置切面和切入点
2.2.2 注解方法声明式事务
@ComponentScan("com.dazuizui")
@EnableTransactionManagement //开启注解事务
public class TransactionConfig{
@Bean
public DataSourceTransactionManager transactionManager(DataSource dataSource){
DataSourceTransactionManager dm = new DataSourceTransactionManager();
dm.setDataSource(dataSource);
return dm;
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource){
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDtaSource(dataSource);
return jdbcTemplate;
}
@Bean
public DtaSource dataSource(){
BasicDataSource ds = new BasicDataSource();
ds.seturl("url");
ds.setDriverClassName("com.mysql.jdbc.Driver")
ds.setUsername("username");
ds.setPassowrd("password");
return ds;
}
}
如果你想使用事务那么就在Service类的上面加入**@Transactional**就是当前类下所有方法都进行事务管理,如果在方法上使用,那么就这个方法受到事务管理。
说一下Spring事务的配置:
基于注解的,在类上或者方法上添加**@Transactional**
3.Spring 传播特性
3.1 什么是传播特性? What is propagation charecteristics?
当一个事务方法被另一个事务方法调用时(方法A调用方法B),这个事务方法应该如何进行。
for example:
@Service
public class test1{
@Transactional
public void function1(){
System.out.println("funcion 1 method");
function2();
}
@Transactional
public void function2(){
System.out.println("function 2 medhod");
}
}
3.2 Spring的7中传播特性 7 kinds of propagation chanrecteristics of Spring
传播行为(propagation) | 描述(discribe) |
---|---|
PROPAGATION_REQUIRED | 默认事务类型,如果没有就新建一个事务;如果有就加入当前事务。 |
PROPAGATION_SUPPORTS | 如果没有事务就非事物执行,如果有事务就使用当前事务 |
PROPAGATION_MANDATORY | 如果没有事务就抛出异常,如果有就使用当前事务 |
PROPAGATION_REQUIRES_NEW | 如果没有事务就非事务执行,所有有就将事务挂起 |
PROPAGATION_NOT_SUPPORTED | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
PROPAGATION_NEVER | 如果有事务就抛出异常,如果没有就非事务执行 |
PROPAGATION_NESTED | 如果没有事务就创建一个事务;如果有就在当前事务种嵌套其他事务 |
3.2.1详细解说7种传播特性
使用注解设置传播特性例如
@Transaction(propagation=Propagation.SUPPORTS)
@Transaction(propagation=Propagation.NEVER)
3.2.1.1 PROPAGATION_NEVER
如果function1 或者 function2存在事务那么直接抛出异常
for example
@Service
public class test1{
@Transactional
public void function1(){
System.out.println("funcion 1 method");
function2();
}
@Transactional
public void function2(){
System.out.println("function 2 medhod");
}
}
这样会报错
@Service
public class test1{
public void function1(){
System.out.println("funcion 1 method");
function2();
}
public void function2(){
System.out.println("function 2 medhod");
}
}
这样就不会报错
3.2.1.2 PROPAGATION_NOT_SUPPORTED
如果被调用方法发现调用它的方法存在事务那么就将事务挂起(我把你放一边,我做我的事情),
for example
@Service
public class test1{
@Transactional
public void function1(){
System.out.println("funcion 1 method");
function2();
}
public void function2(){
System.out.println("function 2 medhod");
}
}
可以说PROPAGATION_NOT_SUPPORTED and PROPAGATION_NEVER 是死都不要事务
3.2.1.3 PROPAGATION_SUPPORTED
你有事务我就用事务执行,你没有事务我就不按事务执行。
可以说propagation_not_supported是可有可无事务
3.2.1.4 propagation_requires_new
不管有没有事务都必须创建一个事务,如果有事务,就将原来的事务挂起。我创建一个新的
for example
@Service
public class test1{
@Transactional
public void function1(){
System.out.println("funcion 1 method");
function2();
}
@Transactional
public void function2(){
System.out.println("function 2 medhod");
}
}
function2不管function1是否存在事务,我function2都必须创建一个事务,当我的事务走完了再去走function1的事务
可以实现子影响父,但父不影响子的效果
3.2.1.5 propagation_nested
for example
@Service
public class test1{
@Transactional
public void function1(){
System.out.println("funcion 1 method");
function2();
}
@Transactional
public void function2(){
System.out.println("function 2 medhod");
}
}
如果function2出现了异常那么function1也跟着回滚
3.2.1.6 propagation_required (默认)
如果没有事务我就创建一个事务,如果有事务那么我就用你的事务
3.2.1.7 propagation_mandatory
如果没有事务我就报错,如果有事务我就用你的
propagation_mandatory 和 propagation_required 和propagation_nested 和 propagation_requires_new 必须有一个事务