[原理][来源解析]spring于@Transactional,Propagation.SUPPORTS,以及 Hibernate Session,以及jdbc Connection关联

Spring 捆绑Hibernate.

夹:

一、 

1. Spring 怎样处理propagation=Propagation.SUPPORTS?

2. Spring 何时生成HibernateSession ?

3.  propagation=Propagation.SUPPORTS和propagation=Propagation.require对生成Session有何影响,共同点和差别 ?

3.1. 未配置@Transaction和 配置@Transaction(propagation=Propagation.SUPPORTS)对生成Session有何影响,共同点和差别?

4. Spring 何时从线程池中获取到jdbcconnection 设置setAutoCommit(false)?

二、 两种无Session情况下获取Session情况,一种抛错,一种正常

三、 那么何时能够获取一个non-transactional Session?


问题:

一.

1. Spring 怎样处理propagation=Propagation.SUPPORTS?

2. Spring 何时生成HibernateSession ?

3. propagation=Propagation.SUPPORTS 和propagation=Propagation.require对生成Session有何影响 ?

共同点:都会进入aspect切面处理, 试图新建Session,开启Transaction ,都能获得.TransactionStatus

差别: 前者成功开启事务,后者未开启,但会设置一个同意懒惰载入Session的配置.详情见以下代码.

3.1. 未配置@Transaction 和 配置@Transaction(propagation=Propagation.SUPPORTS)的差别?

共同点: 都没有起事务.

不同点: 前者不会进入aspect切面处理, 后者进入试图新建Session,开启事务但未成功,会设置一个同意懒惰载入Session的配置. 详情见以下代码

4. Spring 何时从线程池中获取到 jdbcconnection 设置 setAutoCommit(false)?


  正文解析:

spring是在TransactionAspectSupport(切面编程)的createTransactionIfNecessary方法中完毕对@Transactional注解的处理. 然后托付给PlatformTransactionManager实现类的getTransaction()方法( 实现

类是HibernateTransactionManager被我们配置在application.xml中)对propagation=Propagation.SUPPORTS的处理也是在这种方法内实现,详细是其父类AbstractPlatformTransactionManager.getTransaction()中.

代码片段例如以下:

AbstractPlatformTransactionManager.getTransaction(TransactionDefinitiondefinition){

Object transaction = doGetTransaction(); //注1: springframework的HibernateTransactionObject 实例,内部持有的是 HibernateSession ,一開始是Null;

. . otherCode . .

// No existing transaction found -> check propagationbehavior to find out how to proceed.

if (definition.getPropagationBehavior()== TransactionDefinition.PROPAGATION_MANDATORY) {

throw new IllegalTransactionStateException(

"No existing transaction found for transactionmarked with propagation ‘mandatory‘");

}

else if (definition.getPropagationBehavior()== TransactionDefinition.PROPAGATION_REQUIRED ||

definition.getPropagationBehavior() ==TransactionDefinition.PROPAGATION_REQUIRES_NEW ||

definition.getPropagationBehavior() ==TransactionDefinition.PROPAGATION_NESTED) {

SuspendedResourcesHolder suspendedResources = suspend(null);

if (debugEnabled) {

logger.debug("Creating new transaction withname [" + definition.getName() + "]:" + definition);

}

try {

boolean newSynchronization =(getTransactionSynchronization() != SYNCHRONIZATION_NEVER);

DefaultTransactionStatus status = newTransactionStatus(

definition, transaction, true,newSynchronization, debugEnabled, suspendedResources);

doBegin(transaction, definition); // 注2: 生成 HibernateSession ,然后获取jdbcconnection , 而且Connection,setAutoCommit(false),开启我们理解上的sql事务.详细是调用Session持有的HibernateJDBCTransaction中的.begin()方法中,

prepareSynchronization(status,definition);  //设置SpringTransactionSynchronizationManager.initSynchronization().

return status;

}

catch (RuntimeException ex) {

resume(null, suspendedResources);

throw ex;

}

catch (Error err) {

resume(null, suspendedResources);

throw err;

}

}

else {

// 注3  这个流程就是当”线程中无事务,且配置是propagation= Propagation.SUPPORTS”时运行的路径.这一步未生成Hibernate Session, jdbc Connection.但 prepareTransactionStatus()中做了一步操作,设置SpringTransactionSynchronizationManager.initSynchronization().正是这个操作在之后,我们 才干在后来Hibernate
save or update时,同意Hibernate 回调初始化时注冊的 Spring SpringSessionContext 生成 HibernateSession ,进一步从连接池获取 jdbcConnection

// Create "empty" transaction: no actualtransaction, but potentially synchronization.

boolean newSynchronization = (getTransactionSynchronization()== SYNCHRONIZATION_ALWAYS);

return prepareTransactionStatus(definition, nulltrue,newSynchronization, debugEnabled, null);

}

. . .

}

   注2和注3解答了2,3问题.

