Jdbc怎么实现分布式事务数据源动态切换
Jdbc怎么实现分布式事务数据源动态切换
本篇内容介绍了“Jdbc怎么实现分布式事务数据源动态切换”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
一:依赖的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的实现层。
@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);
}
}
/* (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);
}
“Jdbc怎么实现分布式事务数据源动态切换”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注恰卡编程网网站,小编将为大家输出更多高质量的实用文章!
推荐阅读
-
JDBC的连接方法是什么
JDBC的连接方法是什么本篇内容介绍了“JDBC的连接方法是什么”...
-
如何用JDBC实现验证登录
如何用JDBC实现验证登录这篇文章主要介绍“如何用JDBC实现验证...
-
JDBC怎么实现验证登录
JDBC怎么实现验证登录这篇文章主要介绍“JDBC怎么实现验证登录...
-
JDBC是什么
JDBC是什么本篇内容主要讲解“JDBC是什么”,感兴趣的朋友不妨...
-
JDBC连接SQL Server 2005的方法是什么
-
JDBC技术怎么理解
JDBC技术怎么理解这篇文章主要介绍“JDBC技术怎么理解”,在日...
-
JDBC事务处理机制是什么
JDBC事务处理机制是什么本篇内容介绍了“JDBC事务处理机制是什...
-
MyEclipse的JDBC相关驱动程序怎么设置
MyEclipse的JDBC相关驱动程序怎么设置这篇文章主要介绍“...
-
Spring JDBC事务管理怎么实现
SpringJDBC事务管理怎么实现本篇内容主要讲解“Sprin...
-
JDBC驱动程序是什么