[原理][源代码解析]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挂起和恢复的操作.具体详见代码.

### 回答1: `@transactional(propagation = propagation.supports)` 是 Spring 框架的一个注解,用于指定事务的传播行为为“支持当前事务,如果不存在则不开启事务”。也就是如果当前方法正在运行在一个具有事务的上下文,则支持这个事务;否则不会开启新的事务。这个注解通常用于查询或读取操作,不需要对数据库进行更改或写入操作。 ### 回答2: @Transactional(propagation = propagation.supports) 是 Spring 框架的一个注解,可以应用在方法或类级别上,用于声明事务处理的方式。其 propagation 属性用于定义事务的传播方式,而 supports 表示当前方法或类支持加入已有的事务,如果不存在事务,则不会开启新的事务。本文将从以下几方面对其进行详细解析。 1. 事务的传播方式 Spring 框架事务的传播方式共有七种,分别是: - PROPAGATION_REQUIRED:默认传播方式,如果当前存在事务则加入该事务,如果不存在则创建新事务。 - PROPAGATION_SUPPORTS:如果当前存在事务则加入该事务,如果不存在则以非事务方式执行。 - PROPAGATION_MANDATORY:强制要求当前存在事务,如果不存在则抛出异常。 - PROPAGATION_REQUIRES_NEW:如果存在事务则挂起当前事务,创建新的事务执行。如果不存在事务则创建新事务执行。 - PROPAGATION_NOT_SUPPORTED:以非事务方式执行,如果当前存在事务则挂起事务。 - PROPAGATION_NEVER:以非事务方式执行,如果存在事务则抛出异常。 - PROPAGATION_NESTED:使用 JDBC 3.0 Savepoint 进行事务控制,如果当前存在事务则嵌套在该事务执行。 2. 当前支持事务加入 使用 @Transactional(propagation = propagation.supports) 注解的方法或类,在当前已存在的事务运行。如果没有当前事务,则该方法不会启动新的事务,而是以非事务方式执行。 3. 注意事项 - 具有相同或更高优先级的事务可以添加到正在运行的事务。 - 如果当前没有正在运行的事务,并且事务管理器支持这样做,则方法将以非事务方式运行。 - 如果当前没有正在运行的事务,并且事务管理器不支持非事务方式,则会抛出异常。 - 使用 @Transactional 注解时应该密切关注传播级别,否则可能会产生一些不必要的麻烦。 总之,@Transactional(propagation = propagation.supports) 是一个非常有用的注解,可以帮助我们声明 Spring 事务处理的方式。使用 supports 作为传播属性,可以让当前方法或类支持加入已有的事务,而不创建新的事务。对于一些只需要读取数据或执行一些非关键操作的方法,使用 supports 方式可以节约系统资源并提高系统性能。 ### 回答3: 在Spring,@Transactional注解是一个非常重要的注解,它用于声明方法需要在事务执行。使用这个注解可以很方便地管理事务,无需手动编写繁琐的事务管理代码。其propagation是@Transaction注解的一个属性,用于指定事务的传播行为。 在@Transactionpropagation属性有多个取值: 1. PROPAGATION_REQUIRED (默认值):表示必须要启动一个新的事务,如果当前没有事务,则新建一个,如果当前已经存在事务,则加入该事务。 2. PROPAGATION_SUPPORTS:表示当前方法不需要事务,但如果当前存在事务,则加入该事务,即支持当前事务。 3. PROPAGATION_MANDATORY:表示当前方法必须在一个已经存在的事务执行,否则将抛出异常。 4. PROPAGATION_REQUIRES_NEW:表示当前方法必须启动一个新的事务,如果当前已经存在事务,则挂起当前事务并启动一个新的事务。 5. PROPAGATION_NOT_SUPPORTED:表示当前方法不应该在事务执行,如果当前存在事务,则挂起该事务。 6. PROPAGATION_NEVER:表示当前方法不应该在事务执行,如果当前存在事务,则抛出异常。 7. PROPAGATION_NESTED:表示当前方法必须在一个已经存在的事务执行,如果当前没有事务,则新建一个事务。如果当前存在事务,当前方法会被嵌套在该事务执行,即嵌套事务。 而针对于@transactional(propagation = propagation.supports),它的作用是声明当前方法不需要事务,但是如果当前已经存在事务,则会加入当前事务执行。这种传播行为通常用于一些查询方法,比如查询用户信息等,此时不需要对数据进行修改,只需要读取数据就可以了。 总之,@transactional(propagation = propagation.supports)表示当前方法不需要事务,但如果当前存在事务,则加入该事务,即支持当前事务。这种传播行为通常用于一些查询方法,比如查询用户信息等,这样可以减少数据库连接的开销,提高查询效率。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值