我们在Spring里通常把事务交给HibernateTransactionManager来处理,通过Aop配置事务,把事务交给该类之后就会由该类来帮我们管理和提供事务。这里它是怎么实现的,下面我们深入源码.....
public class HibernateTransactionManager extends AbstractPlatformTransactionManager
implements ResourceTransactionManager, BeanFactoryAware, InitializingBean {
首先该类继承了AbstractPlatformTransactionManager类且实现了一系列接口,
public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {
AbstractPlatformTransactionManager这个抽象类实现了接口的getTransaction(TransactionDefinition definition)方法,该方法中执行了doGetTransaction()、doBegin()方法以及其它方法,这里就不一一介绍了,
回到子类HibernateTransactionManager类,该类的重写了父类的doGetTransaction()方法和doBegin(),doCommit(),所以这个方法才是我们主要要讨论的,还有doCommit().........
从父类的getTransaction(TransactionDefinition definition)可以看出会先走doGetTransaction(),而后在走doBegin(),
我们来看doGetTransaction()方法源码:
protected Object doGetTransaction() {
HibernateTransactionObject txObject = new HibernateTransactionObject();//这里new一个HibernateTransactionObject对象
txObject.setSavepointAllowed(isNestedTransactionAllowed());//设置一个保存点
//从当前线程当中以sessionFacoty为key去取相对应的sessionHolder,
SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
if (sessionHolder != null) {
if (logger.isDebugEnabled()) {
logger.debug("Found thread-bound Session [" +
SessionFactoryUtils.toString(sessionHolder.getSession()) + "] for Hibernate transaction");
}
txObject.setSessionHolder(sessionHolder);//把sessionHolder设置到txObject当中
}
else if (this.hibernateManagedSession) {//这是判断有没有设置在当前上下文,比如在配置文件中的thread,或Spring上下文
try {
Session session = getSessionFactory().getCurrentSession();//有就直接从当前上下文去取
if (logger.isDebugEnabled()) {
logger.debug("Found Hibernate-managed Session [" +
SessionFactoryUtils.toString(session) + "] for Spring-managed transaction");
}
txObject.setExistingSession(session);//和上面一样设置sessionHolder到txObject当中,该set方法中又把session包装了下
}
catch (HibernateException ex) {
throw new DataAccessResourceFailureException(
"Could not obtain Hibernate-managed Session for Spring-managed transaction", ex);
}
}
//在事务对象中设置DataSource,其中有个afterPropertiesSet()将从sessionFactory中获取DataSource
if (getDataSource() != null) {
ConnectionHolder conHolder = (ConnectionHolder)
TransactionSynchronizationManager.getResource(getDataSource());//从当前线程中获取绑定的数据库连接,它是在doBegin()方法绑定的
txObject.setConnectionHolder(conHolder);//把从线程中取得的sessionHolder设置到txObject中
}
return txObject;
}
上面这个doGetTransaction()方法走完了就创建了HibernateTransactionObject txObject对象,这个对象也是主角,且往这个对象中填充了两个属性,为这两个属性赋好值,一个是sessionholder,另一个是connectionHolder,也就是session和connect。
当你在业务逻辑里面的C方法里面包含A,B方法时同时调用,只开了一个事务,session还是当前线程里面的同一个,直接跑sessionFactoryUtils.dogetSession()。
分开在action调用时,先A后B,会为A开个事务,在为B开事务,但是从线程里面取session。
下一个就是doBegin()方法,引入一个新对象TransactionDefinition事物描述,有些代码省略.....
protected void doBegin(Object transaction, TransactionDefinition definition) {
HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;//取得txObject对象,把事务强转HibernateTransactionObject
// 如果sessionHolder没有创建,那么这里将会创建hibernate里面的session,并把这个session放到SessionHolder中
Session session = null;
try {//判断txObject上的sessionHolder值是否为空
if (txObject.getSessionHolder() == null || txObject.getSessionHolder().isSynchronizedWithTransaction()) {
Interceptor entityInterceptor = getEntityInterceptor();//一个实体拦截器
Session newSession = (entityInterceptor != null ?
getSessionFactory().openSession(entityInterceptor) : getSessionFactory().openSession());
if (logger.isDebugEnabled()) {
logger.debug("Opened new Session [" + SessionFactoryUtils.toString(newSession) +
"] for Hibernate transaction");
}
txObject.setSession(newSession);
}
//这里从sessionHolder中取出session,为hibernateTransaction做准备
session = txObject.getSessionHolder().getSession();
if (this.prepareConnection && isSameConnectionForEntireSession(session)) {
// We're allowed to change the transaction settings of the JDBC Connection.
if (logger.isDebugEnabled()) {
logger.debug(
"Preparing JDBC Connection of Hibernate Session [" + SessionFactoryUtils.toString(session) + "]");
}
Connection con = session.connection();
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
}
else {
//这里是设置Aop里面你配置的isolation属性
// Not allowed to change the transaction settings of the JDBC Connection.
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
// We should set a specific isolation level but are not allowed to...
throw new InvalidIsolationLevelException(
"HibernateTransactionManager is not allowed to support custom isolation levels: " +
"make sure that its 'prepareConnection' flag is on (the default) and that the " +
"Hibernate connection release mode is set to 'on_close' (SpringTransactionFactory's default). " +
"Make sure that your LocalSessionFactoryBean actually uses SpringTransactionFactory: Your " +
"Hibernate properties should *not* include a 'hibernate.transaction.factory_class' property!");
}
if (logger.isDebugEnabled()) {
logger.debug(
"Not preparing JDBC Connection of Hibernate Session [" + SessionFactoryUtils.toString(session) + "]");
}
}
//这里是设置Aop里面你配置的read-only属性,
if (definition.isReadOnly() && txObject.isNewSession()) {
// Just set to NEVER in case of a new Session for this transaction.
session.setFlushMode(FlushMode.MANUAL);
}
if (!definition.isReadOnly() && !txObject.isNewSession()) {
//判断事物是否只读,是否是一个新的session,也就是当前线程里面存不存在session,不存在则为true(OpenSessionView)
// We need AUTO or COMMIT for a non-read-only transaction.
FlushMode flushMode = session.getFlushMode();
if (flushMode.lessThan(FlushMode.COMMIT)) {
session.setFlushMode(FlushMode.AUTO);
txObject.getSessionHolder().setPreviousFlushMode(flushMode);
}
}
Transaction hibTx;
// Register transaction timeout.
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
hibTx = session.getTransaction();
//设置一个事务超时机制,设置时间hibTx.begin();
hibTx.setTimeout(timeout);
}else {
//将hibernate的事务设置到txObject的sessionHolder的里面,这个sessionHolder会和线程绑定.
hibTx = session.beginTransaction();
}
//将Transaction hibTx设置到txObject中,给txObject事务赋值,主要是一个已经开启的事务
txObject.getSessionHolder().setTransaction(hibTx);
// Register the Hibernate Session's JDBC Connection for the DataSource, if set.
if (getDataSource() != null) {
Connection con = session.connection();
ConnectionHolder conHolder = new ConnectionHolder(con);//包装connection
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
conHolder.setTimeoutInSeconds(timeout);
}
if (logger.isDebugEnabled()) {
logger.debug("Exposing Hibernate transaction as JDBC transaction [" + con + "]");
}
//把当前的数据库connection绑定在当前线程当中.
TransactionSynchronizationManager.bindResource(getDataSource(), conHolder);
//在这里给txObject的ConnectionHolder赋值,以保证在con不为null
txObject.setConnectionHolder(conHolder);
}
//如果是新的sessionHolder,将它和当前线程绑定// Bind the session holder to the thread.
if (txObject.isNewSessionHolder()) {
//判断在当前线程里面有没有这个sessionHolder,当前里面有则为false,open则是true
TransactionSynchronizationManager.bindResource(getSessionFactory(), txObject.getSessionHolder());
//绑定到当前线程当中
}
//在sessionHolder中进行状态标志,标识事务已经开始。
txObject.getSessionHolder().setSynchronizedWithTransaction(true);
}
}
上面这个doBegin方法,首先是得到一个在上面doGetTransaction()里面创建的hibernateTransactionObject对象txObject,还有个实体拦截器,entityInterceptor,该拦截器的作用就相当于一个代理,要访问被代理的对象,先走这个拦截器,我们在doGetTransaction方法中,先判断了在线程和当前上下文能不能取得到session,并把其设置到txObject中,并且还在doBegin()中为了保证sessionHolder不为null,判断同学txObject.getSessionHolder()如果为null,则通过sessionfactory打开一个session,并把它传到txObject封装成sessionHolder,且在opensession方法中传入拦截器,在打开session之前做事.
设置isolation,
read-only='true'时,虚拟事务,可以保证hibernate查询立刻发送sql语句.
1.走完doBegin(),txObject里面设置session和connect,在这个方法已经保证这两个值不为null,在doGetTrainsaction()方法是从线程里面取,如果没绑定,也就是null,在doBegin()中,保证了不为空,而session分为3中情况,1.OpensessionView,2.getCurrentSession(可以是thead或是spring上下文),3.opensession
上面源代码中的isNewSessionHolder()方法是返回这个session是否是一个新的,像OpensessionView则返回false,其它两中情况则是返回true,是新的则要绑定到线程当中.
2.得到的session在方法中开启了一个事务,并把事务存放到sessionHolder里,由于sessionHolder是绑定到线程当中,所以它的事务也将会同步
3.其中,还把数据库连接绑定到当前线程中去了,以数据库连接池datasouce为key,value是connectHolder.
总:doBegin()走完后,当前线程中就已经有两对值:
key | value |
sessionFactory | sessionHolder |
dataSource | conHolder |
Thread.currentThread——>t
t.threadLocals这个Map中包含的{key:ThreadLocal<Map>,value:Map},这里面的Map存放着session,connect。
protected void doCommit(DefaultTransactionStatus status) {//事务提交
HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();
if (status.isDebug()) {
logger.debug("Committing Hibernate transaction on Session [" +
SessionFactoryUtils.toString(txObject.getSessionHolder().getSession()) + "]");
}
try {
txObject.getSessionHolder().getTransaction().commit();//得到sessionHolder的事务,直接提交
}
doCommit()众所周知是事务提交,当然在提交之前,也做了些许多事情,比如清空session,这些方法就没一一列出.可以查看父类AbstractPlatformTransactionManager中的processCommit()方法, 可以看到是先跑一些prepareForCommit准备提交的方法等等......
绑定到线程上的事务,rollback.
更多详细查看 :
http://sailinglee.iteye.com/blog/598908
TransactionDefinition:
http://book.51cto.com/art/200909/149403.htm