前段时间,跟朋友讨论怎么实现这个东西的时候想到的一个方法,不知道正规场合可行不可行,我自己测试的时候没啥问题,我是个新手,希望朋友们不吝指教。
我测试的时候只是增删改查没啥问题,不知道事务是不是如我预料的那样没问题....
当然,做分布式还是用JTA更好一些,现在的JAVA EE容器都直接支持了,下面这些方法只是给像我一样的野战军用的土方法,适用于Tomcat,哈哈。
第一种(不推荐,因为无法实现分布式事务):
直接创建多个SessionFactory和多个DataSource,给他们赋予不同的id,在dao层使用的时候针对不同的数据库操作使用不同的sessionFactory
使用方法:
1、配置oracle数据源spring-oracle.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"
>
<!-- 配置dataSource_oracle -->
<bean id="dataSource_oracle" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@//218.198.177.109:1521/orcl"/>
<property name="username" value="roy"/>
<property name="password" value="roy"/>
<property name="defaultAutoCommit" value="false"/>
</bean>
<!-- 配置sessionFactory_oracle -->
<bean id="sessionFactory_oracle" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource_oracle"/>
<property name="hibernateProperties">
<props>
<!--
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
-->
<prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.jdbc.fetch_size">30</prop>
<prop key="hibernate.jdbc.batch_size">30</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
<property name="annotatedClasses">
<list>
<value>model.User</value>
<value>model.Role</value>
</list>
</property>
</bean>
<!-- 配置事务管理器 -->
<bean id="transactionManager_oracle" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory_oracle"/>
</property>
</bean>
<!-- 配置事务的传播特性 -->
<tx:advice id="txAdvice_oracle" transaction-manager="transactionManager_oracle">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED"/>
<tx:method name="save" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 那些类的哪些方法参与事务 -->
<aop:config>
<aop:pointcut id="allManagerMethod_oracle" expression="execution(* service.*.*(..))"/>
<aop:advisor pointcut-ref="allManagerMethod_oracle" advice-ref="txAdvice_oracle"/>
</aop:config>
<!-- 使Spring关注Annotation -->
<context:annotation-config />
<!-- 让Spring通过自动扫描来查询和管理Bean -->
<context:component-scan base-package ="*" />
</beans>
2、配置mysql数据源spring-mysql:
跟oracle相同,只是去掉“配置注解进行实体映射那两行代码”:
<!-- 使Spring关注Annotation -->
<context:annotation-config />
<!-- 让Spring通过自动扫描来查询和管理Bean -->
<context:component-scan base-package ="*" />
事务传播特性要分开分别配置。
3、在Dao层使用SessionFactory
@Repository("stuDao")
public class StuDaoImpl extends HibernateDaoSupport implements StuDao {
//注入HibernateSession,这里是关键,不同的dao使用不同的sessionFactory。
//当然,可以把这里抽象出来放到一个abstractDao里面,随意了。
@Resource(name="sessionFactory_mysql")
public void setSuperSessionFactory(SessionFactory sessionFactory){
super .setSessionFactory(sessionFactory);
}
public void add(Stu stu) {
this.getHibernateTemplate().save(stu);
}
}
现在,在Manager层调用dao的时候完全按照老套路走就行了,没什么特别的地方了。遗憾的是,这个方法只能够让不同的数据库使用不同的事务边界,无法实现分布式事务,只能在同时调用两个不同的数据库的地方加锁进行控制。
第二种(推荐,可以实现分布式事务管理):
之所以写道第二种,是因为原理跟第一种差不多....只是用到一个中间小组件而已。
就是使用jOTM来进行分布式事务管理,听说spring3.0已经不支持了,我不知道是不是真的,我用的是spring2.5进行的配置,感觉这么好用的东西应该不会不支持,大家有兴趣可以试一下spring3.x。
1、下载jOTM的包
将所有包拿到项目里,去掉重复包,如log4j.jar等。
2、配置spring-jOTM.xml
这个配置文件里也是同方法一相同,配置多个sessionFactory,只不过把这些sessionFactory都交给jOTM去管理,我们只去使用jOTM提供的那个就行了,类似于代理的东东。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"
>
<!--使用xapool连接池,共两个-->
<bean id="dataSource_oracle" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource" destroy-method="shutdown">
<property name="dataSource">
<bean class="org.enhydra.jdbc.standard.StandardXADataSource" destroy-method="shutdown">
<property name="transactionManager" ref="jotm"/>
<property name="driverName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@//218.198.177.109:1521/orcl"/>
</bean>
</property>
<property name="user" value="roy"/>
<property name="password" value="roy"/>
</bean>
<bean id="dataSource_mysql" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource" destroy-method="shutdown">
<property name="dataSource">
<bean class="org.enhydra.jdbc.standard.StandardXADataSource" destroy-method="shutdown">
<property name="transactionManager" ref="jotm"/>
<property name="driverName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/stu"/>
</bean>
</property>
<property name="user" value="root"/>
<property name="password" value="56906950"/>
</bean>
<!-- 定义sessionFactory,共两个-->
<bean id="sessionFactory_oracle" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource_oracle"/>
<property name="annotatedClasses">
<list>
<value>model.User</value>
<value>model.Role</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.jdbc.fetch_size">30</prop>
<prop key="hibernate.jdbc.batch_size">30</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.connection.autocommit ">false</prop>
</props>
</property>
</bean>
<bean id="sessionFactory_mysql" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource_mysql"/>
<property name="annotatedClasses">
<list>
<value>model.Stu</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.jdbc.fetch_size">30</prop>
<prop key="hibernate.jdbc.batch_size">30</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.connection.autocommit ">false</prop>
</props>
</property>
</bean>
<!--声明jta -->
<bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean"/>
<!--定义jta事务管理器-->
<bean id="tsManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="userTransaction" ref="jotm"/>
</bean>
<!-- 配置事务传播特性 -->
<tx:advice id="txAdvice" transaction-manager="tsManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 那些类的哪些方法参与事务 -->
<aop:config>
<aop:advisor pointcut="execution(* service.*.*(..))" advice-ref="txAdvice"/>
</aop:config>
<!-- 使Spring关注Annotation -->
<context:annotation-config />
<!-- 让Spring通过自动扫描来查询和管理Bean -->
<context:component-scan base-package ="*" />
</beans>