一:依赖的jar包 Maven配置
-
<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
transactions.properties
-
# 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;
-
}
-
-
}
三:AOP 注解方式数据源动态切换
-
@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博客 ” ,链接:https://blog.itpub.net/28624388/viewspace-2137095/
,如需转载,请注明出处,否则将追究法律责任。