用过spring的人都熟悉spring的事务管理机制,并且spring支持jta分布式事务,那么,我一直在想,能否在代码中动态的切换事务类型呢?如果当前要操作的多个表在同一个数据源上,就直接本地
事务好了,如果当前操作的表分别在不同的数据源上,就切换成spring里配置好的jta事务。也就是说,事务还是用spring的声明式事务,但是用代码手动的选取用哪一个,能不能这样呢??
我做了个测试,在测试中,配置了两个spring配置文件,一个是使用本地事务,并且只有一个数据源,另一个是jta事务,并且有两个数据源,它们分别如下:
applicationContext-sys.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"
- xsi:schemaLocation="
- http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
- <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
- <property name="locations">
- <list>
- <value>classpath*:conf/jdbc.properties</value>
- </list>
- </property>
- </bean>
- <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
- <property name="driverClassName" value="${driverClassName}" />
- <property name="url" value="${url}" />
- <property name="username" value="${username}" />
- <property name="password" value="${password}" />
- </bean>
- <bean id="sessionFactory"
- class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
- <property name="dataSource" ref="dataSource" />
- <property name="hibernateProperties">
- <props>
- <prop key="hibernate.dialect">
- ${dialect}
- </prop>
- <prop key="hibernate.default_batch_fetch_size">10</prop>
- <prop key="hibernate.max_fetch_depth">0</prop>
- <prop key="hibernate.show_sql">${show_sql}</prop>
- </props>
- </property>
- <property name="mappingDirectoryLocations">
- <list>
- <value>classpath*:/com/zhangweilin/po/</value>
- </list>
- </property>
- </bean>
- <bean id="txManager"
- class="org.springframework.orm.hibernate3.HibernateTransactionManager">
- <property name="sessionFactory" ref="sessionFactory" />
- <property name="nestedTransactionAllowed" value="true" />
- </bean>
- <tx:annotation-driven transaction-manager="txManager" />
- <aop:config>
- <aop:pointcut id="commonServiceOperation"
- expression="execution(* com.zhangweilin.service.*Service.*(..))" />
- <aop:advisor pointcut-ref="commonServiceOperation"
- advice-ref="txAdvice" />
- </aop:config>
- <tx:advice id="txAdvice" transaction-manager="txManager">
- <tx:attributes>
- <tx:method name="init*" rollback-for="Exception" />
- <tx:method name="save*" rollback-for="Exception" />
- <tx:method name="create*" rollback-for="Exception" />
- <tx:method name="login*" rollback-for="Exception" />
- <tx:method name="add*" rollback-for="Exception" />
- <tx:method name="update*" rollback-for="Exception" />
- <tx:method name="modify*" rollback-for="Exception" />
- <tx:method name="delete*" rollback-for="Exception" />
- <tx:method name="remove*" rollback-for="Exception" />
- <tx:method name="clear*" rollback-for="Exception" />
- <tx:method name="register*" rollback-for="Exception" />
- <tx:method name="*" read-only="true" />
- </tx:attributes>
- </tx:advice>
- <!--
- <bean id="ehcacheManager"
- class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
- <property name="configLocation" value="/WEB-INF/classes/ehcache.xml" />
- </bean>
- -->
- <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
- <property name="dataSource" ref="dataSource"/>
- </bean>
- <bean id="dao" class="com.zhangweilin.core.DaoImpl">
- <property name="sessionFactory" ref="sessionFactory" />
- <property name="jdbcTemplate" ref="jdbcTemplate" />
- </bean>
- </beans>
<?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" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath*:conf/jdbc.properties</value> </list> </property> </bean> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="${driverClassName}" /> <property name="url" value="${url}" /> <property name="username" value="${username}" /> <property name="password" value="${password}" /> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect"> ${dialect} </prop> <prop key="hibernate.default_batch_fetch_size">10</prop> <prop key="hibernate.max_fetch_depth">0</prop> <prop key="hibernate.show_sql">${show_sql}</prop> </props> </property> <property name="mappingDirectoryLocations"> <list> <value>classpath*:/com/zhangweilin/po/</value> </list> </property> </bean> <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> <property name="nestedTransactionAllowed" value="true" /> </bean> <tx:annotation-driven transaction-manager="txManager" /> <aop:config> <aop:pointcut id="commonServiceOperation" expression="execution(* com.zhangweilin.service.*Service.*(..))" /> <aop:advisor pointcut-ref="commonServiceOperation" advice-ref="txAdvice" /> </aop:config> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="init*" rollback-for="Exception" /> <tx:method name="save*" rollback-for="Exception" /> <tx:method name="create*" rollback-for="Exception" /> <tx:method name="login*" rollback-for="Exception" /> <tx:method name="add*" rollback-for="Exception" /> <tx:method name="update*" rollback-for="Exception" /> <tx:method name="modify*" rollback-for="Exception" /> <tx:method name="delete*" rollback-for="Exception" /> <tx:method name="remove*" rollback-for="Exception" /> <tx:method name="clear*" rollback-for="Exception" /> <tx:method name="register*" rollback-for="Exception" /> <tx:method name="*" read-only="true" /> </tx:attributes> </tx:advice> <!-- <bean id="ehcacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> <property name="configLocation" value="/WEB-INF/classes/ehcache.xml" /> </bean> --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="dao" class="com.zhangweilin.core.DaoImpl"> <property name="sessionFactory" ref="sessionFactory" /> <property name="jdbcTemplate" ref="jdbcTemplate" /> </bean> </beans>
另一个:applicationContext-test-jotm.xml(jta事务,并且有两个数据源)
- <?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"
- xsi:schemaLocation="
- http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
- <!-- jotm配置 -->
- <bean id="mysqldatasource" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource">
- <property name="dataSource">
- <!--内部XA数据源 -->
- <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://172.16.18.75:3306/?useUnicode=true&characterEncoding=UTF-8" />
- </bean>
- </property>
- <property name="user" value="root" />
- <property name="password" value="123456" />
- </bean>
- <bean id="h2datasource" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource">
- <property name="dataSource">
- <!--内部XA数据源 -->
- <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/pay?useUnicode=true&characterEncoding=UTF-8" />
- </bean>
- </property>
- <property name="user" value="zwllxs" />
- <property name="password" value="123456" />
- </bean>
- <bean id="sessionFactory1" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
- <property name="dataSource" ref="mysqldatasource"/>
- <property name="mappingDirectoryLocations">
- <list>
- <value>classpath*:/com/zhangweilin/po/</value>
- </list>
- </property>
- <property name="hibernateProperties">
- <props>
- <prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop>
- <prop key="hibernate.show_sql">true</prop>
- <prop key="hibernate.jdbc.batch_size">50</prop>
- <prop key="hibernate.cache.use_query_cache">true</prop>
- <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
- </props>
- </property>
- <!--
- <property name="jtaTransactionManager">
- <ref bean="jotm" />
- </property>
- -->
- </bean>
- <bean id="sessionFactory2" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
- <property name="dataSource" ref="h2datasource"/>
- <property name="mappingDirectoryLocations">
- <list>
- <value>classpath*:/com/zhangweilin/po/</value>
- </list>
- </property>
- <property name="hibernateProperties">
- <props>
- <prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop>
- <prop key="hibernate.show_sql">true</prop>
- <prop key="hibernate.jdbc.batch_size">50</prop>
- <prop key="hibernate.cache.use_query_cache">true</prop>
- <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
- </props>
- </property>
- <!--
- <property name="jtaTransactionManager">
- <ref bean="jotm" />
- </property>
- -->
- </bean>
- <bean id="dao1" class="com.zhangweilin.core.DaoImpl">
- <property name="sessionFactory" ref="sessionFactory1" />
- </bean>
- <bean id="dao2" class="com.zhangweilin.core.DaoImpl">
- <property name="sessionFactory" ref="sessionFactory2" />
- </bean>
- <bean id="loginLogService2" class="com.zhangweilin.service.impl.LoginLogServiceImpl">
- <property name="dao" ref="dao1" />
- </bean>
- <bean id="articleService2" class="com.zhangweilin.service.impl.ArticleServiceImpl">
- <property name="dao" ref="dao2" />
- <property name="loginLogService" ref="loginLogService2" />
- </bean>
- <bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean" />
- <!-- jtatransactionmanager容器 -->
- <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
- <property name="userTransaction" ref="jotm" />
- </bean>
- <tx:advice id="txAdvice2" transaction-manager="transactionManager">
- <tx:attributes>
- <tx:method name="add*" propagation="REQUIRED" />
- <tx:method name="upd*" propagation="REQUIRED" />
- <tx:method name="del*" propagation="REQUIRED" />
- <tx:method name="*" read-only="true" />
- </tx:attributes>
- </tx:advice>
- <aop:config>
- <aop:pointcut id="interceptorPointCuts" expression="execution(* com.zhangweilin.service.*Service.*(..))" />
- <aop:advisor id="jotmAdvisor" advice-ref="txAdvice2" pointcut-ref="interceptorPointCuts" />
- </aop:config>
- </beans>
<?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" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"> <!-- jotm配置 --> <bean id="mysqldatasource" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource"> <property name="dataSource"> <!--内部XA数据源 --> <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://172.16.18.75:3306/?useUnicode=true&characterEncoding=UTF-8" /> </bean> </property> <property name="user" value="root" /> <property name="password" value="123456" /> </bean> <bean id="h2datasource" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource"> <property name="dataSource"> <!--内部XA数据源 --> <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/pay?useUnicode=true&characterEncoding=UTF-8" /> </bean> </property> <property name="user" value="zwllxs" /> <property name="password" value="123456" /> </bean> <bean id="sessionFactory1" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="mysqldatasource"/> <property name="mappingDirectoryLocations"> <list> <value>classpath*:/com/zhangweilin/po/</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.jdbc.batch_size">50</prop> <prop key="hibernate.cache.use_query_cache">true</prop> <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop> </props> </property> <!-- <property name="jtaTransactionManager"> <ref bean="jotm" /> </property> --> </bean> <bean id="sessionFactory2" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="h2datasource"/> <property name="mappingDirectoryLocations"> <list> <value>classpath*:/com/zhangweilin/po/</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.jdbc.batch_size">50</prop> <prop key="hibernate.cache.use_query_cache">true</prop> <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop> </props> </property> <!-- <property name="jtaTransactionManager"> <ref bean="jotm" /> </property> --> </bean> <bean id="dao1" class="com.zhangweilin.core.DaoImpl"> <property name="sessionFactory" ref="sessionFactory1" /> </bean> <bean id="dao2" class="com.zhangweilin.core.DaoImpl"> <property name="sessionFactory" ref="sessionFactory2" /> </bean> <bean id="loginLogService2" class="com.zhangweilin.service.impl.LoginLogServiceImpl"> <property name="dao" ref="dao1" /> </bean> <bean id="articleService2" class="com.zhangweilin.service.impl.ArticleServiceImpl"> <property name="dao" ref="dao2" /> <property name="loginLogService" ref="loginLogService2" /> </bean> <bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean" /> <!-- jtatransactionmanager容器 --> <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"> <property name="userTransaction" ref="jotm" /> </bean> <tx:advice id="txAdvice2" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="add*" propagation="REQUIRED" /> <tx:method name="upd*" propagation="REQUIRED" /> <tx:method name="del*" propagation="REQUIRED" /> <tx:method name="*" read-only="true" /> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="interceptorPointCuts" expression="execution(* com.zhangweilin.service.*Service.*(..))" /> <aop:advisor id="jotmAdvisor" advice-ref="txAdvice2" pointcut-ref="interceptorPointCuts" /> </aop:config> </beans>
再附上关键的service:
ArticleService.java:
- /**
- * 文章
- * @author zhangweilin
- *
- */
- public interface ArticleService extends Service<Article>
- {
- /**
- * 测试同时添加分布在不同库上的Article和LoginLog;
- * @param article
- * @throws Exception
- */
- public void addArticle(Article article,String name) throws Exception;
- public void setName(String name);
- public String getName();
- }
/** * 文章 * @author zhangweilin * */ public interface ArticleService extends Service<Article> { /** * 测试同时添加分布在不同库上的Article和LoginLog; * @param article * @throws Exception */ public void addArticle(Article article,String name) throws Exception; public void setName(String name); public String getName(); }
ArticleServiceImpl.java:
- /**
- * 文章
- * @author zhangweilin
- *
- */
- public class ArticleServiceImpl extends ServiceImpl<Article> implements ArticleService
- {
- private LoginLogService loginLogService;
- private String name="张伟林";
- /**
- * @param loginLogService the loginLogService to set
- */
- public void setLoginLogService(LoginLogService loginLogService)
- {
- System.out.println("setLoginLogService: "+loginLogService);
- this.loginLogService = loginLogService;
- }
- @Override
- public void addArticle(Article article,String name) throws Exception
- {
- save(article);
- LoginLog loginLog=new LoginLog();
- loginLog.setAddress(name);
- loginLog.setAdmin(null);
- loginLog.setIp("11.11.11.11");
- // loginLog.setLoginTime(new Date());
- System.out.println(" 添加");
- loginLogService.save(loginLog);
- System.out.println("操作结束");
- }
- @Override
- public String getName()
- {
- System.out.println("getName: "+name);
- return this.name;
- }
- @Override
- public void setName(String name)
- {
- System.out.println("setName: "+name);
- this.name=name;
- }
/** * 文章 * @author zhangweilin * */ public class ArticleServiceImpl extends ServiceImpl<Article> implements ArticleService { private LoginLogService loginLogService; private String name="张伟林"; /** * @param loginLogService the loginLogService to set */ public void setLoginLogService(LoginLogService loginLogService) { System.out.println("setLoginLogService: "+loginLogService); this.loginLogService = loginLogService; } @Override public void addArticle(Article article,String name) throws Exception { save(article); LoginLog loginLog=new LoginLog(); loginLog.setAddress(name); loginLog.setAdmin(null); loginLog.setIp("11.11.11.11"); // loginLog.setLoginTime(new Date()); System.out.println(" 添加"); loginLogService.save(loginLog); System.out.println("操作结束"); } @Override public String getName() { System.out.println("getName: "+name); return this.name; } @Override public void setName(String name) { System.out.println("setName: "+name); this.name=name; }
再附上测试代码:
- package com.zhangweilin.test;
- import java.util.Date;
- import org.aopalliance.aop.Advice;
- import org.junit.BeforeClass;
- import org.junit.Test;
- import org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor;
- import org.springframework.beans.factory.BeanFactory;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- import org.springframework.orm.hibernate3.HibernateTransactionManager;
- import org.springframework.transaction.PlatformTransactionManager;
- import org.springframework.transaction.jta.JtaTransactionManager;
- import org.springframework.transaction.support.AbstractPlatformTransactionManager;
- import com.zhangweilin.po.Article;
- import com.zhangweilin.service.ArticleService;
- import com.zhangweilin.service.LoginLogService;
- /**
- * 测试在代码中动态切换spring的事务策略
- * @author wlzhang
- *
- */
- public class TestServiceJotm
- {
- private static BeanFactory fac;
- private static LoginLogService loginLogService2;
- private static ArticleService articleService;
- private static HibernateTransactionManager hibernateTransactionManager;
- private static PlatformTransactionManager platformTransactionManager;
- private static AbstractPlatformTransactionManager abstractPlatformTransactionManager;
- /**
- * 初始化环境
- */
- @BeforeClass
- public static void init()
- {
- try
- {
- fac = new ClassPathXmlApplicationContext("conf\\spring\\applicationContext*.xml");
- loginLogService2 = (LoginLogService) fac.getBean("loginLogService2");
- articleService = (ArticleService) fac.getBean("articleService2");
- }
- catch (Throwable t)
- {
- t.printStackTrace();
- }
- }
- /**
- * 尝试切换事务管理器
- */
- @Test
- public void testChangeTransactionManager()
- {
- //先测试单例效应
- System.out.println("articleService.name: "+articleService.getName());//第一次获取name值
- articleService.setName("伟林张");
- articleService = (ArticleService) fac.getBean("articleService2");
- System.out.println("articleService.name2: "+articleService.getName());//第二次获取name值,如果spring配置采用的单例,那么此获取的就是修改后的name值
- //尝试着切换事务管理器
- Object jotm=fac.getBean("jotm");
- System.out.println("jotm: "+jotm+" , "+jotm.getClass());
- Object interceptorPointCuts=fac.getBean("interceptorPointCuts");
- System.out.println("interceptorPointCuts: "+interceptorPointCuts+" , "+interceptorPointCuts.getClass());
- DefaultBeanFactoryPointcutAdvisor jotmAdvisor=(DefaultBeanFactoryPointcutAdvisor) fac.getBean("jotmAdvisor");
- System.out.println("jotmAdvisor: "+jotmAdvisor+" , "+jotmAdvisor.getClass());
- hibernateTransactionManager = (HibernateTransactionManager) fac.getBean("txManager");
- System.out.println("hibernateTransactionManager: "+hibernateTransactionManager);
- platformTransactionManager = (PlatformTransactionManager) fac.getBean("transactionManager");
- System.out.println("platformTransactionManager: "+platformTransactionManager);
- System.out.println("切换前");
- if (platformTransactionManager instanceof JtaTransactionManager)
- {
- System.out.println("当前事务: JtaTransactionManager");
- JtaTransactionManager jtaTransactionManager=(JtaTransactionManager) platformTransactionManager;
- System.out.println("转成jtaTransactionManager: "+jtaTransactionManager);
- System.out.println("准备切换");
- platformTransactionManager=hibernateTransactionManager; //尝试将hibernate事务管理器赋给jta事务管理器
- System.out.println("尝试切换成功:platformTransactionManager: "+platformTransactionManager);
- }
- else if (platformTransactionManager instanceof HibernateTransactionManager)
- {
- System.out.println("当前事务: HibernateTransactionManager");
- HibernateTransactionManager jtaTransactionManager=(HibernateTransactionManager) platformTransactionManager;
- System.out.println("转成jtaTransactionManager: "+jtaTransactionManager);
- }
- System.out.println("切换后");
- platformTransactionManager = (PlatformTransactionManager) fac.getBean("transactionManager");
- System.out.println("platformTransactionManager: "+platformTransactionManager);
- if (platformTransactionManager instanceof JtaTransactionManager)
- {
- //在“切换”后,还是调用的这里。说明切换不成功
- System.out.println("当前事务: JtaTransactionManager");
- JtaTransactionManager jtaTransactionManager=(JtaTransactionManager) platformTransactionManager;
- System.out.println("转成jtaTransactionManager: "+jtaTransactionManager);
- System.out.println("准备切换");
- platformTransactionManager=hibernateTransactionManager;
- System.out.println("尝试切换成功");
- }
- else if (platformTransactionManager instanceof HibernateTransactionManager)
- {
- System.out.println("当前事务: HibernateTransactionManager");
- HibernateTransactionManager hibernateTransactionManager=(HibernateTransactionManager) platformTransactionManager;
- System.out.println("转成HibernateTransactionManager: "+hibernateTransactionManager);
- }
- //结果,切换引用是行不通的,而更改现有的单例对象的值是可以的
- }
- /**
- * 切换事务管理器失败,尝试切换 Advisor
- */
- @Test
- public void testChangeAdvisor()
- {
- DefaultBeanFactoryPointcutAdvisor jotmAdvisor=(DefaultBeanFactoryPointcutAdvisor) fac.getBean("jotmAdvisor");
- System.out.println("jotmAdvisor: "+jotmAdvisor+" , "+jotmAdvisor.getClass());
- System.out.println("jotmAdvisor: "+jotmAdvisor.getAdviceBeanName());
- jotmAdvisor.setAdviceBeanName("txAdvice");
- jotmAdvisor=(DefaultBeanFactoryPointcutAdvisor) fac.getBean("jotmAdvisor");
- System.out.println("jotmAdvisor: "+jotmAdvisor.getAdviceBeanName());//adviceBeanName名被更改了,。幻想着切换事务的可行性增大了
- // Advice advice=jotmAdvisor.getAdvice();
- }
- /**
- * 先不做切换的数据操作,完全符合自己预期
- * @throws Exception
- */
- @Test
- public void testArticleService() throws Exception
- {
- System.out.println("articleService: "+articleService);
- Article article=new Article();
- article.setAddTime(new Date());
- article.setContent("太好了");
- article.setTitle("jotm测试下");
- article.setType(20);
- articleService.addArticle(article,"上海");
- }
- /**
- * Advisor看起来貌似切换成功了,所以正式尝试切换事务来增加数据,测试中保证让数据库端一个表不能正常插入数据,以测试事务的一致性
- */
- @Test
- public void testChangeTrancation()
- {
- DefaultBeanFactoryPointcutAdvisor jotmAdvisor=(DefaultBeanFactoryPointcutAdvisor) fac.getBean("jotmAdvisor");
- System.out.println("使用默认事务:jta事务");
- Article article=new Article();
- article.setAddTime(new Date());
- article.setContent("使用默认事务:jta事务太好了");
- article.setTitle("使用默认事务:jta事务_jotm测试下");
- article.setType(20);
- try
- {
- articleService.addArticle(article,"使用默认事务:jta事务_上海");
- }
- catch (Exception e)
- {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- jotmAdvisor.setAdviceBeanName("txAdvice2"); //尝试以更改adviceBeanName的方式修改指定的事务
- jotmAdvisor=(DefaultBeanFactoryPointcutAdvisor) fac.getBean("jotmAdvisor");
- System.out.println("事务已切换,使用本地事务");
- article=new Article();
- article.setAddTime(new Date());
- article.setContent("事务已切换,使用本地事务_事务太好了");
- article.setTitle("事务已切换,使用本地事务_jotm测试下");
- article.setType(20);
- try
- {
- articleService.addArticle(article,"事务已切换,使用本地事务_上海");
- }
- catch (Exception e)
- {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- /**
- * 切换事务失败,事务的一致性并没有符合自己的预期。经过查询文档,关于setAdviceBeanName方法的描述如下,
- * Specify the name of the advice bean that this advisor should refer to.
- An instance of the specified bean will be obtained on first access of this advisor's advice. This advisor will only ever obtain at most one single instance of
- the advice bean, caching the instance for the lifetime of the advisor.
- * 只在第一次访问时才创建,之后不能更改,哎,杯具
- */
- }
package com.zhangweilin.test; import java.util.Date; import org.aopalliance.aop.Advice; import org.junit.BeforeClass; import org.junit.Test; import org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor; import org.springframework.beans.factory.BeanFactory; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.orm.hibernate3.HibernateTransactionManager; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.jta.JtaTransactionManager; import org.springframework.transaction.support.AbstractPlatformTransactionManager; import com.zhangweilin.po.Article; import com.zhangweilin.service.ArticleService; import com.zhangweilin.service.LoginLogService; /** * 测试在代码中动态切换spring的事务策略 * @author wlzhang * */ public class TestServiceJotm { private static BeanFactory fac; private static LoginLogService loginLogService2; private static ArticleService articleService; private static HibernateTransactionManager hibernateTransactionManager; private static PlatformTransactionManager platformTransactionManager; private static AbstractPlatformTransactionManager abstractPlatformTransactionManager; /** * 初始化环境 */ @BeforeClass public static void init() { try { fac = new ClassPathXmlApplicationContext("conf\\spring\\applicationContext*.xml"); loginLogService2 = (LoginLogService) fac.getBean("loginLogService2"); articleService = (ArticleService) fac.getBean("articleService2"); } catch (Throwable t) { t.printStackTrace(); } } /** * 尝试切换事务管理器 */ @Test public void testChangeTransactionManager() { //先测试单例效应 System.out.println("articleService.name: "+articleService.getName());//第一次获取name值 articleService.setName("伟林张"); articleService = (ArticleService) fac.getBean("articleService2"); System.out.println("articleService.name2: "+articleService.getName());//第二次获取name值,如果spring配置采用的单例,那么此获取的就是修改后的name值 //尝试着切换事务管理器 Object jotm=fac.getBean("jotm"); System.out.println("jotm: "+jotm+" , "+jotm.getClass()); Object interceptorPointCuts=fac.getBean("interceptorPointCuts"); System.out.println("interceptorPointCuts: "+interceptorPointCuts+" , "+interceptorPointCuts.getClass()); DefaultBeanFactoryPointcutAdvisor jotmAdvisor=(DefaultBeanFactoryPointcutAdvisor) fac.getBean("jotmAdvisor"); System.out.println("jotmAdvisor: "+jotmAdvisor+" , "+jotmAdvisor.getClass()); hibernateTransactionManager = (HibernateTransactionManager) fac.getBean("txManager"); System.out.println("hibernateTransactionManager: "+hibernateTransactionManager); platformTransactionManager = (PlatformTransactionManager) fac.getBean("transactionManager"); System.out.println("platformTransactionManager: "+platformTransactionManager); System.out.println("切换前"); if (platformTransactionManager instanceof JtaTransactionManager) { System.out.println("当前事务: JtaTransactionManager"); JtaTransactionManager jtaTransactionManager=(JtaTransactionManager) platformTransactionManager; System.out.println("转成jtaTransactionManager: "+jtaTransactionManager); System.out.println("准备切换"); platformTransactionManager=hibernateTransactionManager; //尝试将hibernate事务管理器赋给jta事务管理器 System.out.println("尝试切换成功:platformTransactionManager: "+platformTransactionManager); } else if (platformTransactionManager instanceof HibernateTransactionManager) { System.out.println("当前事务: HibernateTransactionManager"); HibernateTransactionManager jtaTransactionManager=(HibernateTransactionManager) platformTransactionManager; System.out.println("转成jtaTransactionManager: "+jtaTransactionManager); } System.out.println("切换后"); platformTransactionManager = (PlatformTransactionManager) fac.getBean("transactionManager"); System.out.println("platformTransactionManager: "+platformTransactionManager); if (platformTransactionManager instanceof JtaTransactionManager) { //在“切换”后,还是调用的这里。说明切换不成功 System.out.println("当前事务: JtaTransactionManager"); JtaTransactionManager jtaTransactionManager=(JtaTransactionManager) platformTransactionManager; System.out.println("转成jtaTransactionManager: "+jtaTransactionManager); System.out.println("准备切换"); platformTransactionManager=hibernateTransactionManager; System.out.println("尝试切换成功"); } else if (platformTransactionManager instanceof HibernateTransactionManager) { System.out.println("当前事务: HibernateTransactionManager"); HibernateTransactionManager hibernateTransactionManager=(HibernateTransactionManager) platformTransactionManager; System.out.println("转成HibernateTransactionManager: "+hibernateTransactionManager); } //结果,切换引用是行不通的,而更改现有的单例对象的值是可以的 } /** * 切换事务管理器失败,尝试切换 Advisor */ @Test public void testChangeAdvisor() { DefaultBeanFactoryPointcutAdvisor jotmAdvisor=(DefaultBeanFactoryPointcutAdvisor) fac.getBean("jotmAdvisor"); System.out.println("jotmAdvisor: "+jotmAdvisor+" , "+jotmAdvisor.getClass()); System.out.println("jotmAdvisor: "+jotmAdvisor.getAdviceBeanName()); jotmAdvisor.setAdviceBeanName("txAdvice"); jotmAdvisor=(DefaultBeanFactoryPointcutAdvisor) fac.getBean("jotmAdvisor"); System.out.println("jotmAdvisor: "+jotmAdvisor.getAdviceBeanName());//adviceBeanName名被更改了,。幻想着切换事务的可行性增大了 // Advice advice=jotmAdvisor.getAdvice(); } /** * 先不做切换的数据操作,完全符合自己预期 * @throws Exception */ @Test public void testArticleService() throws Exception { System.out.println("articleService: "+articleService); Article article=new Article(); article.setAddTime(new Date()); article.setContent("太好了"); article.setTitle("jotm测试下"); article.setType(20); articleService.addArticle(article,"上海"); } /** * Advisor看起来貌似切换成功了,所以正式尝试切换事务来增加数据,测试中保证让数据库端一个表不能正常插入数据,以测试事务的一致性 */ @Test public void testChangeTrancation() { DefaultBeanFactoryPointcutAdvisor jotmAdvisor=(DefaultBeanFactoryPointcutAdvisor) fac.getBean("jotmAdvisor"); System.out.println("使用默认事务:jta事务"); Article article=new Article(); article.setAddTime(new Date()); article.setContent("使用默认事务:jta事务太好了"); article.setTitle("使用默认事务:jta事务_jotm测试下"); article.setType(20); try { articleService.addArticle(article,"使用默认事务:jta事务_上海"); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } jotmAdvisor.setAdviceBeanName("txAdvice2"); //尝试以更改adviceBeanName的方式修改指定的事务 jotmAdvisor=(DefaultBeanFactoryPointcutAdvisor) fac.getBean("jotmAdvisor"); System.out.println("事务已切换,使用本地事务"); article=new Article(); article.setAddTime(new Date()); article.setContent("事务已切换,使用本地事务_事务太好了"); article.setTitle("事务已切换,使用本地事务_jotm测试下"); article.setType(20); try { articleService.addArticle(article,"事务已切换,使用本地事务_上海"); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } /** * 切换事务失败,事务的一致性并没有符合自己的预期。经过查询文档,关于setAdviceBeanName方法的描述如下, * Specify the name of the advice bean that this advisor should refer to. An instance of the specified bean will be obtained on first access of this advisor's advice. This advisor will only ever obtain at most one single instance of the advice bean, caching the instance for the lifetime of the advisor. * 只在第一次访问时才创建,之后不能更改,哎,杯具 */ }
不知道有谁能提供更好的测试方案,如果有在代码中切换spring里的事务的方案更好
http://zwllxs.iteye.com/blog/1004081
相关推荐
在Spring中,事务管理分为编程式和声明式两种方式。本篇文章将详细解释Spring事务管理的流程,以及如何通过时序图来理解这一过程。 首先,我们来看Spring事务的流程。当一个事务开始时,通常会经历以下步骤: 1. *...
在Spring中,事务的传播行为有七种: - `REQUIRED`:默认行为,如果当前没有事务,则新建一个;如果已经存在事务,则加入到当前事务。 - `SUPPORTS`:如果当前存在事务,则支持事务;如果没有事务,则不开启。 - `...
在Spring中,声明式事务主要通过AOP(面向切面编程)实现。当一个方法被标记为需要事务管理时,Spring会自动在方法调用前后处理事务的开始、提交、回滚等操作。例如,我们可以通过`@Transactional`注解来标记一个...
在Spring中,事务管理分为两种模式:声明式事务管理和编程式事务管理。声明式事务管理通过配置元数据(如XML或注解)来控制事务边界,而编程式事务管理则通过TransactionTemplate或PlatformTransactionManager接口...
在Spring中,AOP可以通过基于XML的配置或者基于注解的方式实现。 ##### 2.2 使用Spring AOP增强DAO 在客户管理系统中,为了实现对所有DAO类中以`save`开头的方法进行权限验证,可以使用Spring AOP的注解方式来实现...
在本文中,我们将深入探讨如何实现动态数据源切换,支持Spring声明式事务管理,并讨论多数据源回滚策略。以下是对这些知识点的详细说明: 1. **动态数据源切换**: - 通过AspectJ实现数据源的动态切换,可以设置在...
在Spring中,声明式事务管理依赖于AOP(面向切面编程)来实现。首先,需要配置一个事务管理器,通常使用`DataSourceTransactionManager`,它与数据源`dataSource`关联。然后,通过`<tx:annotation-driven>`标签启用...
在Spring框架中,事务管理是核心特性之一,它使得开发者能够在多操作数据库时保持数据的一致性和完整性。本文将深入探讨Spring事务管理的源码,理解其背后的实现机制。 首先,Spring事务管理有两种主要模式:编程式...
在Spring中,我们可以配置事务的传播行为,比如REQUIRED(默认,如果当前存在事务,则加入当前事务,否则新建一个事务)、PROPAGATION_SUPPORTS(如果当前存在事务,则加入,否则不开启事务)、PROPAGATION_REQUIRES...
在本项目中,我们将探讨如何利用MyBatis与Spring框架实现动态切换数据源的功能。首先,我们需要理解MyBatis和Spring的基本概念以及它们如何协同工作。 MyBatis是一个优秀的持久层框架,它简化了Java与数据库之间的...
在Spring框架中,数据库动态切换是一项关键功能,它允许应用程序根据特定条件或需求在多个数据库之间灵活地切换。这在处理分布式系统、多租户应用或者数据隔离等场景时非常有用。下面我们将深入探讨这个主题。 首先...
这些隔离级别决定了并发环境中事务间的可见性和一致性。 - **传播行为**:定义了在不同情况下事务应该如何传播。例如,PROPAGATION_REQUIRED表示如果当前存在事务,则加入该事务;如果没有,就创建一个新的事务。 ...
"Spring动态切换多数据源Demo"是一个示例项目,它展示了如何在Spring中实现灵活的数据源切换。 首先,我们需要了解Spring中的数据源。在Spring中,数据源(DataSource)是Java中定义的javax.sql.DataSource接口的...
1. **Spring声明式事务管理**:这是Spring中最常用的一种事务管理方式,通过在方法上添加@Transactional注解,Spring容器会在方法执行前后自动进行事务的开启、提交、回滚等操作。例如,在业务服务类的方法上标注此...
这篇文章将深入探讨如何在Spring中运用策略模式,并结合源码分析其工作原理。 策略模式的核心在于将算法封装到具有共同接口的独立类中,使得它们可以相互替换。在Spring框架中,策略模式常用于处理不同策略的配置和...
Spring事务操作示例(四种方式),包含完整代码和数据库文件(基于MySQL,在项目sql文件夹中),可运行,学习Spring事务详见博客:http://blog.csdn.net/daijin888888/article/details/51822257
在Spring中,默认情况下如果目标对象实现了接口,则使用JDK动态代理;如果目标对象没有实现接口,则使用CGLIB代理。代理类在执行方法前后加入事务处理逻辑,从而实现事务管理。 异常是导致事务失效的常见原因之一。...
2. 声明式事务管理:这是 Spring 的一大特色,它允许开发者在配置文件或注解中声明事务的边界,而不必在业务代码中显式管理事务。Spring 支持在 XML 配置文件中使用 `<tx:advice>` 和 `<tx:annotation-driven>` 元素...
Spring事务原理是指Spring框架中的一种机制,用于管理事务,并提供了多种配置方式。事务是指一系列的操作,作为一个整体执行,如果其中某个操作失败,整个事务将回滚。Spring事务原理围绕着两个核心:...
在Spring中,事务管理器(如DataSourceTransactionManager或HibernateTransactionManager)是核心组件,它负责与底层数据库进行交互,执行事务的开始、提交、回滚等操作。开发者可以在XML配置文件中定义事务管理器,...