Hibernate、Spring事务要点拾遗

本文深入探讨了数据库系统中事务隔离级别和事务传播特性,详细解释了JDBC和Hibernate如何实现事务管理,包括Serializable、RepeatableRead、ReadCommitted、ReadUncommitted等隔离级别及PROPAGATION_REQUIRED、PROPAGATION_SUPPORTS等传播特性。同时,通过分析HibernateTransactionManager的源码,展示了Spring和Hibernate集成后如何进行事务管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、事务隔离级别和事务传播特性

数据库系统中多个事务的并发可能发生以下5种现象:

     第一类丢失更新撤消一个事务时,把其它事务已提交的更新的数据覆盖了。
     脏读一个事务读到另一个事务未提交的更新数据。
     幻读一个事务执行两次查询,但第二次查询比第一次查询多出了一些数据行。
      不可重复读一个事务两次读同一行数据,可是这两次读到的数据不一样。
      第二类丢失更新这是不可重复读中的特例,一个事务覆盖另一个事务已提交的更新数据。
JDBC的数据库连接使用数据库默认的事务隔离级别,hibernate可以显式设置事务隔离级别
</pre><pre name="code" class="html" style="font-size:14px;"><session-factory>
<!-- 设置JDBC的隔离级别 -->
<property name="hibernate.connection.isolation">2</property>
</session-factory>
每一种事务隔离级别对应一个正整数:
     Serializable:串行化。隔离级别最高8
     Repeatable Read:可重复读。4
     Read Committed:读已提交数据。2
     Read Uncommitted:读未提交数据。隔离级别最差。1

隔离级别

脏读 (Dirty Read)

不可重复读(NonRepeatable Read)

幻读 (Phantom Read)

读操作未提交 (Read uncommitted)

可能

可能

可能

读操作已提交 (Read commited)

不可能

可能

可能

可重复读 (Repeatable read)

不可能

不可能

可能

可串行化 (Serializable)

不可能

不可能

不可能

 以下是7种事务传播特性

1.PROPAGATION_REQUIRED: 如果存在一个事务,则支持当前事务。如果没有事务则开启

2.PROPAGATION_SUPPORTS: 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行
3.PROPAGATION_MANDATORY: 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。
4.PROPAGATION_REQUIRES_NEW: 总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
5.PROPAGATION_NOT_SUPPORTED: 总是非事务地执行,并挂起任何存在的事务。
6.PROPAGATION_NEVER: 总是非事务地执行,如果存在一个活动事务,则抛出异常
7.PROPAGATION_NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务,  则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行

2、HibernateTranscationManager

       通常在Spring和Hibernate的集成中,hibernate的事务管理被委托给HibernateTranscationManager。以下通过HibernateTranscationManager的部分源码对Spring和Hihernate集成后的事务管理进行分析。
public class HibernateTransactionManager extends AbstractPlatformTransactionManager  
        implements ResourceTransactionManager, BeanFactoryAware, InitializingBean {  
      首先该类继承了AbstractPlatformTransactionManager类且重写了doGetTransaction()方法和doBegin(),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。
下一个就是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方法中传入拦截器。
现在这个主角类HibernateTransactionObject对象txObject已经包含了sessionHolder,conHolder,已经开启了的Transaction。doCommit()众所周知是事务提交,当然在提交之前,也做了些许多事情,比如清空session,这些方法就没一一列出.可以查看父类AbstractPlatformTransactionManager中的processCommit()方法, 可以看到是先跑一些prepareForCommit准备提交的方法等等......
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的事务,直接提交   
    }  







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值