HibernateTransactionManager事务管理

配置JdbcTemplate

先配置数据源:

    <bean id="dataSource"         class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost:3306/mkyongjava" />
        <property name="username" value="root" />
        <property name="password" value="password" />
    </bean>

在配置JdbcTemplate

JdbcCustomerDAO继承JdbcTemplate

    <bean id="customerDAO" class="com.mkyong.customer.dao.impl.JdbcCustomerDAO">
        <property name="dataSource" ref="dataSource" />
    </bean>

配置HibernateTemplate

    <context:property-placeholder location="jdbc.properties" />  
    <!-- c3p0数据源 -->  
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">  
        <!-- 驱动程序 -->  
        <property name="driverClass">  
            <value>${jdbc.driverClass}</value>  
        </property>  

        <!-- 连接的url地址 -->  
        <property name="jdbcUrl">  
            <value>${jdbc.url}</value>  
        </property>  

        <!-- 连接的用户名 -->  
        <property name="user">  
            <value>${jdbc.user}</value>  
        </property>  

        <!-- 连接的密码 -->  
        <property name="password">  
            <value>${jdbc.password}</value>  
        </property>  

        <!-- 最大池数 -->  
        <property name="maxPoolSize">  
            <value>${c3p0.pool.max}</value>  
        </property>  

        <!-- 最小池数 -->  
        <property name="minPoolSize">  
            <value>${c3p0.pool.min}</value>  
        </property>  
        <!-- 默认初始化的池数 -->  
        <property name="initialPoolSize">  
            <value>${c3p0.pool.init}</value>  
        </property>  
    </bean>  


    <bean id="sessionFactory"          class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">  
        <!-- 设置数据源 -->  
        <property name="dataSource" ref="dataSource" />  
        <!-- 属性设置 -->  
        <property name="hibernateProperties">  
            <props>  
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>  
                <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>  
            </props>  
        </property>  
        <!-- 映射文件配置 -->  
        <property name="mappingResources">  
            <list>  
                <value>cn/csdn/domain/Customer.hbm.xml</value>  
            </list>  
        </property>  
    </bean>  


<!-- hibernate模板 -->  
    <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">  
        <property name="sessionFactory" ref="sessionFactory" />  
    </bean>

如果一个方法中既用了HibernateTemplate,又用了JdbcTemplate,应该怎么配事务?用 DataSouceTransactionManager是不行的,而用HibernateTransactionManager就可以保证
HibernateTransactionManager可以保证SessionFactoryUtilDataSourceUtil都能在一个事务里取到同一个连接

在一个service方法里面,用了jdbcdaosupport的dao又用了hibernateDaoSupport的dao,在spring里面给service方法配上了事务,

但是通过mysql的bin log,发现这种不同的dao使用的连接id不是同一个,即jdbctemplate使用了一个链接,而hibernatetemplate使用了另外一个链接,虽然两种dao都是针对一个mysql实例,但却没法保证事务。

使用hibernateTransaction manager,可以保证混用时候的事务。我们这边就以为datasourcetransactionmanager也是一样,但发现事实上不一样。确实我们换成hibernateTransaction manager,两种dao使用的connection就归一了,真好,但是为啥呢?

以下是datasourceTransactionManagerdoGetTransactiondoBegin代码

protected Object doGetTransaction() {  

//只是设定一个dataSource为key的存放connection的threadlcal  
   DataSourceTransactionObject txObject = new DataSourceTransactionObject();  
   txObject.setSavepointAllowed(isNestedTransactionAllowed());  
   ConnectionHolder conHolder =  
      (ConnectionHolder) TransactionSynchronizationManager.getResource(this.dataSource);  
   txObject.setConnectionHolder(conHolder, false);  
   return txObject;  
}  

protected void doBegin(Object transaction, TransactionDefinition definition) {  
     .....  

   try {  
    if (txObject.getConnectionHolder() == null ||  
      txObject.getConnectionHolder().isSynchronizedWithTransaction()) {  
     Connection newCon = this.dataSource.getConnection();  
    }  

....  
//从datasource拿一个连接,放入thread生命周期的holder  

}  

这就完了。

然后jdbctemplate会通过datasourceutil去拿这个holder里面的connection

从而在一个事务里使用这个连接。

但是hibernateTransactionManager呢:

protected Object doGetTransaction() {  
   HibernateTransactionObject txObject = new HibernateTransactionObject();  
   txObject.setSavepointAllowed(isNestedTransactionAllowed());  

   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, false);  
   }  

   if (getDataSource() != null) {  
    ConnectionHolder conHolder = (ConnectionHolder)  
      TransactionSynchronizationManager.getResource(getDataSource());  
    txObject.setConnectionHolder(conHolder);  
   }  

   return txObject;  
}  

//两个holder都管!  

protected void doBegin(Object transaction, TransactionDefinition definition) {  
     .....  

   try {  
    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.setSessionHolder(new SessionHolder(newSession), true);  
    }  

    .....  
    //从sessionFactory拿个新session,也会产生一个新连接  

    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) + "]");  
     }  

     //原来直接把session后面的connection也放入holder  
     Connection con = session.connection();  
     Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);  
     txObject.setPreviousIsolationLevel(previousIsolationLevel);  
    }  

所以如果使用hibernateTransactionManager的话,就完全可以保证SessionFactoryUtil和datasourceutil都能在一个事务里取到同一个连接!所有的疑问烟消云散了,
所以大家还是使用hibernateTransactionManager从而随心所欲的使用jdbctemplate和hibernatetemplate吧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值