代码
- txObject.getSessionHolder().setSynchronizedWithTransaction(true);
- session = txObject.getSessionHolder().getSession();
-
- Connection con = session.connection();
- Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
- txObject.setPreviousIsolationLevel(previousIsolationLevel);
-
- if (definition.isReadOnly() && txObject.isNewSessionHolder()) {
-
- session.setFlushMode(FlushMode.NEVER);
- }
-
- if (!definition.isReadOnly() && !txObject.isNewSessionHolder()) {
-
- FlushMode flushMode = session.getFlushMode();
- if (FlushMode.NEVER.equals(flushMode)) {
- session.setFlushMode(FlushMode.AUTO);
-
- txObject.getSessionHolder().setPreviousFlushMode(flushMode);
- }
- }
-
-
- txObject.getSessionHolder().setTransaction(session.beginTransaction());
-
-
- if (definition.getTimeout() != TransactionDefinition.TIMEOUT_DEFAULT) {
- txObject.getSessionHolder().setTimeoutInSeconds(definition.getTimeout());
- }
-
-
- if (getDataSource() != null) {
- ConnectionHolder conHolder = new ConnectionHolder(con);
- if (definition.getTimeout() != TransactionDefinition.TIMEOUT_DEFAULT) {
- conHolder.setTimeoutInSeconds(definition.getTimeout());
- }
- if (logger.isDebugEnabled()) {
- logger.debug("Exposing Hibernate transaction as JDBC transaction [" + con + "]");
- }
- TransactionSynchronizationManager.bindResource(getDataSource(), conHolder);
- txObject.setConnectionHolder(conHolder);
- }
-
-
- if (txObject.isNewSessionHolder()) {
- TransactionSynchronizationManager.bindResource(getSessionFactory(), txObject.getSessionHolder());
- }
- }
- catch (Exception ex) {
- SessionFactoryUtils.releaseSession(session, getSessionFactory());
- throw new CannotCreateTransactionException("Could not open Hibernate Session for transaction", ex);
- }
- }
通过以上对代码的注释可以知道,如果给service设置声明式事务管理,假设事务传播途径为required,然后一个service调用另一个service时,他们其实是共用一个session,原则是没有就创建,有就不创建,并返回之前已创建的session和transaction。也就是说spring通过threadlocal把session和对应的transaction放到线程之中,保证了在整个方法栈的任何一个地方都能得到同一个session和transaction。
所以如果你的方法在事务体之内,那么你只要通过hibernatesupportdao或者hibernatetemplate来得到session的话,那这个session一定是开始事务的那个session,这个得到session的主要方法在SessionFactoryUtils里,我们来看一下
(这里还有一个小细节,public abstract class SessionFactoryUtils ,Juergen Hoeller在写工具类的时候为了不能让其有实例使用的是abstract,而我们一般的做法是final类加private的构造方法,看上去不怎么雅观,看看源代码还是能学习到不少写代码的技巧的,这里还有一个插曲,上次feiing还说java为什么不能弄成final和abstract同时存在呢,这样就可以确保既不会有实例产生,也不能继承了,呵呵)
在SessionFactoryUtils的doGetSession里写到,如果当前线程有绑定session,则返回这个session,如果没有绑定session,则看是否允许创建(既allowCreate这个参数是true还是false,这个参数将会在很多地方设计到,比如说hibernatetemplate和hibernatedaosupport里都有),如果不允许创建就抛出一个原始的hibernateException,举个例子,如果你没有给某个service方法配置声明式事务管理,而却要在这个service所调用的dao里得到当前得session,这样就会抛这个错了:
代码
- if (method.getName().equals("getCurrentSession")) {
-
- try {
- return SessionFactoryUtils.doGetSession((SessionFactory) proxy, false);
-
- }
- catch (IllegalStateException ex) {
- throw new HibernateException(ex.getMessage());
- }
- }
到这里事务开始部分基本就结束了
按正常流程,那么接下来就是方法结束commit的问题了。Commit放到下一篇文章里说吧