千家信息网

Spring事务

发表于:2026-10-31 作者:千家信息网编辑
千家信息网最后更新 2026年10月31日,spring事务基本配置参见:http://www.cnblogs.com/leiOOlei/p/3725911.htmlspring事务传播机制参见:http://www.cnblogs.com/a
千家信息网最后更新 2026年10月31日Spring事务

spring事务基本配置

参见:http://www.cnblogs.com/leiOOlei/p/3725911.html

spring事务传播机制

参见:http://www.cnblogs.com/aurawing/articles/1887030.html

简单说一下new和nested的区别。
使用new的时候,外层事务的提交或回滚,与new的事务没有关系。而使用nested时,内层事务最终是提交还是回滚,需要依赖于外层事务。参见下表。

事务传播配置外层事务(set a=1)内层事务(set b=2)最终结果
new提交提交a=1 && b=2
new提交回滚a=1
new回滚提交b=2
new回滚回滚什么都不变
nested提交提交a=1 && b=2
nested提交回滚a=1(这种情况需要增加一个配置:<property name="globalRollbackOnParticipationFailure" value="false" />)
nested回滚提交什么都不变
nested回滚回滚什么都不变

spring事务隔离机制

参见:Isolation Level(事务隔离等级):

  1. Serializable:最严格的级别,事务串行执行,资源消耗最大;
  2. REPEATABLE READ:保证了一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据。避免了"脏读取"和"不可重复读取"的情况,但是带来了更多的性能损失。
  3. READ COMMITTED:大多数主流数据库的默认事务等级,保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了"脏读取"。该级别适用于大多数系统。
  4. Read Uncommitted:保证了读取过程中不会读取到非法数据。隔离级别在于处理多事务的并发问题。

我们知道并行可以提高数据库的吞吐量和效率,但是并不是所有的并发事务都可以并发运行,这需要查看数据库教材的可串行化条件判断了。

这里就不阐述了。
我们首先说并发中可能发生的3中不讨人喜欢的事情

  1. Dirty reads--读脏数据。也就是说,比如事务A的未提交(还依然缓存)的数据被事务B读走,如果事务A失败回滚,会导致事务B所读取的的数据是错误的。
  2. non-repeatable reads--数据不可重复读。比如事务A中两处读取数据-total-的值。在第一读的时候,total是100,然后事务B就把total的数据改成200,事务A再读一次,结果就发现,total竟然就变成200了,造成事务A数据混乱。
  3. phantom reads--幻象读数据,这个和non-repeatable reads相似,也是同一个事务中多次读不一致的问题。但是non-repeatable reads的不一致是因为他所要取的数据集被改变了(比如total的数据),但是phantom reads所要读的数据的不一致却不是他所要读的数据集改变,而是他的条件数据集改变。比如Select account.id where account.name="ppgogo*",第一次读去了6个符合条件的id,第二次读取的时候,由于事务b把一个帐号的名字由"dd"改成"ppgogo1",结果取出来了7个数据。
--Dirty readsnon-repeatable readsphantom reads
Serializable不会不会不会
REPEATABLE READ不会不会会
READ COMMITTED不会会会
Read Uncommitted会会会
DEFALT(使用底层数据库的默认隔离级别)???

spring事务管理其他配置

readOnly

标记事务只读。只读事务会被优化;但是"只读"事务中其实可以写数据。

timeout

事务超时时间

rollbackFor/rollbackForClassName

标记哪些异常会引发回滚。默认情况下,所有RuntimeException都会引发回滚;所有其它异常(checked-exception)都不引发回滚。如果需要针对某种checked-exception进行回滚,则需要为事务配置rollbackFor或者rollbackForClassName

noRollbackFor/noRollbackForClassName

标记哪些异常不会引发回滚。默认情况下,所有RuntimeException都会引发回滚;所有其它异常(checked-exception)都不引发回滚。如果需要使得某种RuntimeException不进行回滚,则需要为事务配置noRollbackFor/noRollbackForClassName。

spring事务机制基本原理

aop

无论配置方式,还是注解方式,spring都是基于spring aop来进行事务管理。
即,在事务切入点处,生成一个动态代理。在代理中管理事务(开启、传播、提交或回滚等)。可参见下面两张图:

两张图都是调用isLocked()方法时的线程栈。可以看到,第二章图是通过动态代理来调用isLocked()方法的,而第一张图则不是。
动态代理的方式简化了代码的开发;但是也引入了一些小问题。后面会提。