对以上代码中命名的一点看法:

l       getTransaction返回TransactioStaus, 感觉用 getTransactioStaus比 spring眼下的命名getTransaction更合适 或者取名 getTransactionIfNecessary比較好的,依据注3可知,此分支并没有真正的开启数据库事务.更没有获取jdbc Connection.和不论什么生成 Hibernate Session.

l   比較重要的几个类Springframework的HibernateTransactionObject,Hibernate的Session,Hibernate的JDBCTransaction,jdbc的Connection. Springframework HibernateTransactionObject持有一个 Hibernate Session, Hibernate Session持有一个Hibernate JDBCTransaction , 终于持有 jdbc Connection.

由于 数据库事务Connection.setAutoCommit(false).事务开启是附属于Connection. Connection应该是先于事务开启. 所以感觉用Springframework HibernateTransactionObject 和Hibernate JDBCTransaction 持有 jdbc Connection不同合理.

取名为 Springframework  HibernateTransactionStatusObject ,  Hibernate  JDBCTransactionStaus更合理.

对于第4个问题.

对于@Transaction(propagation=Propagation.REQUIRE)时
Session新建和Session获取都是在AbstractPlatformTransactionManager.getTransaction方法中完毕的

对于@Transaction(propagation=Propagation.SUPPORTS) , 当懒惰获取完Session后,当且仅当真正尝试数据库操作时才会懒惰获取Connection.

获取Connection的简单堆栈例如以下.

ConnectionManager.openConnection()line: 446   //注:发现没有连接,从线程池获取一个连接

ConnectionManager.getConnection()line: 167

BatchingBatcher(AbstractBatcher).prepareQueryStatement(String,boolean, ScrollMode) line: 161

EntityLoader(Loader).prepareQueryStatement(QueryParameters,boolean, SessionImplementor) line: 1700


问题:

二. 对于上面第3个小问题的延伸,注3表明此处并没有生成Session. 然后get or save 正常不报错. 我们定义为A情况.

    A.当处于propagation=Propagation.SUPPORTS时,未生成Session和获取到jdbc Connection.当我们 save or get 时候正常不报错.

以下看下无Session情况下获取Session的第二种情况:

    B.我们可能遇到过这种错误:No Hibernate Session bound to thread,and configuration does not allow creationof non-transactional one here.错误原因是我们save
or get的时候获取不到Session,不正常抛错

     A和B都是在无Session情况下获取Session, 为什么一个正常,一个不正常?


正文解析:

