使用JTOM实现多数据源的分布式事务管理
使用spring和mybatis可以很方便的实现一个数据源的事务管理,但是如果需要同时对多个数据源进行事务控制,并且不想使用重量级容器提供的机制的话,可以使用JOTM达到目的.
下面介绍JTOM整合spring实现多数据源动态切换及分布式事务管理
1.首先,如果不是maven项目需加入jtom整合需要的jar包并buildpath
2.首先创建 JotmFactoryBean.java
package com.crs.ticket.utils.jotmutil; import javax.naming.NamingException; import javax.transaction.SystemException; import org.objectweb.jotm.Current; import org.objectweb.jotm.Jotm; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.FactoryBean; /** * @author pypua */ @SuppressWarnings("rawtypes") public class JotmFactoryBean implements FactoryBean, DisposableBean { private Current jotmCurrent; private Jotm jotm; public JotmFactoryBean() throws NamingException { // Check for already active JOTM instance. this.jotmCurrent = Current.getCurrent(); // If none found, create new local JOTM instance. if (this.jotmCurrent == null) { // Only for use within the current Spring context: // local, not bound to registry. this.jotm = new Jotm(true, false); this.jotmCurrent = Current.getCurrent(); } } public void setDefaultTimeout(int defaultTimeout) { this.jotmCurrent.setDefaultTimeout(defaultTimeout); // The following is a JOTM oddity: should be used for demarcation // transaction only, // but is required here in order to actually get rid of JOTM's default // (60 seconds). try { this.jotmCurrent.setTransactionTimeout(defaultTimeout); } catch (SystemException ex) { // should never happen } } public Jotm getJotm() { return this.jotm; } public Object getObject() { return this.jotmCurrent; } public Class getObjectType() { return this.jotmCurrent.getClass(); } public boolean isSingleton() { return true; } public void destroy() { if (this.jotm != null) { this.jotm.stop(); } } }
2.创建CustomSqlSessionTemplate.java
package com.crs.ticket.utils.jotmutil; import static java.lang.reflect.Proxy.newProxyInstance; import static org.apache.ibatis.reflection.ExceptionUtil.unwrapThrowable; import static org.mybatis.spring.SqlSessionUtils.closeSqlSession; import static org.mybatis.spring.SqlSessionUtils.getSqlSession; import static org.mybatis.spring.SqlSessionUtils.isSqlSessionTransactional; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.sql.Connection; import java.util.List; import java.util.Map; import org.apache.ibatis.exceptions.PersistenceException; import org.apache.ibatis.executor.BatchResult; import org.apache.ibatis.session.Configuration; import org.apache.ibatis.session.ExecutorType; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.MyBatisExceptionTranslator; import org.mybatis.spring.SqlSessionTemplate; import org.springframework.dao.support.PersistenceExceptionTranslator; import org.springframework.util.Assert; /** * <b>function:</b> 继承SqlSessionTemplate 重写相关方法 */ public class CustomSqlSessionTemplate extends SqlSessionTemplate { private final SqlSessionFactory sqlSessionFactory; private final ExecutorType executorType; private final SqlSession sqlSessionProxy; private final PersistenceExceptionTranslator exceptionTranslator; private Map<Object, SqlSessionFactory> targetSqlSessionFactorys; private SqlSessionFactory defaultTargetSqlSessionFactory; public void setTargetSqlSessionFactorys(Map<Object, SqlSessionFactory> targetSqlSessionFactorys) { this.targetSqlSessionFactorys = targetSqlSessionFactorys; } public void setDefaultTargetSqlSessionFactory(SqlSessionFactory defaultTargetSqlSessionFactory) { this.defaultTargetSqlSessionFactory = defaultTargetSqlSessionFactory; } public CustomSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) { this(sqlSessionFactory, sqlSessionFactory.getConfiguration().getDefaultExecutorType()); } public CustomSqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType) { this(sqlSessionFactory, executorType, new MyBatisExceptionTranslator(sqlSessionFactory.getConfiguration() .getEnvironment().getDataSource(), true)); } public CustomSqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) { super(sqlSessionFactory, executorType, exceptionTranslator); this.sqlSessionFactory = sqlSessionFactory; this.executorType = executorType; this.exceptionTranslator = exceptionTranslator; this.sqlSessionProxy = (SqlSession) newProxyInstance( SqlSessionFactory.class.getClassLoader(), new Class[] { SqlSession.class }, new SqlSessionInterceptor()); this.defaultTargetSqlSessionFactory = sqlSessionFactory; } @Override public SqlSessionFactory getSqlSessionFactory() { SqlSessionFactory targetSqlSessionFactory = targetSqlSessionFactorys.get(CustomerContextHolder.getContextType()); if (targetSqlSessionFactory != null) { return targetSqlSessionFactory; } else if (defaultTargetSqlSessionFactory != null) { return defaultTargetSqlSessionFactory; } else { Assert.notNull(targetSqlSessionFactorys, "Property 'targetSqlSessionFactorys' or 'defaultTargetSqlSessionFactory' are required"); Assert.notNull(defaultTargetSqlSessionFactory, "Property 'defaultTargetSqlSessionFactory' or 'targetSqlSessionFactorys' are required"); } return this.sqlSessionFactory; } @Override public Configuration getConfiguration() { return this.getSqlSessionFactory().getConfiguration(); } public ExecutorType getExecutorType() { return this.executorType; } public PersistenceExceptionTranslator getPersistenceExceptionTranslator() { return this.exceptionTranslator; } /** * {@inheritDoc} */ public <T> T selectOne(String statement) { return this.sqlSessionProxy.<T> selectOne(statement); } /** * {@inheritDoc} */ public <T> T selectOne(String statement, Object parameter) { return this.sqlSessionProxy.<T> selectOne(statement, parameter); } /** * {@inheritDoc} */ public <K, V> Map<K, V> selectMap(String statement, String mapKey) { return this.sqlSessionProxy.<K, V> selectMap(statement, mapKey); } /** * {@inheritDoc} */ public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) { return this.sqlSessionProxy.<K, V> selectMap(statement, parameter, mapKey); } /** * {@inheritDoc} */ public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) { return this.sqlSessionProxy.<K, V> selectMap(statement, parameter, mapKey, rowBounds); } /** * {@inheritDoc} */ public <E> List<E> selectList(String statement) { return this.sqlSessionProxy.<E> selectList(statement); } /** * {@inheritDoc} */ public <E> List<E> selectList(String statement, Object parameter) { return this.sqlSessionProxy.<E> selectList(statement, parameter); } /** * {@inheritDoc} */ public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) { return this.sqlSessionProxy.<E> selectList(statement, parameter, rowBounds); } /** * {@inheritDoc} */ public void select(String statement, ResultHandler handler) { this.sqlSessionProxy.select(statement, handler); } /** * {@inheritDoc} */ public void select(String statement, Object parameter, ResultHandler handler) { this.sqlSessionProxy.select(statement, parameter, handler); } /** * {@inheritDoc} */ public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) { this.sqlSessionProxy.select(statement, parameter, rowBounds, handler); } /** * {@inheritDoc} */ public int insert(String statement) { return this.sqlSessionProxy.insert(statement); } /** * {@inheritDoc} */ public int insert(String statement, Object parameter) { return this.sqlSessionProxy.insert(statement, parameter); } /** * {@inheritDoc} */ public int update(String statement) { return this.sqlSessionProxy.update(statement); } /** * {@inheritDoc} */ public int update(String statement, Object parameter) { return this.sqlSessionProxy.update(statement, parameter); } /** * {@inheritDoc} */ public int delete(String statement) { return this.sqlSessionProxy.delete(statement); } /** * {@inheritDoc} */ public int delete(String statement, Object parameter) { return this.sqlSessionProxy.delete(statement, parameter); } /** * {@inheritDoc} */ public <T> T getMapper(Class<T> type) { return getConfiguration().getMapper(type, this); } /** * {@inheritDoc} */ public void commit() { throw new UnsupportedOperationException("Manual commit is not allowed over a Spring managed SqlSession"); } /** * {@inheritDoc} */ public void commit(boolean force) { throw new UnsupportedOperationException("Manual commit is not allowed over a Spring managed SqlSession"); } /** * {@inheritDoc} */ public void rollback() { throw new UnsupportedOperationException("Manual rollback is not allowed over a Spring managed SqlSession"); } /** * {@inheritDoc} */ public void rollback(boolean force) { throw new UnsupportedOperationException("Manual rollback is not allowed over a Spring managed SqlSession"); } /** * {@inheritDoc} */ public void close() { throw new UnsupportedOperationException("Manual close is not allowed over a Spring managed SqlSession"); } /** * {@inheritDoc} */ public void clearCache() { this.sqlSessionProxy.clearCache(); } /** * {@inheritDoc} */ public Connection getConnection() { return this.sqlSessionProxy.getConnection(); } /** * {@inheritDoc} * @since 1.0.2 */ public List<BatchResult> flushStatements() { return this.sqlSessionProxy.flushStatements(); } /** * Proxy needed to route MyBatis method calls to the proper SqlSession got from Spring's Transaction Manager It also * unwraps exceptions thrown by {@code Method#invoke(Object, Object...)} to pass a {@code PersistenceException} to * the {@code PersistenceExceptionTranslator}. */ private class SqlSessionInterceptor implements InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { final SqlSession sqlSession = getSqlSession( CustomSqlSessionTemplate.this.getSqlSessionFactory(), CustomSqlSessionTemplate.this.executorType, CustomSqlSessionTemplate.this.exceptionTranslator); try { Object result = method.invoke(sqlSession, args); if (!isSqlSessionTransactional(sqlSession, CustomSqlSessionTemplate.this.getSqlSessionFactory())) { // force commit even on non-dirty sessions because some databases require // a commit/rollback before calling close() sqlSession.commit(true); } return result; } catch (Throwable t) { Throwable unwrapped = unwrapThrowable(t); if (CustomSqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) { Throwable translated = CustomSqlSessionTemplate.this.exceptionTranslator .translateExceptionIfPossible((PersistenceException) unwrapped); if (translated != null) { unwrapped = translated; } } throw unwrapped; } finally { closeSqlSession(sqlSession, CustomSqlSessionTemplate.this.getSqlSessionFactory()); } } } }
3.创建DynamicCreateDataSourceBean.java
package com.crs.ticket.utils.jotmutil; import java.io.IOException; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.apache.ibatis.session.SqlSessionFactory; import org.enhydra.jdbc.pool.StandardXAPoolDataSource; import org.springframework.beans.BeansException; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationListener; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.jdbc.core.JdbcTemplate; import com.crs.ticket.common.entity.DbConfig; import com.crs.ticket.utils.PropertyUtil; public class DynamicCreateDataSourceBean implements ApplicationContextAware, ApplicationListener<ApplicationEvent> { private static final String DBFILE_PATH = "/config/jdbc.properties"; private ConfigurableApplicationContext app; private JdbcTemplate jdbcTemplate; private CustomSqlSessionTemplate sqlSessionTemplate; public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } public void setSqlSessionTemplate(CustomSqlSessionTemplate sqlSessionTemplate) { this.sqlSessionTemplate = sqlSessionTemplate; } @Override public void setApplicationContext(ApplicationContext app) throws BeansException { this.app = (ConfigurableApplicationContext)app; } @Override public void onApplicationEvent(ApplicationEvent event) { // 如果是容器刷新事件OR Start Event if (event instanceof ContextRefreshedEvent) { try { regDynamicBean(); } catch (IOException e) { e.printStackTrace(); } // System.out.println(event.getClass().getSimpleName()+" 事件已发生!"); } } private void regDynamicBean() throws IOException { // 解析属性文件,得到数据源Map Map<String, DbConfig> mapCustom = parsePropertiesFile(); // 把数据源bean注册到容器中 // addSourceBeanToApp(mapCustom); addSqlSessionFactorySourceToApp(mapCustom); } /** * 功能说明:根据DataSource创建bean并注册到容器中 * * @param acf * @param mapCustom */ private void addSourceBeanToApp(Map<String, DbConfig> mapCustom) { DefaultListableBeanFactory acf = (DefaultListableBeanFactory) app.getAutowireCapableBeanFactory(); PropertyUtil propertyUtil = new PropertyUtil(); String initialPoolSize = propertyUtil.getProperty(DBFILE_PATH, "jdbc.initialPoolSize"); String minPoolSize = propertyUtil.getProperty(DBFILE_PATH, "jdbc.minPoolSize"); String maxPoolSize = propertyUtil.getProperty(DBFILE_PATH, "jdbc.maxPoolSize"); String maxIdleTime = propertyUtil.getProperty(DBFILE_PATH, "jdbc.maxIdleTime"); String acquireIncrement = propertyUtil.getProperty(DBFILE_PATH, "jdbc.acquireIncrement"); String maxStatements = propertyUtil.getProperty(DBFILE_PATH, "jdbc.maxStatements"); String idleConnectionTestPeriod = propertyUtil.getProperty(DBFILE_PATH, "jdbc.idleConnectionTestPeriod"); String acquireRetryAttempts = propertyUtil.getProperty(DBFILE_PATH, "jdbc.acquireRetryAttempts"); String DATASOURCE_BEAN_CLASS = "org.enhydra.jdbc.pool.StandardXAPoolDataSource"; BeanDefinitionBuilder bdb; Iterator<String> iter = mapCustom.keySet().iterator(); Map<Object, Object> targetDataSources = new LinkedHashMap<Object, Object>(); // BeanDefinition beanDefinition = new ChildBeanDefinition("portal"); // 将默认数据源放入 targetDataSources map中 targetDataSources.put("1", app.getBean("portal")); // 根据数据源得到数据,动态创建数据源bean 并将bean注册到applicationContext中去 StandardXAPoolDataSource dataSource; while (iter.hasNext()) { // bean ID String beanKey = iter.next(); // 创建bean bdb = BeanDefinitionBuilder.rootBeanDefinition(DATASOURCE_BEAN_CLASS); bdb.getBeanDefinition().setAttribute("id", beanKey); bdb.addPropertyValue("driverClass", mapCustom.get(beanKey).getDriverclass()); bdb.addPropertyValue("jdbcUrl", mapCustom.get(beanKey).getJdbcurl()); bdb.addPropertyValue("user", mapCustom.get(beanKey).getUsername()); bdb.addPropertyValue("password", mapCustom.get(beanKey).getPassword()); bdb.addPropertyValue("initialPoolSize", Integer.parseInt(initialPoolSize)); bdb.addPropertyValue("minPoolSize", Integer.parseInt(minPoolSize)); bdb.addPropertyValue("maxPoolSize", Integer.parseInt(maxPoolSize)); bdb.addPropertyValue("maxIdleTime", Integer.parseInt(maxIdleTime)); bdb.addPropertyValue("acquireIncrement", Integer.parseInt(acquireIncrement)); bdb.addPropertyValue("maxStatements", Integer.parseInt(maxStatements)); bdb.addPropertyValue("idleConnectionTestPeriod", Integer.parseInt(idleConnectionTestPeriod)); bdb.addPropertyValue("acquireRetryAttempts", Integer.parseInt(acquireRetryAttempts)); // 注册bean acf.registerBeanDefinition("ds" + beanKey, bdb.getBeanDefinition()); // 放入map中,注意一定是刚才创建bean对象 } } /** * 功能说明:GET ALL SM_STATIONS FROM DB1 * * @return * @throws IOException */ @SuppressWarnings("rawtypes") private Map<String, DbConfig> parsePropertiesFile() throws IOException { String sql = "SELECT ID_COMPANY,DRIVERCLASS,JDBCURL,USERNAME,PASSWORD FROM CRS_DB_CONFIG WHERE IS_DEL=0 AND IS_ENABLED=10091020"; List list = jdbcTemplate.queryForList(sql); Iterator iterator = list.iterator(); Map<String, DbConfig> mds = new HashMap<String, DbConfig>(); while (iterator.hasNext()) { Map map4station = (Map) iterator.next(); DbConfig dsi = new DbConfig(); dsi.setIdCompany((String)map4station.get("ID_COMPANY")); dsi.setDriverclass((String)map4station.get("DRIVERCLASS")); dsi.setJdbcurl((String)map4station.get("JDBCURL")); dsi.setUsername((String)map4station.get("USERNAME")); dsi.setPassword((String)map4station.get("PASSWORD")); mds.put(dsi.getIdCompany(), dsi); } return mds; } private void addSqlSessionFactorySourceToApp(Map<String, DbConfig> mapCustom){ DefaultListableBeanFactory acf = (DefaultListableBeanFactory) app.getAutowireCapableBeanFactory(); PropertyUtil propertyUtil = new PropertyUtil(); String minSize = propertyUtil.getProperty(DBFILE_PATH, "jdbc.minPoolSize"); String maxSize = propertyUtil.getProperty(DBFILE_PATH, "jdbc.maxPoolSize"); String sleepTime = propertyUtil.getProperty(DBFILE_PATH, "jdbc.sleepTime"); String lifeTime = propertyUtil.getProperty(DBFILE_PATH, "jdbc.lifeTime"); String deadLockMaxWait = propertyUtil.getProperty(DBFILE_PATH, "jdbc.deadLockMaxWait"); String deadLockRetryWait = propertyUtil.getProperty(DBFILE_PATH, "jdbc.deadLockRetryWait"); String DATASOURCE_BEAN_CLASS = "org.enhydra.jdbc.pool.StandardXAPoolDataSource"; BeanDefinitionBuilder bdb; BeanDefinitionBuilder bdb_child; BeanDefinitionBuilder bdb_ssf; Iterator<String> iter = mapCustom.keySet().iterator(); Map<Object, SqlSessionFactory> targetSqlSessionFactorys = new LinkedHashMap<Object, SqlSessionFactory>(); // BeanDefinition beanDefinition = new ChildBeanDefinition("portal"); // 将默认SqlSessionFactory放入 targetSqlSessionFactorys map中 targetSqlSessionFactorys.put("portal1", (SqlSessionFactory)app.getBean("portalSqlSessionFactory")); while (iter.hasNext()) { // bean ID String beanKey = iter.next(); // 创建连接池bean bdb = BeanDefinitionBuilder.rootBeanDefinition(DATASOURCE_BEAN_CLASS); bdb.getBeanDefinition().setAttribute("id", beanKey); bdb.getBeanDefinition().setAttribute("destroy-method", "shutdown"); //创建数据源 bdb_child = BeanDefinitionBuilder.rootBeanDefinition("org.enhydra.jdbc.standard.StandardXADataSource"); bdb_child.getBeanDefinition().setAttribute("destroy-method", "shutdown"); bdb_child.addPropertyValue("transactionManager", app.getBean("jotm")); // bdb_child.addPropertyReference("transactionManager", "jotm"); bdb_child.addPropertyValue("driverName", mapCustom.get(beanKey).getDriverclass()); bdb_child.addPropertyValue("url", mapCustom.get(beanKey).getJdbcurl()); acf.registerBeanDefinition("ds_child" + beanKey, bdb_child.getBeanDefinition()); // bdb.addPropertyReference("dataSource", "ds_child" + beanKey); bdb.addPropertyValue("dataSource", app.getBean("ds_child" + beanKey)); bdb.addPropertyValue("user", mapCustom.get(beanKey).getUsername()); bdb.addPropertyValue("password", mapCustom.get(beanKey).getPassword()); bdb.addPropertyValue("minSize", Integer.parseInt(minSize)); bdb.addPropertyValue("maxSize", Integer.parseInt(maxSize)); bdb.addPropertyValue("sleepTime", Integer.parseInt(sleepTime)); bdb.addPropertyValue("lifeTime", Integer.parseInt(lifeTime)); bdb.addPropertyValue("deadLockMaxWait", Integer.parseInt(deadLockMaxWait)); bdb.addPropertyValue("deadLockRetryWait", Integer.parseInt(deadLockRetryWait)); // 注册连接池bean acf.registerBeanDefinition("ds" + beanKey, bdb.getBeanDefinition()); //创建SqlSessionFactory bdb_ssf = BeanDefinitionBuilder.rootBeanDefinition("org.mybatis.spring.SqlSessionFactoryBean"); bdb_ssf.getBeanDefinition().setAttribute("id", "sqlSessionFactory" + beanKey); bdb_ssf.addPropertyValue("dataSource", bdb.getBeanDefinition()); bdb_ssf.addPropertyValue("mapperLocations", "classpath*:com/crs/**/*.xml"); //注册SqlSessionFactory acf.registerBeanDefinition("sqlSessionFactory" + beanKey, bdb_ssf.getBeanDefinition()); targetSqlSessionFactorys.put(beanKey, (SqlSessionFactory)app.getBean("sqlSessionFactory" + beanKey)); } sqlSessionTemplate.setTargetSqlSessionFactorys(targetSqlSessionFactorys); sqlSessionTemplate.setDefaultTargetSqlSessionFactory((SqlSessionFactory)app.getBean("portalSqlSessionFactory")); } }
4.创建CustomerContextHolder.java(多数据源切换工具)
package com.crs.ticket.utils.jotmutil; /** * <b>function:</b> 多数据源 */ public abstract class CustomerContextHolder { public final static String SESSION_FACTORY_PORTAL1 = "portal1"; public final static String SESSION_FACTORY_BO1 = "bo1"; private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>(); public static void setContextType(String contextType) { contextHolder.set(contextType); } public static String getContextType() { return contextHolder.get(); } public static void clearContextType() { contextHolder.remove(); } }
5.创建配置文件.properties读取工具类
package com.crs.ticket.utils; import java.io.IOException; import java.util.Properties; public class PropertyUtil { public String getProperty(String fileName,String key){ String value = null; Properties pro = new Properties(); try { pro.load(getClass().getResourceAsStream(fileName)); if(pro.containsKey(key)) value = pro.getProperty(key).trim(); } catch (IOException e) { e.printStackTrace(); } return value; } }
6.创建动态数据源实体类
package com.crs.ticket.common.entity; public class DbConfig { private String idCompany; private String driverclass; private String jdbcurl; private String username; private String password; public String getIdCompany() { return idCompany; } public void setIdCompany(String idCompany) { this.idCompany = idCompany; } public String getDriverclass() { return driverclass; } public void setDriverclass(String driverclass) { this.driverclass = driverclass; } public String getJdbcurl() { return jdbcurl; } public void setJdbcurl(String jdbcurl) { this.jdbcurl = jdbcurl; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
7.配置spring/spring-mybatis配置文件
<?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-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd "> <!-- 配置jtom实例 --> <bean id="jotm" class="com.crs.ticket.utils.jotmutil.JotmFactoryBean"> <property name="defaultTimeout" value="500000"/> </bean> <bean id="myJtaManager" class="org.springframework.transaction.jta.JtaTransactionManager"> <property name="userTransaction"> <ref local="jotm"/> </property> </bean> <!-- 配置mybatis Mapper扫描器 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.crs.**.mapper" /> <property name="sqlSessionTemplateBeanName" value="sqlSessionTemplate"/> </bean> <!-- 配置自定义的SqlSessionTemplate模板,注入相关配置 --> <bean id="sqlSessionTemplate" class="com.crs.ticket.utils.jotmutil.CustomSqlSessionTemplate"> <constructor-arg ref="portalSqlSessionFactory" /> <property name="targetSqlSessionFactorys"> <map> <!-- <entry value-ref="portalSqlSessionFactory" key="portal1"/> --> <!-- <entry value-ref="boSqlSessionFactory" key="bo1"/> --> </map> </property> </bean> <!-- 配置datasource数据源 --> <!-- destroy-method="close"当数据库连接不使用的时候,就把该连接重新放到数据池中,方便下次使用调用. --> <bean id="portal" 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="${portal.jdbc.driverClass}"/> <property name="url" value="${portal.jdbc.jdbcUrl}"/> </bean> </property> <property name="user" value="${portal.jdbc.user}"/> <property name="password" value="${portal.jdbc.password}"/> <property name="minSize" value="${jdbc.minPoolSize}"/> <property name="maxSize" value="${jdbc.maxPoolSize}"/> <property name="sleepTime" value="${jdbc.sleepTime}"/> <property name="lifeTime" value="${jdbc.lifeTime}"/> <property name="deadLockMaxWait" value="${jdbc.deadLockMaxWait}"/> <property name="deadLockRetryWait" value="${jdbc.deadLockRetryWait}"/> </bean> <!-- 配置session工厂 --> <bean id="portalSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="portal"/> <property name="configLocation" value="classpath:config/mybatis-configuration.xml"></property> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" > <ref bean="portal"/> </property> </bean> <bean id="applicationEventListener" class="com.crs.ticket.utils.jotmutil.DynamicCreateDataSourceBean"> <property name="jdbcTemplate" ref="jdbcTemplate" ></property> <property name="sqlSessionTemplate" ref="sqlSessionTemplate" ></property> </bean > <!-- 通知配置 --> <tx:advice id="txAdvice" transaction-manager="myJtaManager"> <tx:attributes> <tx:method name="del*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" no-rollback-for="java.lang.RuntimeException" /> <tx:method name="insert*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" /> <tx:method name="update*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" /> <tx:method name="add*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" /> <tx:method name="modify*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" /> <tx:method name="correction*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" /> <tx:method name="find*" propagation="SUPPORTS" /> <tx:method name="query*" propagation="SUPPORTS" /> <tx:method name="get*" propagation="SUPPORTS" /> <tx:method name="select*" propagation="SUPPORTS" /> <tx:method name="list*" propagation="SUPPORTS" /> <tx:method name="*" propagation="SUPPORTS" /> </tx:attributes> </tx:advice> <!-- 配置spring AOP --><!-- expression="execution(* com.crs..service..*.*(..)))任意返回值的定义在service包以及子包中的任意方法,..代表参数 --> <aop:config> <aop:pointcut id="pc" expression="execution(* com.crs..service..*.*(..)))" /> <aop:advisor pointcut-ref="pc" advice-ref="txAdvice" /> </aop:config> </beans>
8.controller中使用切换数据源(举例)
CustomerContextHolder.setContextType(CustomerContextHolder.SESSION_FACTORY_PORTAL1); List<Student> studentList = ticketchooseservice.findStudentInfoByStudNo(studentNo); System.out.println(studentList.size()); CustomerContextHolder.setContextType("36b37c0011c945808e655c80ff34457e"); List<Student> studentLista = ticketchooseservice.findStudentInfoByStudNo(studentNo);
划船不用桨、杨帆不等风、一生全靠浪