线程上下文

spring会将事务相关的有状态数据(数据库连接、hibernate的session等)放在线程上下文中(ThreadLocal)。因此,事务间的传播关系、事务开启和关闭的时机,与线程中的方法调用栈很相似。
另外,由于事务与线程相关,因此目前spring的事务管理无法让多个子线程在同一事务内运行。

如何测试

首先来看看如何确定运行时是否使用了事务、事务是如何传播的。
首先在log4j中加入以下配置。严格说只要记录了org.springframework.transaction.support.AbstractPlatformTransactionManager的日志即可。另一个logger是为了记录SQL的,也可以将它替换成其它logger。

                                       

然后运行事务相关代码:

@Testpublic void test() {           // 这个方法使用默认的传播方式(REQUIRED)            this.lockServiceByDB.tryLock(LockName.EVENT_LOAN, "23424");            // 这个方法使用REQUIRES_NEW的传播方式            this.lockServiceByDB.isLocked(LockName.EVENT_LOAN, "23424");}

可以找到如下日志:

2016-07-06 18:01:10,969 DEBUG AbstractPlatformTransactionManager.getTransaction Creating new transaction with name[cn.youcredit.thread.bizaccount.service.impl.LockServiceByDBTestBySpring.test]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; '',-cn.youcredit.thread.common.exception.ServiceException
【中略】
2016-07-06 18:01:11,297 DEBUG AbstractPlatformTransactionManager.handleExistingTransaction Participating in existing transaction
2016-07-06 18:01:11,309 DEBUG SqlStatementLogger.logStatement
select count(1) as col_00 from dblocks dblock0 where dblock0.lockName=? and dblock0.uniKey=?
2016-07-06 18:01:11,325 DEBUG SqlStatementLogger.logStatement
insert into db_locks (lockName, lockTimeAsLong, uniKey) values (?, ?, ?)
【中略】
2016-07-06 18:01:11,331 DEBUG AbstractPlatformTransactionManager.handleExistingTransaction Suspending current transaction, creating new transaction with name [cn.youcredit.thread.bizaccount.service.impl.LockServiceByDB.isLocked]
【中略】
2016-07-06 18:01:11,335 DEBUG SqlStatementLogger.logStatement
select count(1) as col_00 from dblocks dblock0 where dblock0.lockName=? and dblock0.uniKey=?
2016-07-06 18:01:11,337 DEBUG AbstractPlatformTransactionManager.processCommit Initiating transaction commit
2016-07-06 18:01:11,337 DEBUG HibernateTransactionManager.doCommit Committing Hibernate transaction on Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=org.hibernate.engine.spi.ExecutableList@1a9ea4d9 updates=org.hibernate.engine.spi.ExecutableList@59ca0db6 deletions=org.hibernate.engine.spi.ExecutableList@33293dac orphanRemovals=org.hibernate.engine.spi.ExecutableList@384841e3 collectionCreations=org.hibernate.engine.spi.ExecutableList@571f925f collectionRemovals=org.hibernate.engine.spi.ExecutableList@5eb192b7 collectionUpdates=org.hibernate.engine.spi.ExecutableList@248f1090 collectionQueuedOps=org.hibernate.engine.spi.ExecutableList@5eb20abb unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])]
【中略】
2016-07-06 18:01:11,339 DEBUG AbstractPlatformTransactionManager.cleanupAfterCompletion Resuming suspended transaction after completion of inner transaction
2016-07-06 18:01:11,340 DEBUG AbstractPlatformTransactionManager.proce***ollback Initiating transaction rollback
2016-07-06 18:01:11,340 DEBUG HibernateTransactionManager.doRollback Rolling back Hibernate transaction on Session [SessionImpl(PersistenceContext[entityKeys=[EntityKey[cn.youcredit.thread.common.model.auth.UserInfo#system], EntityKey[cn.youcredit.thread.bizaccount.bean.DBLock#139], EntityKey[cn.youcredit.thread.common.model.auth.UserGroupInfo#500]],collectionKeys=[]];ActionQueue[insertions=org.hibernate.engine.spi.ExecutableList@2f90ad92 updates=org.hibernate.engine.spi.ExecutableList@4710332d deletions=org.hibernate.engine.spi.ExecutableList@7930de44 orphanRemovals=org.hibernate.engine.spi.ExecutableList@52891a77 collectionCreations=org.hibernate.engine.spi.ExecutableList@785fd189 collectionRemovals=org.hibernate.engine.spi.ExecutableList@3e900cf4 collectionUpdates=org.hibernate.engine.spi.ExecutableList@412d379c collectionQueuedOps=org.hibernate.engine.spi.ExecutableList@5b6dc76c unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])]

从日志中可以清楚的看到事务操作、传播的过程:

  1. 首先,运行LockServiceByDBTestBySpring.test()方法时,创建了一个新事务。这是SpringJUnit4Cla***unner的事务逻辑,即每一个单元测试都会启动一个事务,并且默认情况下,该事务会回滚。
  2. 然后,在执行到this.lockServiceByDB.tryLock()方法时,由于传播方式是REQUIRED,因此会加入当当前已有的事务中,并执行两条sql。
  3. 接着执行this.lockServiceByDB.isLocked()方法。由于这个方法的事务传播方式是REQUIRES_NEW,因此会挂起当前事务,并创建一个新的事务,在新的事务中执行一条SQL。
  4. 新事务执行并提交之后,恢复被挂起的上层事务。并继续执行。由于后面没有其它逻辑、代码,因此开始回滚外层事务。

常见问题

事务标记在protcted或private方法上,导致事务失效

spring的事务注解只对public方法生效,对protcted、friendly(默认)、private方法无效。如果在后面这些方法上标记事务注解,其效果等于没有标记。

注解继承不当,导致事务失效

Java注解的基本继承关系如下。spring的Transactional注解上有Inherited的元注解。

-未写@Inherited:写了@Inherited的
子类的类上能否继承到父类的类上的注解?否能
子类方法,实现了父类上的抽象方法,这个方法能否继承到注解?否否
子类方法,继承了父类上的方法,这个方法能否继承到注解?能能
子类方法,覆盖了父类上的方法,这个方法能否继承到注解?否否

例如下面的代码中,虽然Son在类级别上声明了事务,但是它的tryLocked()方法并不会启动新的事务。因为它在父类中没有声明事务。

public class Father{    public void tryLocked(){}}@Transactional(REQUIRES_NEW)public class Son extends Father{}

使用this方式调用,导致事务失效

对于spring aop的动态代理来说,被代理实例和方法是一个"黑盒"。只有在"黑盒"之外才能进行事务管理。而this调用是黑盒内部的调用逻辑,代理无法感知。
因此,像下文这样的代码中,isLocked()方法并不会启动新的事务。

@Transactional(REQUIRES_NEW)    public void isLocked(){        ……    }     @Transactional()    public void tryLock(){         this.isLocked();         ……    }

事务与查询

虽然查询操作并不更新数据,但是查询也需要事务。尤其对hibernate来说。

hibernate操作数据库时,需要获取到一个hibernate的session。而这个session也由HibernateTransactionManager来管理。管理的方式与其它有状态数据一样,都是放在ThreadLocal中。如果线程上没有事务管理器,那么就拿不到session。hibernate做查询时就会报错:

org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:134) ~[spring-orm-4.2.2.RELEASE.jar:4.2.2.RELEASE]

有时候明明没有写事务注解,也能执行查询,那么多半是在某个地方默认、或者"偷偷"开了事务。比如继承SpringTestCase的单元测试会默认开启事务。或者web环境下,线程池中的线程上遗留了以前绑定的事务管理器。

事务 数据 方法 注解 传播 方式 线程 管理 配置 代理 事务管理 数据库 标记 代码 情况 级别 查询 运行 动态 外层 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 小米移动互联网科技园 苏州找大状互联网科技有限公司 互联网科技工作委员会副主任毛军 云信互联网科技有限公司 工业互联网科技新基建 深圳互联网科技公司 互联网金融公司科技 互联网科技集团 互联网科技公司电话 云电互联网科技 国外互联网科技网站 互联网科技产品 宁波青枫互联网科技有限公司 湖南诚度互联网科技有限公司 徐州市互联网科技有限公司 广州互联网高科技取餐柜 艺电能源互联网科技有限公司招聘 张家口科技产业互联网平台 北京品多多互联网科技有限公司 互联网 科技节活动 微视频大赛 科技金融是不是互联网金融 疫情对互联网科技公司影响 科技与互联网发展 狮子座互联网科技 奇士达互联网科技 狮子座互联网科技培训 互联网科技公司做什么 四个字互联网科技公司取名 允成互联网科技有限公司融资 梅州GM互联网络科技有限公司
0