详细代码片段例如以下:

        SpringSessionFactoryUtils.doGetSession(SessionFactory sessionFactory,InterceptorentityInterceptor,SQLExceptionTranslator jdbcExceptionTranslator,booleanallowCreate){

                    if (TransactionSynchronizationManager.isSynchronizationActive()){  // 注4:A情况下返回是true,原因见注3,B情况下返回是false.

// 注: 此部分代码实现了”假设眼下没有Session那么就生成Session”的逻辑

}

                   if ((!(allowCreate)) && (!(isSessionTransactional(session,sessionFactory)))) { // 注5: 两个开关推断. allowCreate 对于HibernateManager是强制设置为false(关闭)的,后者正是前面HibernateManager处理@Transaction时开启(返回true).
 有一个同意就正常运行返回了Session. 两个有一个开启(ture)就不抛错,正常运行返回Session.

何时allowCreateture?

见以下 三. 那么何时能够获取非事务类型的Session? .

closeSession(session);

throw new IllegalStateException("No Hibernate Session bound to thread, andconfiguration
does not allow creation of non-transactional one here");

}

return session;     //注6, 假设没有被注5禁止,那么就返回生成的Session

}

注4,注5解答了上述问题.

所以出现B问题, 检查下自己的代码,是否处于事务环境中. 因为getTransaction()会把Session绑定到ThreadLocal中,假设新建了独立线程, 注意内部调用的代码是否加上@Transaction,不然该线程中是无法获取到Threadlocal的Session变量.

对于这个Exception.后半部分”configuration does notallow creation of non-transactional one here”的详细语义.是指”configuration不同意生成一个非事务类型的Session”.


三. 那么何时能够获取非事务类型的Session?


1.       查看源码能够发现OpenSessionInViewFilter中能够 (配置在 web.xml中),正是这个allow=true ,才使其在无事务环境下先生成一个Session,并延迟关闭.保证了view层能够获取到懒惰载入的实体.

2.       还有就是Spring 提供的HibernateTemplate 模板工具类中也是allow=true,方便我们运行Hibernate方法.

其它如propagation= Propagation.require_new也是在上述的代码中,进行原connection挂起和恢复的操作.详细详见代码.

 其它如propagation =Propagation.require_new也是在上述的代码中,进行原connection挂起和恢复的操作.详细详见代码.

版权声明:本文博主原创文章,博客,未经同意不得转载。

时间: 2024-08-04 03:56:57

[原理][来源解析]spring于@Transactional,Propagation.SUPPORTS,以及 Hibernate Session,以及jdbc Connection关联的相关文章

[原理][源代码解析]spring中@Transactional,Propagation.SUPPORTS,以及 Hibernate Session,以及jdbc Connection关系---转载

问题: 一. 1. Spring 如何处理propagation=Propagation.SUPPORTS? 2. Spring 何时生成HibernateSession ? 3. propagation=Propagation.SUPPORTS 和propagation=Propagation.require对生成Session有何影响 ? 共同点:都会进入aspect切面处理, 试图新建Session,开启Transaction ,都能获得.TransactionStatus 区别: 前者成

hibernate+spring+struts中使用原生态的sql导致oping JDBC connection连接池资源抽光问题

打代码已经有好几个月了. HibernateTemplate hibernateTemplate = getHibernateTemplate();SessionFactory sessionFactory = hibernateTemplate.getSessionFactory(); Session session = sessionFactory.openSession(); Query query = session.createSQLQuery(hql).addEntity(Argum

深入解析Spring架构与设计原理-数据库的操作实现

关于Spring JDBC 还是从Spring JDBC说起吧,虽然现在应用很多都是直接使用Hibernate或者其他的ORM工具.但JDBC毕竟还是很基本的,其中的JdbcTemplate就是我们经常使用的,比如JDBCTemplate的execute方法,就是一个基本的方法,在这个方法的实现中,可以看到对数据库操作的基本过程. //execute方法执行的是输入的sql语句  public void execute(final String sql) throws DataAccessExc

Spring中@Transactional事务回滚实例及源码

一.使用场景举例 在了解@Transactional怎么用之前我们必须要先知道@Transactional有什么用.下面举个栗子:比如一个部门里面有很多成员,这两者分别保存在部门表和成员表里面,在删除某个部门的时候,假设我们默认删除对应的成员.但是在执行的时候可能会出现这种情况,我们先删除部门,再删除成员,但是部门删除成功了,删除成员的时候出异常了.这时候我们希望如果成员删除失败了,之前删除的部门也取消删除.这种场景就可以使用@Transactional事物回滚. 二.checked异常和unc

Spring中@Transactional用法深度分析之一

引言: 在Spring中@Transactional提供一种控制事务管理的快捷手段,但是很多人都只是@Transactional简单使用,并未深入了解,其各个配置项的使用方法,本文将深入讲解各个配置项的使用. 1.  @Transactional的定义 Spring中的@Transactional基于动态代理的机制,提供了一种透明的事务管理机制,方便快捷解决在开发中碰到的问题.在现实中,实际的问题往往比我们预期的要复杂很多,这就要求对@Transactional有深入的了解,以来应对复杂问题.

【Spring】@Transactional解释 (转)

Spring是当今广泛使用的框架,为Java核心堆栈带来了许多强大的功能和扩展.然而,大多数人倾向于使用这些功能,而不了解其潜在的机制. 由于现实生活中没有"魔法",我们将在这一系列文章中深入研究与事务和数据库相关的一些Spring功能. 第一篇文章是处理着名的@Transactional注释,为开发者节省了管理低级别事务代码的负担. 第二篇文章可以在这里:Spring @ PersistenceContext / @ PersistenceUnit解释 注意:以下代码分析使用Spri

Spring中@Transactional事务回滚(含实例详细讲解,附源码)

原文出处: 小宝鸽 一.使用场景举例 在了解@Transactional怎么用之前我们必须要先知道@Transactional有什么用.下面举个栗子:比如一个部门里面有很多成员,这两者分别保存在部门表和成员表里面,在删除某个部门的时候,假设我们默认删除对应的成员.但是在执行的时候可能会出现这种情况,我们先删除部门,再删除成员,但是部门删除成功了,删除成员的时候出异常了.这时候我们希望如果成员删除失败了,之前删除的部门也取消删除.这种场景就可以使用@Transactional事物回滚. 二.che

Spring 的 @Transactional

Spring业务的传达行动 在service类前加上@Transactional,声明这个service一切办法需求业务管理.每一个业务办法开始时都会翻开一个业务. Spring默许情况下会对运行期破例(RunTimeException)进行业务回滚.这个破例是unchecked 假如遇到checked意外就不回滚. 如何改动默许规矩: 1 让checked破例也回滚:在整个办法前加上 @Transactional(rollbackFor=Exception.class) 2 让unchecke

Spring 注解@Transactional

Spring事务的传播行为 在service类前加上@Transactional,声明这个service所有方法需要事务管理.每一个业务方法开始时都会打开一个事务. Spring默认情况下会对运行期例外(RunTimeException)进行事务回滚.这个例外是unchecked 如果遇到checked意外就不回滚. 如何改变默认规则: 1 让checked例外也回滚:在整个方法前加上 @Transactional(rollbackFor=Exception.class) 2 让unchecke