`

Spring-JDBC/ORM 统一事务管理解决方案

 
阅读更多

若使用 MyBatis[JDBC] 与hibernate[ORM] 框架结合,且 使用 相同的事务:

 

解决方案三种:

 

1: 将JDBC事务打开,且Hibernate事务关闭,再修改 hibernate sessionFactory的 useTransactionAwareDataSource  属性为true

 

<!-- 事务管理器配置, 使用jdbc事务 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>
<!-- 使用annotation定义事务 -->
	<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
<!-- Hibernate配置 -->
	<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="namingStrategy">
			<bean class="org.hibernate.cfg.ImprovedNamingStrategy" />
		</property>
		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.dialect">${hibernate.dialect}</prop>
				<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
				<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
				<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
				<prop key="hibernate.cache.provider_configuration_file_resource_path">ehcache/ehcache-hibernate-local.xml</prop>
			</props>
		</property>
		<property name="packagesToScan" value="org.springtest.entity" />
		<property name="useTransactionAwareDataSource" value="true"/>
	</bean>

 参加Spring源码:

 

SessionFactory org.springframework.orm.hibernate3.LocalSessionFactoryBean.buildSessionFactory() throws Exception
if (dataSource != null) {
				Class providerClass = LocalDataSourceConnectionProvider.class;
				if (isUseTransactionAwareDataSource() || dataSource instanceof TransactionAwareDataSourceProxy) {
					providerClass = TransactionAwareDataSourceConnectionProvider.class;
				}
				else if (config.getProperty(Environment.TRANSACTION_MANAGER_STRATEGY) != null) {
					providerClass = LocalJtaDataSourceConnectionProvider.class;
				}
				// Set Spring-provided DataSource as Hibernate ConnectionProvider.
				config.setProperty(Environment.CONNECTION_PROVIDER, providerClass.getName());
			}
 第二种: 使用JTA事务:
<beans>

  <bean id="myDataSource1" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName value="java:comp/env/jdbc/myds1"/>
  </bean>

  <bean id="myDataSource2" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName" value="java:comp/env/jdbc/myds2"/>
  </bean>

  <bean id="mySessionFactory1" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="myDataSource1"/>
    <property name="mappingResources">
      <list>
        <value>product.hbm.xml</value>
      </list>
    </property>
    <property name="hibernateProperties">
      <value>
        hibernate.dialect=org.hibernate.dialect.MySQLDialect
        hibernate.show_sql=true
      </value>
    </property>
  </bean>

  <bean id="mySessionFactory2" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="myDataSource2"/>
    <property name="mappingResources">
      <list>
        <value>inventory.hbm.xml</value>
      </list>
    </property>
    <property name="hibernateProperties">
      <value>
        hibernate.dialect=org.hibernate.dialect.OracleDialect
      </value>
    </property>
  </bean>

  <bean id="myTxManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>

  <bean id="myProductDao" class="product.ProductDaoImpl">
    <property name="sessionFactory" ref="mySessionFactory1"/>
  </bean>

  <bean id="myInventoryDao" class="product.InventoryDaoImpl">
    <property name="sessionFactory" ref="mySessionFactory2"/>
  </bean>

  <!-- this shows the Spring 1.x style of declarative transaction configuration -->
  <!-- it is totally supported, 100% legal in Spring 2.x, but see also above for the sleeker, Spring 2.0 style -->
  <bean id="myProductService"
      class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <property name="transactionManager" ref="myTxManager"/>
    <property name="target">
      <bean class="product.ProductServiceImpl">
        <property name="productDao" ref="myProductDao"/>
        <property name="inventoryDao" ref="myInventoryDao"/>
      </bean>
    </property>
    <property name="transactionAttributes">
      <props>
        <prop key="increasePrice*">PROPAGATION_REQUIRED</prop>
        <prop key="someOtherBusinessMethod">PROPAGATION_REQUIRES_NEW</prop>
        <prop key="*">PROPAGATION_SUPPORTS,readOnly</prop>
      </props>
    </property>
  </bean>

</beans>

 

第三种:使用被代理的数据源:

 

使用 TransactionAwareDataSourceProxy

如果不得已要显式获取数据连接,除了使用 DataSourceUtils 获取事务上下文绑定的连接外,还可以通过 TransactionAwareDataSourceProxy 对数据源进行代理。数据源对象被代理后就具有了事务上下文感知的能力,通过代理数据源的 getConnection() 方法获取的连接和使用 DataSourceUtils.getConnection() 获取连接的效果是一样的。

下面是使用 TransactionAwareDataSourceProxy 对数据源进行代理的配置:


清单 11.applicationContext.xml:对数据源进行代理

				
<bean id="dataSource"
    class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close"
    p:driverClassName="oracle.jdbc.driver.OracleDriver"
    p:url="jdbc:oracle:thin:@localhost:1521:orcl"
    p:username="test"
    p:password="test"
    p:defaultAutoCommit="false"/>
    
<!-- ①对数据源进行代理-->
<bean id="dataSourceProxy" 
    class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy"
    p:targetDataSource-ref="dataSource"/>
    
<!-- ②直接使用数据源的代理对象-->
<bean id="jdbcTemplate"
    class="org.springframework.jdbc.core.JdbcTemplate"
    p:dataSource-ref="dataSourceProxy"/>
    
<!-- ③直接使用数据源的代理对象-->
<bean id="jdbcManager"
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
    p:dataSource-ref="dataSourceProxy"/>

 

对数据源进行代理后,我们就可以通过数据源代理对象的 getConnection() 获取事务上下文中绑定的数据连接了。

因此,如果数据源已经进行了 TransactionAwareDataSourceProxy 的代理,而且方法存在事务上下文,那么清单 1 的代码也不会生产连接泄漏的问题。

 

参加 void org.mybatis.spring.SqlSessionFactoryBean.setDataSource(DataSource dataSource)

public void setDataSource(DataSource dataSource) {
		if (dataSource instanceof TransactionAwareDataSourceProxy) {
			this.dataSource = ((TransactionAwareDataSourceProxy) dataSource)
					.getTargetDataSource();
		} else
			this.dataSource = dataSource;
	}

 以及:void org.springframework.jdbc.datasource.DataSourceTransactionManager.setDataSource(DataSource dataSource)

public void setDataSource(DataSource dataSource)
    {
        if(dataSource instanceof TransactionAwareDataSourceProxy)
            this.dataSource = ((TransactionAwareDataSourceProxy)dataSource).getTargetDataSource();
        else
            this.dataSource = dataSource;
    }

 

及: void org.springframework.orm.jpa.JpaTransactionManager.setDataSource(DataSource dataSource)

 

对于 Hibernate 的 sessionFactory 取得的所有的实际数据库连接皆取自于 

Connection org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourcedataSource) throws SQLException

 

而就是这个方法保证了取得的数据库连接 是 绑定到当前线程的真正数据库连接.

 

对于MyBatis官方文档中就是 使用 JDBC事务管理器便能够管理事务,则

 

只要 数据库被代理了,且使用的是 JDBC事务管理器则能够保证事务的一致性,

 

 

 另参见Hibernate配置:void org.springframework.orm.hibernate3.AbstractSessionFactoryBean.setUseTransactionAwareDataSource(boolean useTransactionAwareDataSource)

和 http://www.blogjava.net/i369/articles/194855.html

但JPA事务管理器取得的数据库连接也是 DataSourceUtils.doGetConnection 取得的连接

分享到:
评论

相关推荐

    Spring-Reference_zh_CN(Spring中文参考手册)

    9.9. 公共问题的解决方案 9.9.1. 对一个特定的 DataSource 使用错误的事务管理器 9.10. 更多的资源 10. DAO支持 10.1. 简介 10.2. 一致的异常层次 10.3. 一致的DAO支持抽象类 11. 使用JDBC进行数据访问 11.1. 简介 ...

    Spring攻略PDF版

    Spring专家力作 理论与实践完美结合 问题描述→解决方案→实现方法 第一部分 核心概念  第1章 控制反转和容器   1.1 使用容器管理组件   1.1.1 问题描述   1.1.2 解决方案   1.1.3 实现方法  ...

    Spring攻略中文版PDF

    Spring专家力作 理论与实践完美结合 问题描述→解决方案→实现方法 第一部分 核心概念  第1章 控制反转和容器   1.1 使用容器管理组件   1.1.1 问题描述   1.1.2 解决方案   1.1.3 实现方法  ...

    Spring攻略英文版(附带源码)

    Spring专家力作 理论与实践完美结合 问题描述→解决方案→实现方法 第一部分 核心概念  第1章 控制反转和容器   1.1 使用容器管理组件   1.1.1 问题描述   1.1.2 解决方案   1.1.3 实现方法   1.2...

    Spring攻略(第二版 中文高清版).part1

    1.1.2 解决方案 1 1.1.3 工作原理 3 1.2 配置Spring IoC容器中的Bean 4 1.2.1 问题 4 1.2.2 解决方案 4 1.2.3 工作原理 4 1.3 调用构造程序创建Bean 14 1.3.1 问题 14 1.3.2 解决方案 14 1.3.3 ...

    Spring攻略(第二版 中文高清版).part2

    1.1.2 解决方案 1 1.1.3 工作原理 3 1.2 配置Spring IoC容器中的Bean 4 1.2.1 问题 4 1.2.2 解决方案 4 1.2.3 工作原理 4 1.3 调用构造程序创建Bean 14 1.3.1 问题 14 1.3.2 解决方案 14 1.3.3 ...

    Spring中文帮助文档

    9.5.1. 理解Spring的声明式事务管理实现 9.5.2. 第一个例子 9.5.3. 回滚 9.5.4. 为不同的bean配置不同的事务语义 9.5.5. &lt;tx:advice/&gt; 有关的设置 9.5.6. 使用 @Transactional 9.5.7. 事务传播 9.5.8. 通知...

    spring chm文档

    9.9. 公共问题的解决方案 9.9.1. 对一个特定的 DataSource 使用错误的事务管理器 9.10. 更多的资源 10. DAO支持 10.1. 简介 10.2. 一致的异常层次 10.3. 一致的DAO支持抽象类 11. 使用JDBC进行数据访问 11.1....

    Spring API

    9.5.1. 理解Spring的声明式事务管理实现 9.5.2. 第一个例子 9.5.3. 回滚 9.5.4. 为不同的bean配置不同的事务语义 9.5.5. &lt;tx:advice/&gt; 有关的设置 9.5.6. 使用 @Transactional 9.5.7. 事务传播 9.5.8. 通知...

    Spring 2.0 开发参考手册

    9.9. 公共问题的解决方案 9.9.1. 对一个特定的 DataSource 使用错误的事务管理器 9.10. 更多的资源 10. DAO支持 10.1. 简介 10.2. 一致的异常层次 10.3. 一致的DAO支持抽象类 11. 使用JDBC进行数据访问 11.1....

    ssh(structs,spring,hibernate)框架中的上传下载

     以上是Spring+Hibernate将文件二进制数据持久化到数据库的解决方案,而Struts通过将表单中file类型的组件映射为ActionForm中类型为org.apache.struts.upload. FormFile的属性来获取表单提交的文件数据。  工程...

    springmybatis

    DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"&gt; &lt;typeAliases&gt; &lt;typeAlias alias="User" type="com.yihaomen.mybatis.model.User"/&gt; &lt;/...

    Spring.3.x企业应用开发实战(完整版).part2

    10.5.2 Hibernate+Spring JDBC混合框架的事务管理 10.6 特殊方法成漏网之鱼 10.6.1 哪些方法不能实施Spring AOP事务 10.6.2 事务增强遗漏实例 10.7 数据连接泄漏 10.7.1 底层连接资源的访问问题 10.7.2 Spring JDBC...

    ShardingSphere:SpringBoot2+MybatisPlus+Swagge分库分表

    ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈。 它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar(计划中)这3款相互独立的产品组成,shardingSphere定位为关系型数据库中间件。? ...

    ShardingSphere:SpringBoot2+MybatisPlus读写分离+分表

    ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈。 它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar(计划中)这3款相互独立的产品组成,shardingSphere定位为关系型数据库中间件。 ...

    ShardingSphere:SpringBoot2+MybatisPlus+Swagger读写分离

    ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈。它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar(计划中)这3款相互独立的产品组成,shardingSphere定位为关系型数据库中间件。? ...

    ShardingSphere:SpringBoot2+MybatisPlus3+UI不分库只分表

    ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈。它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar(计划中)这3款相互独立的产品组成,shardingSphere定位为关系型数据库中间件。? ...

    Spring3.x企业应用开发实战(完整版) part1

    10.5.2 Hibernate+Spring JDBC混合框架的事务管理 10.6 特殊方法成漏网之鱼 10.6.1 哪些方法不能实施Spring AOP事务 10.6.2 事务增强遗漏实例 10.7 数据连接泄漏 10.7.1 底层连接资源的访问问题 10.7.2 Spring JDBC...

    ShardingSphere:SpringBoot2+MybatisPlus+读写分离+分库分表

    ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈。 它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar(计划中)这3款相互独立的产品组成,shardingSphere定位为关系型数据库中间件。? ...

    java三大框架

    Spring也许称得上是个一站式解决方案,提供了一个典型应用所需要的大部分基础架构。它还涉及到了其他framework没有考虑到的内容。 尽管它仅仅是一个从2003年2月才开始的开源项目,但Spring有深厚的历史根基。 ...

Global site tag (gtag.js) - Google Analytics