HibernateTransactionManager事务管理

来源:互联网 发布:写一个动态数组模板类 编辑:程序博客网 时间:2024/04/19 11:15

配置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
原创粉丝点击