贵有恒,何必三更起、五更眠、最无益,只怕一日曝、十日寒。这篇文章主要讲述#聊一聊悟空编辑器#spring框架事务相关知识点Spring框架教程相关的知识,希望能为你提供帮助。
一、什么是事务
事务就是用户定义的一系列执行SQL语句的操作, 这些操作要么完全地执行,要么完全地都不执行, 它是一个不可分割的工作执行单元。
事务的使用场景:
在日常生活中,有时我们需要进行银行转账,这个银行转账操作背后就是需要执行多个SQL语句,假如这些SQL执行到一半突然停电了,那么就会导致这个功能只完成了一半,这种情况是不允许出现,要想解决这个问题就需要通过事务来完成。
事务是逻辑上的一组操作,要么都执行,要么都不执行。
我们系统的每个业务方法可能包括了多个原子性的数据库操作,比如下面的 savePerson() 方法中就有两个原子性的数据库操作。这些原子性的数据库操作是有依赖的,它们要么都执行,要不就都不执行。
public void savePerson()
personDao.save(person);
personDetailDao.save(personDetail);
另外,需要格外注意的是:事务能否生效数据库引擎是否支持事务是关键。比如常用的 mysql 数据库默认使用支持事务的?
?innodb?
??引擎。但是,如果把数据库引擎变为 ??myisam?
?,那么程序也就不再支持事务了!???spring相关视频教程在线观看????视频简介: 本套java视频教程主要讲解了Spring4在SSM框架中的使用及运用方式。本套Java视频教程内容涵盖了实际工作中可能用到的几乎所有知识点。为以后的学习打下坚实的基础。
二、事物的四大特性
- 原子性: 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;
- 一致性: 执行事务前后,数据保持一致;
- 隔离性: 并发访问数据库时,一个用户的事物不被其他事务所干扰也就是说多个事务并发执行时,一个事务的执行不应影响其他事务的执行;
- 持久性: 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
三、详谈 Spring 对事务的支持
再提醒一次:你的程序是否支持事务首先取决于数据库 ,比如使用 MySQL 的话,如果你选择的是 innodb 引擎,那么恭喜你,是可以支持事务的。但是,如果你的 MySQL 数据库使用的是 myisam 引擎的话,那不好意思,从根上就是不支持事务的。
这里再多提一下一个非常重要的知识点: MySQL 怎么保证原子性的?
我们知道如果想要保证事务的原子性,就需要在异常发生时,对已经执行的操作进行回滚,在 MySQL 中,恢复机制是通过 回滚日志(undo log) 实现的,所有事务进行的修改都会先先记录到这个回滚日志中,然后再执行相关的操作。如果执行过程中遇到异常的话,我们直接利用 回滚日志 中的信息将数据回滚到修改之前的样子即可!并且,回滚日志会先于数据持久化到磁盘上。这样就保证了即使遇到数据库突然宕机等情况,当用户再次启动数据库的时候,数据库还能够通过查询回滚日志来回滚将之前未完成的事务。
1. Spring 支持两种方式的事务管理 1)编程式事务管理通过 TransactionTemplate或者TransactionManager手动管理事务,实际应用中很少使用,但是对于你理解 Spring 事务管理原理有帮助。
使用TransactionTemplate 进行编程式事务管理的示例代码如下:
@Autowired
private TransactionTemplate transactionTemplate;
public void testTransaction()
transactionTemplate.execute(new TransactionCallbackWithoutResult()
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus)
try
// ....业务代码
catch (Exception e)
//回滚
transactionStatus.setRollbackOnly();
);
使用 ?
?TransactionManager?
?
进行编程式事务管理的示例代码如下:@Autowired
private PlatformTransactionManager transactionManager;
public void testTransaction()
TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
try
// ....业务代码
transactionManager.commit(status);
catch (Exception e)
transactionManager.rollback(status);
2)声明式事务管理
推荐使用(代码侵入性最小),实际是通过 AOP 实现(基于?
?@Transactional?
?
的全注解方式使用最多)。使用 ?
?@Transactional?
?注解进行事务管理的示例代码如下:@Transactional(propagation=propagation.PROPAGATION_REQUIRED)
public void aMethod
//do something
B b = new B();
C c = new C();
b.bMethod();
c.cMethod();
2. Spring 事务管理接口介绍Spring 框架中,事务管理相关最重要的 3 个接口如下:
- PlatformTransactionManager: (平台)事务管理器,Spring 事务策略的核心。
- TransactionDefinition: 事务定义信息(事务隔离级别、传播行为、超时、只读、回滚规则)。
- TransactionStatus: 事务运行状态。
PlatformTransactionManager 会根据 TransactionDefinition 的定义比如事务超时时间、隔离界别、传播行为等来进行事务管理 ,而 TransactionStatus 接口则提供了一些方法来获取事务相应的状态比如是否新事务、是否可以回滚等等。
1)PlatformTransactionManager:事务管理接口Spring 并不直接管理事务,而是提供了多种事务管理器 。Spring 事务管理器的接口是: PlatformTransactionManager 。
通过这个接口,Spring 为各个平台如 JDBC(DataSourceTransactionManager)、Hibernate(HibernateTransactionManager)、JPA(JpaTransactionManager)等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。
PlatformTransactionManager 接口的具体实现如下:
【#聊一聊悟空编辑器#spring框架事务相关知识点Spring框架教程】 ?
?PlatformTransactionManager?
?接口中定义了三个方法:package org.springframework.transaction;
import org.springframework.lang.Nullable;
public interface PlatformTransactionManager
//获得事务
TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;
//提交事务
void commit(TransactionStatus var1) throws TransactionException;
//回滚事务
void rollback(TransactionStatus var1) throws TransactionException;
2)TransactionDefinition:事务属性事务管理器接口 PlatformTransactionManager 通过 getTransaction(TransactionDefinition definition) 方法来得到一个事务,这个方法里面的参数是 TransactionDefinition 类 ,这个类就定义了一些基本的事务属性。
事务属性可以理解成事务的一些基本配置,描述了事务策略如何应用到方法上。
事务属性包含了 5 个方面:
- 传播特性
- 隔离级别
- 回滚规则
- 事务超时
- 是否只读
?TransactionDefinition?
?
接口中定义了 5 个方法以及一些表示事务属性的常量比如隔离级别、传播行为等等。package org.springframework.transaction;
import org.springframework.lang.Nullable;
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 = 1;
int ISOLATION_READ_COMMITTED = 2;
int ISOLATION_REPEATABLE_READ = 4;
int ISOLATION_SERIALIZABLE = 8;
int TIMEOUT_DEFAULT = -1;
// 返回事务的传播行为,默认值为 REQUIRED。
int getPropagationBehavior();
//返回事务的隔离级别,默认值是 DEFAULT
int getIsolationLevel();
// 返回事务的超时时间,默认值为-1。如果超过该时间限制但事务还没有完成,则自动回滚事务。
int getTimeout();
// 返回是否为只读事务,默认值为 false
boolean isReadOnly();
@Nullable
String getName();
3)TransactionStatus:事务状态TransactionStatus接口用来记录事务的状态 该接口定义了一组方法,用来获取或判断事务的相应状态信息。
PlatformTransactionManager.getTransaction(…)方法返回一个 TransactionStatus 对象。
TransactionStatus 接口接口内容如下:
public interface TransactionStatus
boolean isNewTransaction(); // 是否是新的事物
boolean hasSavepoint(); // 是否有恢复点
void setRollbackOnly(); // 设置为只回滚
boolean isRollbackOnly(); // 是否为只回滚
boolean isCompleted; // 是否已完成
3. 事务属性详解 1)传播特性 PROPAGATION :新的事务应该被启动还是挂起?方法是否要在事务的环境中运行?
- PROPAGATION_MANDATORY 方法必须在事务中运行,如果没有事务就要抛出错误 MANDATORY 是强制的意思
- PROPAGATION_NESTED 嵌套,外层有事务的情况下 如果内层要打开事务就打开事务嵌套运行,如果内层没有事务就加入到上层事务中去,嵌套事务是可以独立提交和回滚的 (对于jdbc Spring其实在内层没有开启新事务,只是在内层方法前设置了savepoint)
- PROPAGATION_NEVER 表示这个方法不能运行在事务中,如果上下文有事务 就要抛出异常
- PROPAGATION_NOT_SUPPORTED 表示当前方法运行的时候 如果有上下文事务,那么上下文事务会被挂起 等该方法执行结束,上下文事务恢复
- PROPAGATION_REQUIRED 表示当前方法必须运行在事务中,如果上下文有事务就加入上下文事务; 上下文没有事务,就启动一个新事务
- PROPAGATION_REQUIRES_NEW 当前方法一定会启动自己的事务,如果有上下文事务,上下文事务会被挂起的 (对于jdbc Spring在内层开启新事务(创建了新的Connection 内层事务是独立的开启 提交 回滚的)
- PROPAGATION_SUPPORTS 表示当前方法不需要上下文事务,但是如果有上下文事务的话 还是可以在上下文事务里运行的
3个问题:
脏读:事务A在执行过程中 读取到了事务B修改过但是尚未提交的数据
不可重复读: 事务A读取了两次,两次结果不同, 原因是中途事务B修改了数据并且提交了
幻读: 事务A读取了3行数据 过了一会再读取读出来4条数据, 原因是事务B中途insert了一条数据; 多出来的这一条数据叫做幻 影数据
- ISOLATION_DEFAULT 数据库默认隔离级别 mysql的话 就是read_committed
- ISOLATION_READ_UNCOMMITTED 读未提交 会导致脏读, 但是也是效率最高的一种级别
- iosLATION_READ_COMMITTED 读已提交,最常用的的级别,可以防止脏读
- ISOLATION_REPEATABLE_READ 可重复读, 能防止脏读和重复读, 但是防不了幻读
- ISOLATION_SERIALIZABLE 最高级别,可防幻读
private boolean readOnly = false;
public final void setReadOnly(boolean readOnly)
this.readOnly = readOnly;
public final boolean isReadOnly()
return this.readOnly;
4)事务超时 timeOut
private int timeout = TIMEOUT_DEFAULT;
public final void setTimeout(int timeout)
if (timeout < TIMEOUT_DEFAULT)
throw new IllegalArgumentException("Timeout must be a positive integer or TIMEOUT_DEFAULT");
this.timeout = timeout;
public final int getTimeout()
return this.timeout;
5)回滚规则
private List< RollbackRuleAttribute> rollbackRules;
public void setRollbackRules(List< RollbackRuleAttribute> rollbackRules)
this.rollbackRules = rollbackRules;
public List< RollbackRuleAttribute> getRollbackRules()
if (this.rollbackRules == null)
this.rollbackRules = new LinkedList< RollbackRuleAttribute> ();
return this.rollbackRules;
// 判断当前抛出的异常是否要回滚
public boolean rollbackOn(Throwable ex)
RollbackRuleAttribute winner = null;
int deepest = Integer.MAX_VALUE;
if (this.rollbackRules != null)
for (RollbackRuleAttribute rule : this.rollbackRules)
int depth = rule.getDepth(ex);
if (depth > = 0 & & depth < deepest)
deepest = depth;
winner = rule;
if (logger.isTraceEnabled())
logger.trace("Winning rollback rule is: " + winner);
// User superclass behavior (rollback on unchecked) if no rule matches.
if (winner == null)
logger.trace("No relevant rollback rule found: applying default rules");
return super.rollbackOn(ex);
return !(winner instanceof NoRollbackRuleAttribute); //判断winner是否是不回滚的异常类型
4. @Transactional 注解使用详解1) @Transactional 的作用范围 方法 :推荐将注解使用于方法上,不过需要注意的是:该注解只能应用到 public 方法上,否则不生效。
类 :如果这个注解使用在类上的话,表明该注解对该类中所有的 public 方法都生效。
接口 :不推荐在接口上使用。
2) @Transactional 的常用配置参数@Transactional注解源码如下,里面包含了基本事务属性的配置:
@Target(ElementType.TYPE, ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional
@AliasFor("transactionManager")
String value() default "";
@AliasFor("value")
String transactionManager() default "";
Propagation propagation() default Propagation.REQUIRED;
Isolation isolation() default Isolation.DEFAULT;
int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
boolean readOnly() default false;
Class< ? extends Throwable> [] rollbackFor() default ;
String[] rollbackForClassName() default ;
Class< ? extends Throwable> [] noRollbackFor() default ;
String[] noRollbackForClassName() default ;
?
?@Transactional?
?
的常用配置参数总结(只列巨额 5 个我平时比较常用的):3)@Transactional 事务注解原理面试中在问 AOP 的时候可能会被问到的一个问题。简单说下吧!
我们知道,@Transactional 的工作机制是基于 AOP 实现的,AOP 又是使用动态代理实现的。如果目标对象实现了接口,默认情况下会采用 JDK 的动态代理,如果目标对象没有实现了接口,会使用 CGLIB 动态代理。
4)Spring AOP 自调用问题若同一类中的其他没有 @Transactional 注解的方法内部调用有 @Transactional 注解的方法,有@Transactional 注解的方法的事务会失效。
这是由于Spring AOP代理的原因造成的,因为只有当 @Transactional 注解的方法在类以外被调用的时候,Spring 事务管理才生效。
MyService 类中的method1()调用method2()就会导致method2()的事务失效。
@Service
public class MyService
private void method1()
method2();
//......
@Transactional
public void method2()
//......
解决办法就是避免同一类中自调用或者使用 AspectJ 取代 Spring AOP 代理。
5) @Transactional 的使用注意事项总结
- @Transactional 注解只有作用到 public 方法上事务才生效,不推荐在接口上使用;
- 避免同一个类中调用 @Transactional 注解的方法,这样会导致事务失效;
- 正确的设置 @Transactional 的 rollbackFor 和 propagation 属性,否则事务可能会回滚失败
推荐阅读
- Renix修改报文长度——网络测试仪实操
- #yyds干货盘点#Python爬虫实战,pyecharts模块,Python实现中国地铁数据可视化
- 我以订披萨为例,给女朋友详细讲了Java设计模式的3种工厂模式
- Spock框架Mock对象方法经验总结#yyds干货盘点#
- 逼真,特别逼真的决策树可视化
- Linux之diff命令
- SQLServer2014故障转移群集的部署
- 数据湖是谁(那数据仓库又算什么?)
- #过年不停更#Axios踩坑日记