一:依赖的jar包 Maven配置
二:配置
dataSource.properties
transactions.properties
三:AOP 注解方式数据源动态切换
四:数据源动态切换实例
五:分布式事务下的数据源动态切换
@Transactional 通过数据库的connection来建立事务的,为了保证数据源能顺利切换,要保证@DataSource优先于@Transactional执行。 实现办法 在DataSourceAspect 切面上增加注解@Order(1). 此处需要了解切面的层次和执行顺序等相关知识。 @Transactionl,@DataSource 在service层的同一个方法上。
dao实现类
注意,此处采用了编程式来实现事务,注解式暂时还没有好的解决方法,欢迎大家讨论分享。 此处的@DataSource 放在了dao的实现层。
点击(此处)折叠或打开
- <dependency>
- <groupId>com.atomikos</groupId>
- <artifactId>transactions</artifactId>
- <version>4.0.4</version>
- </dependency>
- <dependency>
- <groupId>com.atomikos</groupId>
- <artifactId>transactions-api</artifactId>
- <version>4.0.4</version>
- </dependency>
- <dependency>
- <groupId>com.atomikos</groupId>
- <artifactId>atomikos-util</artifactId>
- <version>4.0.4</version>
- </dependency>
- <dependency>
- <groupId>com.atomikos</groupId>
- <artifactId>transactions-jdbc-deprecated</artifactId>
- <version>3.8.0</version>
- </dependency>
- <dependency>
- <groupId>com.atomikos</groupId>
- <artifactId>transactions-jta</artifactId>
- <version>4.0.4</version>
- </dependency>
- <dependency>
- <groupId>com.atomikos</groupId>
- <artifactId>transactions-jdbc</artifactId>
- <version>4.0.4</version>
- </dependency>
-
- <dependency>
- <groupId>cglib</groupId>
- <artifactId>cglib-nodep</artifactId>
- <version>3.2.5</version>
- </dependency>
-
- <dependency>
- <groupId>javax.transaction</groupId>
- <artifactId>jta</artifactId>
- <version>1.1</version>
- </dependency>
dataSource.properties
点击(此处)折叠或打开
- workDesk.jdbc.driverclass=com.mysql.jdbc.Driver
- workDesk.jdbc.url=jdbc:mysql://10.243.3.18:3306/system?userUnicode=true&characterEncoding=UTF-8
- workDesk.jdbc.username=root
- workDesk.jdbc.password=$Fortune2015
- workDesk.jdbc.poolsize.max=3
- workDesk.jdbc.poolsize.min=3
- workDesk.jdbc.poolsize.initial=2
- workDesk.jdbc.idletime.max=25000
- workDesk.jdbc.idleConnectionTestPeriod=18000
-
- #-------workDesk jdbc--------
- workDesk.read.jdbc.driverclass=com.mysql.jdbc.Driver
- workDesk.read.jdbc.url=jdbc:mysql://112.74.53.213:3306/gmc?userUnicode=true&characterEncoding=UTF-8
- workDesk.read.jdbc.username=root
- workDesk.read.jdbc.password=Wanmide@123
- workDesk.read.jdbc.poolsize.max=3
- workDesk.read.jdbc.poolsize.min=3
- workDesk.read.jdbc.poolsize.initial=2
- workDesk.read.jdbc.idletime.max=25000
- workDesk.read.jdbc.idleConnectionTestPeriod=18000
-
- jdbc.xaDataSourceClassName=com.mysql.jdbc.jdbc2.optional.MysqlXADataSource
点击(此处)折叠或打开
- # SAMPLE PROPERTIES FILE FOR THE TRANSACTION SERVICE
- # THIS FILE ILLUSTRATES THE DIFFERENT SETTINGS FOR THE TRANSACTION MANAGER
- # UNCOMMENT THE ASSIGNMENTS TO OVERRIDE DEFAULT VALUES;
-
- # Required: factory implementation class of the transaction core.
- # NOTE: there is no default for this, so it MUST be
- #
- com.atomikos.icatch.service=com.atomikos.icatch.standalone.UserTransactionServiceFactory
-
-
- # Set base name of file where messages are output
- # (also known as the 'console file').
- #
- # com.atomikos.icatch.console_file_name = tm.out
-
- # Size limit (in bytes) for the console file;
- # negative means unlimited.
- #
- # com.atomikos.icatch.console_file_limit=-1
-
- # For size-limited console files, this option
- # specifies a number of rotating files to
- # maintain.
- #
- # com.atomikos.icatch.console_file_count=1
-
- # Set the number of log writes between checkpoints
- #
- # com.atomikos.icatch.checkpoint_interval=500
-
- # Set output directory where console file and other files are to be put
- # make sure this directory
- #
- # com.atomikos.icatch.output_dir = ./
-
- # Set directory of log files; make sure this directory
- #
- com.atomikos.icatch.log_base_dir = ./
-
- # Set base name of log file
- # this name will be used as the first part of
- # the system-generated log file name
- #
- # com.atomikos.icatch.log_base_name = tmlog
-
- # Set the max number of active local transactions
- # or -1 for unlimited.
- #
- # com.atomikos.icatch.max_actives = 50
-
- # Set the default timeout (in milliseconds) for local transactions
- #
- # com.atomikos.icatch.default_jta_timeout = 10000
-
- # Set the max timeout (in milliseconds) for local transactions
- #
- # com.atomikos.icatch.max_timeout = 300000
-
- # The globally unique name of this transaction manager process
- # override this value with a globally unique name
- #
- # com.atomikos.icatch.tm_unique_name = tm
-
- # Do we want to use parallel subtransactions? JTA
点击(此处)折叠或打开
- /**
- * Atomikos 数据源A
- * @return
- */
- @Bean(name="dataSourceA",initMethod="init",destroyMethod="close")
- public AtomikosDataSourceBean dataSourceA()
- {
- AtomikosDataSourceBean dataSourceA=new AtomikosDataSourceBean();
- dataSourceA.setUniqueResourceName("dataSourceA");
- dataSourceA.setXaDataSourceClassName(xaDataSourceClassName);
- Properties xaProperties = new Properties();
- xaProperties.put("user", user);
- xaProperties.put("password", password);
- xaProperties.put("url", jdbcUrl);
- xaProperties.put("pinGlobalTxToPhysicalConnection", true);
- dataSourceA.setXaProperties(xaProperties);
- dataSourceA.setMaxPoolSize(maxPoolSize);
- dataSourceA.setMinPoolSize(minPoolSize);
- dataSourceA.setMaxIdleTime(maxIdleTime);
- dataSourceA.setTestQuery("SELECT 1");
- return dataSourceA;
- }
-
-
- /**
- * Atomikos 数据源A
- * @return
- */
- @Bean(name="dataSourceB",initMethod="init",destroyMethod="close")
- public AtomikosDataSourceBean dataSourceB()
- {
- AtomikosDataSourceBean dataSourceA=new AtomikosDataSourceBean();
- dataSourceA.setUniqueResourceName("dataSourceB");
- dataSourceA.setXaDataSourceClassName(xaDataSourceClassName);
- Properties xaProperties = new Properties();
- xaProperties.put("user", readUser);
- xaProperties.put("password", readPassword);
- xaProperties.put("url", readJdbcUrl);
- xaProperties.put("pinGlobalTxToPhysicalConnection", true);
- dataSourceA.setXaProperties(xaProperties);
- dataSourceA.setMaxPoolSize(readMaxPoolSize);
- dataSourceA.setMinPoolSize(readMinPoolSize);
- dataSourceA.setMaxIdleTime(readMaxIdleTime);
- dataSourceA.setTestQuery("SELECT 1");
- return dataSourceA;
- }
点击(此处)折叠或打开
- @Configuration
- public class DynamicTransactionManagerElConfig {
-
- // @Autowired
- // @Qualifier("platformTomcat")
- // private DataSource platformTomcat;
- //
- // @Autowired
- // @Qualifier("platformReadTomcat")
- // private DataSource platformReadTomcat;
-
- @Autowired
- @Qualifier("dataSourceA")
- private DataSource dataSourceA;
-
- @Autowired
- @Qualifier("dataSourceB")
- private DataSource dataSourceB;
-
- @Bean(name = "dataSource")
- public DynamicDataSource dataSource() {
- DynamicDataSource dataSource = new DynamicDataSource();
- Map<Object, Object> targetDataSources = new HashMap<>();
- targetDataSources.put("master", dataSourceA);
- targetDataSources.put("slave", dataSourceB);
- dataSource.setTargetDataSources(targetDataSources);
- dataSource.setDefaultTargetDataSource(dataSourceA);
- return dataSource;
- }
-
- @Bean(name = "jdbcTemplate")
- public JdbcTemplate jdbcTemplate(DynamicDataSource dataSource) {
- JdbcTemplate jdbcTemplate = new JdbcTemplate();
- jdbcTemplate.setDataSource(dataSource);
- return jdbcTemplate;
- }
-
- @Bean(name = "jdbcReadTemplate")
- public JdbcTemplate jdbcReadTemplate(DynamicDataSource dataSource) {
- JdbcTemplate jdbcReadTemplate = new JdbcTemplate();
- jdbcReadTemplate.setDataSource(dataSource);
- return jdbcReadTemplate;
- }
-
- @Bean(name = "atomikosTransactionManager", initMethod = "init", destroyMethod = "close")
- public UserTransactionManager atomikosTransactionManager() {
- UserTransactionManager atomikosTransactionManager = new UserTransactionManager();
- atomikosTransactionManager.setForceShutdown(true);
- return atomikosTransactionManager;
- }
-
- @Bean(name = "atomikosUserTransaction")
- public UserTransactionImp atomikosUserTransaction() {
- UserTransactionImp atomikosUserTransaction = new UserTransactionImp();
- try {
- atomikosUserTransaction.setTransactionTimeout(300);
- }
- catch (SystemException e) {
- e.printStackTrace();
- }
- return atomikosUserTransaction;
- }
-
- // @Bean(name = "transactionManager")
- // public DataSourceTransactionManager transactionManager(DynamicDataSource
- // dataSource) {
- // DataSourceTransactionManager transactionManager = new
- // DataSourceTransactionManager();
- // transactionManager.setDataSource(dataSource);
- // return transactionManager;
- // }
-
- @Bean(name = "transactionManager")
- public JtaTransactionManager transactionManager(UserTransactionManager atomikosTransactionManager,
- UserTransactionImp atomikosUserTransaction) {
- JtaTransactionManager transactionManager = new JtaTransactionManager();
- transactionManager.setTransactionManager(atomikosTransactionManager);
- transactionManager.setUserTransaction(atomikosUserTransaction);
- transactionManager.setAllowCustomIsolationLevels(true);
- return transactionManager;
- }
-
- }
点击(此处)折叠或打开
- @Retention(RetentionPolicy.RUNTIME)
- @Target(ElementType.METHOD)
- @Documented
- public @interface DataSource {
- String value();
- }
点击(此处)折叠或打开
- public class DynamicDataSource extends AbstractRoutingDataSource {
-
- @Override
- protected Object determineCurrentLookupKey() {
- return DataSourceContextHolder.getDataSource();
- }
-
- }
点击(此处)折叠或打开
- public class DataSourceContextHolder {
-
- private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
-
- public static void setDataSource(String dataSource) {
- contextHolder.set(dataSource);
- }
-
- public static String getDataSource() {
- return contextHolder.get();
- }
-
- public static void removeDataSource() {
- contextHolder.remove();
- }
-
- }
点击(此处)折叠或打开
- @Aspect
- @Order(1)
- @Component
- public class DataSourceAspect {
-
- @Pointcut("@annotation(com.gemdale.ghome.business.async.deal.center.demo.datasource.DataSource)")
- public void dataSourcePointCut() {
- };
-
- @Before("dataSourcePointCut()")
- public void before(JoinPoint joinPoint) {
-
- System.out.println("=============dataSourcePointCut:before=============");
- Object target = joinPoint.getTarget();
- String method = joinPoint.getSignature().getName();
-
- // Class[] classz = target.getClass().getInterfaces();
- Class<?> classz = target.getClass();
- Class<?>[] parameterTypes = ((MethodSignature) joinPoint.getSignature()).getMethod().getParameterTypes();
-
- try {
- // Method m = classz[0].getMethod(method, parameterTypes);
- Method m = classz.getMethod(method, parameterTypes);
- if (null != m && m.isAnnotationPresent(DataSource.class)) {
- DataSource dataSource = m.getAnnotation(DataSource.class);
- DataSourceContextHolder.setDataSource(dataSource.value());
-
- System.out.println("=============dataSource:" + dataSource.value());
- }
- }
- catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- }
点击(此处)折叠或打开
- @Repository("gmcSmsInfoDaoImpl")
- public class GmcSmsInfoDaoImpl extends BaseDaoSupport implements GmcSmsInfoDAO{
-
- /* (non-Javadoc)
- * @see com.gemdale.ghome.business.async.deal.center.demo.GmcSmsInfoDAO#addMaster(com.gemdale.ghome.business.async.deal.center.demo.GmcSmsInfo)
- */
- @Override
- @DataSource("master")
- public Integer addMaster(GmcSmsInfo smsInfo) throws FrameworkDAOException {
- return save(smsInfo);
- }
-
- /* (non-Javadoc)
- * @see com.gemdale.ghome.business.async.deal.center.demo.GmcSmsInfoDAO#addSlave(com.gemdale.ghome.business.async.deal.center.demo.GmcSmsInfo)
- */
- @Override
- @DataSource("slave")
- public Integer addSlave(GmcSmsInfo smsInfo) throws FrameworkDAOException {
- return save(smsInfo);
- }
-
-
- }
五:分布式事务下的数据源动态切换
情况一:事务下唯一数据源切换
点击(此处)折叠或打开
- @Transactional(rollbackFor={Exception.class,RuntimeException.class})
- @DataSource("master")
- public GmcSmsInfo addMaster(GmcSmsInfo smsInfo) throws BusinessServiceException {
- try {
- smsInfo.setSmsId(gmcSmsInfoDaoImpl.save(smsInfo));
- }
- catch (FrameworkDAOException e) {
- throw new BusinessServiceException(e);
- }
- return smsInfo;
- }
@Transactional 通过数据库的connection来建立事务的,为了保证数据源能顺利切换,要保证@DataSource优先于@Transactional执行。 实现办法 在DataSourceAspect 切面上增加注解@Order(1). 此处需要了解切面的层次和执行顺序等相关知识。 @Transactionl,@DataSource 在service层的同一个方法上。
情况二:事务下多数据源切换
service类
点击(此处)折叠或打开
- @Autowired
- private GmcSmsInfoDAO gmcSmsInfoDaoImpl;
-
- @Autowired
- @Qualifier("transactionManager")
- private JtaTransactionManager transactionManager;
-
-
- public void addMasterAndSlave(GmcSmsInfo smsInfo) throws BusinessServiceException {
- UserTransaction userTransaction = transactionManager.getUserTransaction();
- try {
- userTransaction.begin();
- gmcSmsInfoDaoImpl.addMaster(smsInfo);
- smsInfo = new GmcSmsInfo();
-
- smsInfo.setChannel("test2");
- smsInfo.setContent("test2");
- smsInfo.setStatus("001");
- smsInfo.setCreateDate(Calendar.getInstance().getTime());
- smsInfo.setMobile("88888888");
- gmcSmsInfoDaoImpl.addSlave(smsInfo);
- userTransaction.commit();
- }
- catch (Exception e) {
- try {
- userTransaction.rollback();
- }
- catch (IllegalStateException e1) {
- e1.printStackTrace();
- }
- catch (SecurityException e1) {
- e1.printStackTrace();
- }
- catch (SystemException e1) {
- e1.printStackTrace();
- }
- throw new BusinessServiceException(e);
- }
-
- }
dao实现类
点击(此处)折叠或打开
- /* (non-Javadoc)
- * @see com.gemdale.ghome.business.async.deal.center.demo.GmcSmsInfoDAO#addMaster(com.gemdale.ghome.business.async.deal.center.demo.GmcSmsInfo)
- */
- @Override
- @DataSource("master")
- public Integer addMaster(GmcSmsInfo smsInfo) throws FrameworkDAOException {
- return save(smsInfo);
- }
-
- /* (non-Javadoc)
- * @see com.gemdale.ghome.business.async.deal.center.demo.GmcSmsInfoDAO#addSlave(com.gemdale.ghome.business.async.deal.center.demo.GmcSmsInfo)
- */
- @Override
- @DataSource("slave")
- public Integer addSlave(GmcSmsInfo smsInfo) throws FrameworkDAOException {
- return save(smsInfo);
- }
注意,此处采用了编程式来实现事务,注解式暂时还没有好的解决方法,欢迎大家讨论分享。 此处的@DataSource 放在了dao的实现层。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/28624388/viewspace-2137095/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/28624388/viewspace-2137095/