[原理][源代码解析]spring中@Transactional,Propagation.SUPPORTS,以及 Hibernate Session,以及jdbc Connection关系
来源:互联网 发布:写作软件哪个好 编辑:程序博客网 时间:2024/05/18 12:37
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, null, true,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.
何时allowCreate是ture?见下面 三. 那么何时可以获取非事务类型的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挂起和恢复的操作.具体详见代码.
- [原理][源代码解析]spring中@Transactional,Propagation.SUPPORTS,以及 Hibernate Session,以及jdbc Connection关系
- spring配置事务管理及事物传播行为介绍(@Transactional(propagation = Propagation.SUPPORTS))
- Spring事务管理中@Transactional的propagation参数
- Spring事务管理中@Transactional的propagation参数
- Spring事务管理中@Transactional的propagation参数
- Spring事务管理中@Transactional的propagation参数
- hibernate,spring管理事务中(transaction,JDBC connection,Hibernate Session的使用)
- Spring Transactional Propagation
- PHP中Session原理以及和Cookie的关系
- Spring中@transactional原理
- Spring事务管理中@Transactional的propagation参数(转)
- Spring @Transactional的propagation参数
- Spring: @Transactional中的propagation属性
- Spring: @Transactional中的propagation属性
- Spring: @Transactional中的propagation属性
- Spring: @Transactional中的propagation属性
- jQuery工作原理解析以及源代码示例
- jQuery工作原理解析以及源代码示例
- 第四届在线编程大赛·线上初赛:带通配符的数-我的解题方法
- 前端学习——JSON格式详解
- JSP 简介
- jabberNet 发送出席信息
- C++中如何在main()函数之前执行操作?
- [原理][源代码解析]spring中@Transactional,Propagation.SUPPORTS,以及 Hibernate Session,以及jdbc Connection关系
- 黑马程序员——动态代理技术
- 基于sqlCE 3.0的数据库开发
- android状态机机制StateMachine
- 省市区 数组套字典 字典套数组
- 放逐心灵之旅
- bzoj1230[Usaco2008 Nov]lites 开关灯
- 两圆交点
- 集成百度地图API实现定位