下面哪个逾期一天报金融数据库库不是逾期一天报金融数据库库集成商提供的全文库

& & <span style="color:#FF年8月16日11:45:39更新:这里贴出我自己写的一个demo,放在CSDN上了。
& & 前面写了一篇关于使用Spring +&druid + Mybatis配置多数据源,并在代码中动态选择使用不同的数据源的博文,当时写该文时,由于比较忙,只简单做了记录,后来又做了一些扩展,添加了分布式事务等,今天就另起一文,详细记录下目前生产线上正在使用的稳定版本。
& & 首先说下业务场景:
& & 有一个系统作为数据中转服务器,我称之为系统A。若干个系统数据都需要经过该系统A做处理、转发,而数据交互有多种方式,如WebService、REST API、中间表等,A也会操作自己的数据库。本文主要围绕操作中间表的方式来讲。
& & A需要操作的自己的数据库是确定的,但由于接入的系统可能随业务发展而增加或改变,所以不能将中间表的连接信息写死,需要使用配置文件维护,并在服务器启动的时候全动态加载,然后由不同的业务去决定使用哪一个数据池的连接。(该段文本描述的业务问题已在上篇文章中解决)
& & 由于系统A会读中间表,然后将读取的数据预处理,然后存入A系统的数据库或其他中间库,如果使用DataSourceTransactionManager作为事务管理器来控制事务,会出现多数据库事务不一致的问题,那么,解决这类问题有两种方案:编程式事务和分布式事务。如果使用编程式事务的话,需要在每个地方显示地开启事务和提交事务,这样耦合性太高,而且对于复杂的业务来说,不好处理,故不适合系统A的业务场景。后来看了分布式事务框架atomikos,觉得应该能解决我的问题,经测试,效果很赞,下面就让我们一起来看看它是什么集成到系统的。(原理的话,大家自己百度一下)
& & 好了,说了这么多,下面来一步一步解决我们问题。
& & 一、配置多套数据源(一个默认的数据源defaultDataSource,是系统A自己的数据库,另一个是需要在服务启动的时候动态初始化的数据源atomikosDynamicDataSource)。
&?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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
&!-- 默认的dataSource --&
&bean id="defaultDataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" destroy-method="close"&
&!-- uniqueResourceName很重要,不能重复 --&
&property name="uniqueResourceName" value="defaultDataSource"/&
&property name="xaDataSourceClassName" value="com.alibaba.druid.pool.xa.DruidXADataSource" /&
&property name="borrowConnectionTimeout" value="${pro.borrowConnectionTimeout}" /&
&property name="minPoolSize" value="${pro.minPoolSize}" /&
&property name="maxPoolSize" value="${pro.maxPoolSize}" /&
&property name="maxLifetime" value="0" /&
&!-- xaProperties实质上是设置属性xaDataSourceClassName的对象的值,即com.alibaba.druid.pool.xa.DruidXADataSource的参数值 --&
&property name="xaProperties"&
&prop key="driverClassName"&${pro.driver}&/prop&
&prop key="url"&${pro.url}&/prop&
&prop key="username"&${pro.username}&/prop&
&prop key="password"&${pro.password}&/prop&
&prop key="initialSize"&${pro.initialSize}&/prop&
&prop key="minIdle"&${pro.minIdle}&/prop&
&prop key="maxActive"&${pro.maxActive}&/prop&
&prop key="maxWait"&${pro.maxWait}&/prop&
&prop key="timeBetweenEvictionRunsMillis"&${pro.timeBetweenEvictionRunsMillis}&/prop&
&prop key="minEvictableIdleTimeMillis"&${pro.minEvictableIdleTimeMillis}&/prop&
&prop key="validationQuery"&SELECT 1&/prop&
&prop key="testWhileIdle"&true&/prop&
&prop key="testOnBorrow"&false&/prop&
&prop key="testOnReturn"&false&/prop&
&prop key="poolPreparedStatements"&true&/prop&
&prop key="maxPoolPreparedStatementPerConnectionSize"&${pro.maxPoolPreparedStatementPerConnectionSize}&/prop&
&prop key="filters"&stat&/prop&
&/property&
&!-- 定义主业务使用的sqlSessionFactory --&
&bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"&
&property name="configLocation"&
&value&classpath:config/sqlMapConfig.xml&/value&
&/property&
&property name="dataSource" ref="defaultDataSource" /&
&property name="typeAliasesPackage" value="com.eya.model.domain" /&
&!-- 扫描defaultDataSource对应的数据源的SQL配置文件,这部分数据库操作就不需要动态切换数据源,直接使用默认数据源操作数据库即可 --&
&property name="mapperLocations" value="classpath:com/eya/dao/**/*.xml" /&
&!-- 扫描mybatis的接口所在的文件 --&
&bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"&
&property name="basePackage" value="com.eya.dao,com.eya.pubmapper" /&
&property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/&
&!-- 定义中间表使用的数据源、sqlSessionFactory等 --&
&bean id="atomikosDynamicDataSource" class="com.eya.pubservice.datasource.AtomikosDynamicDataSource" &
&!-- &property name="defaultTargetDataSource" ref="defaultDataSource"&&/property& --&
&property name="targetDataSources"&
&!-- 这里还可以加多个dataSource,由于不确定数据源的地址信息,所以这里不配置,在代码中去动态初始化 --&
&/property&
&!-- 定义数据交互业务使用的sqlSessionFactory --&
&bean id="sqlSessionFactory4MiddleTable" class="org.mybatis.spring.SqlSessionFactoryBean"&
&property name="dataSource" ref="atomikosDynamicDataSource" /&
&!-- 扫描中间表的SQL配置文件 --&
&property name="mapperLocations" value="classpath:com/eya/middletable/**/*.xml" /&
&!-- 扫描mybatis的接口所在的文件 --&
&bean id="mapperScannerConfigurer4MiddleTable" class="org.mybatis.spring.mapper.MapperScannerConfigurer"&
&property name="basePackage" value="com.eya.middletable" /&
&property name="sqlSessionFactoryBeanName" value="sqlSessionFactory4MiddleTable"/&
&!-- jta分布式事务 --&
&!-- Atomikos 事务管理器配置 --&
&bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
init-method="init" destroy-method="close"&
&!-- &property name="startupTransactionService" value="false" /& --&
&!-- close()时是否强制终止事务 --&
&property name="forceShutdown" value="false" /&
&!-- Atomikos UserTransaction配置 --&
&bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp"&&/bean&
&!-- JTA事务管理器 --&
&bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager"&
&property name="transactionManager"&
&ref bean="atomikosTransactionManager" /&
&/property&
&property name="userTransaction"&
&ref bean="atomikosUserTransaction" /&
&/property&
&!-- 开启注解事务,使用@Transactional来标记需要事务控制的方法或类 --&
&tx:annotation-driven transaction-manager="txManager" proxy-target-class="true" /&
& & 说明一下,这是spring的配置文件,主要配置mybatis的信息,其中涉及到了数据源、mybatis的SQL文件和接口类、声明事务管理。这里面有几个需要重点指出的地方
& & 1.文件中的表达式,如${pro.url},是引入properties的内容,这个很简单,将配置信息定义到properties文件中,便于维护。
& & 2.DataSource的定义:和原来定义DataSource不同,原来定义时,是使用class为com.alibaba.druid.pool.xa.DruidXADataSource(也可以是c3p0)来定义bean,然后配置连接池的信息,现在是定义class为com.atomikos.jdbc.AtomikosDataSourceBean的bean,然后使用xaDataSourceClassName指明具体使用的连接池类,使用xaProperties来配置连接池的属性。
& & 3.defaultDataSource:defaultDataSource为系统A自己的数据库信息,这个是确定的,所以直接在配置文件中定义好,然后根据defaultDataSource来配置sqlSessionFactory,并使用sqlSessionFactory来配置mapperScannerConfigurer,这部分是完成系统A自己的数据源配置以及myBatis配置(SQL文件扫描和接口类)。注意:定义org.mybatis.spring.mapper.MapperScannerConfigurer的bean时,需要使用sqlSessionFactoryBeanName来指定使用哪一个sqlSessionFactory,不然会抛出异常。
& & 4.atomikosDynamicDataSource:这是一个自己实现的数据源类(代码我稍后贴出来并讲解代码中的内容),属性targetDataSources是一个map集合,用于存储该数据源的连接池信息。以上配置文件中,没有配置map的值,因为不能像defaultDataSource一样确定数据库连接地址等信息,所以在服务器启动的时候,用代码去初始化这个数据源(根据配置的多个数据库信息,初始化对应个数的连接池,然后存放到targetDataSources中),targetDataSources被初始化后,在系统运行过程中,根据不同的业务,从targetDataSources中选择不同的连接池来操作数据库。
& & 5.分布式事务配置:在配置文件中定义了atomikosTransactionManager、atomikosUserTransaction两个bean,然后在txManager中注入这2个bean,并在最后使用&tx:annotation-driven transaction-manager="txManager" proxy-target-class="true" /&开启注解事务。配置很简单,这样就配置好了我们的分布式事务,不过在我使用过程中,出现了一个困扰我很久的事务提交超时问题(com.atomikos.icatch.RollbackException: Prepare: NO vote),就在昨天我才解决它。其实是应该在添加一个配置文件,配置事务的相关属性,具体内容参考我的博文:
& & 说明:大部分情况下,按照上述配置,在配置&atomikosDynamicDataSource的时候,同时配置targetDataSources的值,并在代码中动态确定使用哪套数据源(继承AbstractRoutingDataSource并实现determineCurrentLookupKey即可)就可以了,这也是网上目前大部分资料已经完成的内容。
& & 二、创建AbstractDynamicDataSource、AtomikosDynamicDataSource,管理动态创建的数据源,然后创建一个标记使用的数据源的上下文对象,DBContextHolder,用来标记当前业务需要使用哪一个数据源。&&&&
package com.eya.pubservice.
import java.util.M
import javax.sql.DataS
import org.apache.commons.collections.MapU
import org.slf4j.L
import org.slf4j.LoggerF
import org.springframework.beans.BeansE
import org.springframework.context.ApplicationC
import org.springframework.context.ApplicationContextA
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataS
* 动态数据源父类
* @create ll
* @createDate 日 下午2:38:05
* @updateDate
public abstract class AbstractDynamicDataSource&T extends DataSource& extends
AbstractRoutingDataSource
implements
ApplicationContextAware {
/** 日志 */
protected Logger logger = LoggerFactory.getLogger(getClass());
/** 默认的数据源KEY */
//protected static final String DEFAULT_DATASOURCE_KEY = "defaultDataSource";
/** 数据源KEY-VALUE键值对 */
private Map&Object, Object& targetDataS
/** spring容器上下文 */
private static ApplicationC
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ctx = applicationC
public static ApplicationContext getApplicationContext() {
public static Object getBean(String name) {
return ctx.getBean(name);
* @param targetDataSources the targetDataSources to set
public void setTargetDataSources(Map&Object, Object& targetDataSources) {
this.targetDataSources = targetDataS
super.setTargetDataSources(targetDataSources);
// afterPropertiesSet()方法调用时用来将targetDataSources的属性写入resolvedDataSources中的
super.afterPropertiesSet();
* @return the targetDataSources
public Map&Object, Object& getTargetDataSources() {
return this.targetDataS
* 创建数据源
* @param driverClassName 数据库驱动名称
* @param url 连接地址
* @param username 用户名
* @param password 密码
* @return 数据源{@link T}
* @Author : ll. create at 日 下午2:44:34
public abstract T createDataSource(String driverClassName, String url, String username,
String password);
* 设置系统当前使用的数据源
* &p&数据源为空或者为0时,自动切换至默认数据源,即在配置文件中定义的默认数据源
* @see org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource#determineCurrentLookupKey()
protected Object determineCurrentLookupKey() {
logger.debug("【设置系统当前使用的数据源】");
Map&String, Object& configMap = DBContextHolder.getDBType();
logger.debug("【当前数据源配置为:{}】", configMap);
if (MapUtils.isEmpty(configMap)) {
// 使用默认数据源
//return DEFAULT_DATASOURCE_KEY;
throw new IllegalArgumentException("没有指定数据源");
// 判断数据源是否需要初始化
this.verifyAndInitDataSource();
logger.debug("【切换至数据源:{}】", configMap);
return configMap.get(DBContextHolder.DATASOURCE_KEY);
* 判断数据源是否需要初始化
* @Author : ll. create at 日 下午3:57:43
private void verifyAndInitDataSource() {
Map&String, Object& configMap = DBContextHolder.getDBType();
Object obj = this.targetDataSources.get(configMap.get(DBContextHolder.DATASOURCE_KEY));
if (obj != null) {
logger.info("【初始化数据源】");
T datasource = this.createDataSource(configMap.get(DBContextHolder.DATASOURCE_DRIVER)
.toString(), configMap.get(DBContextHolder.DATASOURCE_URL).toString(),
configMap.get(DBContextHolder.DATASOURCE_USERNAME).toString(),
configMap.get(DBContextHolder.DATASOURCE_PASSWORD).toString());
this.addTargetDataSource(configMap.get(DBContextHolder.DATASOURCE_KEY).toString(),
datasource);
* 往数据源key-value键值对集合添加新的数据源
* @param key 新的数据源键
* @param dataSource 新的数据源
* @Author : ll. create at 日 下午2:56:49
public void addTargetDataSource(String key, T dataSource) {
this.targetDataSources.put(key, dataSource);
super.setTargetDataSources(this.targetDataSources);
// afterPropertiesSet()方法调用时用来将targetDataSources的属性写入resolvedDataSources中的
super.afterPropertiesSet();
package com.eya.pubservice.
import java.sql.SQLE
import java.util.L
import org.apache.commons.lang3.StringU
import org.springframework.beans.factory.annotation.A
import com.alibaba.druid.filter.F
import com.alibaba.druid.pool.DruidDataS
import com.alibaba.druid.pool.xa.DruidXADataS
import com.atomikos.jdbc.AtomikosDataSourceB
import com.eya.pubservice.bean.properties.DBP
import com.eya.util.ProIdU
* @create ll
* @createDate 日 下午2:14:27
* @updateDate
public class AtomikosDynamicDataSource extends AbstractDynamicDataSource&AtomikosDataSourceBean& {
/** db.properties配置信息的对应文件 */
@Autowired
private DBProperties dBP
private boolean testWhileIdle =
private boolean testOnBorrow =
private boolean testOnReturn =
// 是否打开连接泄露自动检测
private boolean removeAbandoned =
// 连接长时间没有使用,被认为发生泄露时长
private long removeAbandonedTimeoutMillis = 300 * 1000;
// 发生泄露时是否需要输出 log,建议在开启连接泄露检测时开启,方便排错
private boolean logAbandoned =
// 只要maxPoolPreparedStatementPerConnectionSize&0,poolPreparedStatements就会被自动设定为true,使用oracle时可以设定此值。
private int maxPoolPreparedStatementPerConnectionSize = -1;
// 配置监控统计拦截的filters
private S // 监控统计:"stat" 防SQL注入:"wall" 组合使用: "stat,wall"
private List&Filter& filterL
* 创建数据源
* @see com.eya.pubservice.datasource.IDynamicDataSource#createDataSource(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
public AtomikosDataSourceBean createDataSource(String driverClassName, String url,
String username, String password) {
DruidXADataSource ds = new DruidXADataSource();
ds.setName(ProIdUtil.get16TimeRandom());
ds.setUrl(url);
ds.setUsername(username);
ds.setPassword(password);
ds.setDriverClassName(driverClassName);
ds.setInitialSize(dBProperties.getInitialSize());
ds.setMinIdle(dBProperties.getMinIdle());
ds.setMaxActive(dBProperties.getMaxActive());
ds.setMaxWait(dBProperties.getMaxWait());
ds.setTimeBetweenConnectErrorMillis(dBProperties.getTimeBetweenConnectErrorMillis());
ds.setTimeBetweenEvictionRunsMillis(dBProperties.getTimeBetweenEvictionRunsMillis());
ds.setMinEvictableIdleTimeMillis(dBProperties.getMinEvictableIdleTimeMillis());
ds.setValidationQuery(dBProperties.getValidationQuery());
ds.setTestWhileIdle(testWhileIdle);
ds.setTestOnBorrow(testOnBorrow);
ds.setTestOnReturn(testOnReturn);
ds.setRemoveAbandoned(removeAbandoned);
ds.setRemoveAbandonedTimeoutMillis(removeAbandonedTimeoutMillis);
ds.setLogAbandoned(logAbandoned);
// 只要maxPoolPreparedStatementPerConnectionSize&0,poolPreparedStatements就会被自动设定为true,参照druid的源码
ds.setMaxPoolPreparedStatementPerConnectionSize(
dBProperties.getMaxPoolPreparedStatementPerConnectionSize());
if (StringUtils.isNotBlank(filters))
ds.setFilters(filters);
} catch (SQLException e) {
ds.close();
throw new RuntimeException(e);
AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
atomikosDataSourceBean.setXaDataSource(ds);
// 设置数据源的唯一名称,不允许重复
atomikosDataSourceBean.setUniqueResourceName(ProIdUtil.getTimeRandomId(32));
atomikosDataSourceBean.setMaxPoolSize(dBProperties.getMaxPoolSize());
atomikosDataSourceBean.setMinPoolSize(dBProperties.getMinPoolSize());
atomikosDataSourceBean
.setBorrowConnectionTimeout(dBProperties.getBorrowConnectionTimeout());
atomikosDataSourceBean.getXaProperties().setProperty("", arg1);
atomikosDataSourceBean.getXaProperties().setProperty("", arg1);
atomikosDataSourceBean.getXaProperties().setProperty("", arg1);
atomikosDataSourceBean.getXaProperties().setProperty("", arg1);
atomikosDataSourceBean.setMaxLifetime(0);
addFilterList(ds);
return atomikosDataSourceB
private void addFilterList(DruidDataSource ds) {
if (filterList != null) {
List&Filter& targetList = ds.getProxyFilters();
for (Filter add : filterList) {
boolean found =
for (Filter target : targetList) {
if (add.getClass().equals(target.getClass())) {
if (!found)
targetList.add(add);
package com.eya.pubservice.
import java.util.HashM
import java.util.M
* 当前正在使用的数据源信息的线程上线文
* @create ll
* @createDate 日 下午2:37:07
* @updateDate
public class DBContextHolder {
/** 数据源的KEY */
public static final String DATASOURCE_KEY = "DATASOURCE_KEY";
/** 数据源的URL */
public static final String DATASOURCE_URL = "DATASOURCE_URL";
/** 数据源的驱动 */
public static final String DATASOURCE_DRIVER = "DATASOURCE_DRIVER";
/** 数据源的用户名 */
public static final String DATASOURCE_USERNAME = "DATASOURCE_USERNAME";
/** 数据源的密码 */
public static final String DATASOURCE_PASSWORD = "DATASOURCE_PASSWORD";
private static final ThreadLocal&Map&String, Object&& contextHolder = new ThreadLocal&Map&String, Object&&();
public static void setDBType(Map&String, Object& dataSourceConfigMap) {
contextHolder.set(dataSourceConfigMap);
public static Map&String, Object& getDBType() {
Map&String, Object& dataSourceConfigMap = contextHolder.get();
if (dataSourceConfigMap == null) {
dataSourceConfigMap = new HashMap&String, Object&();
return dataSourceConfigM
public static void clearDBType() {
contextHolder.remove();
& & 说明一下:
& & 1.AbstractDynamicDataSource:该类继承AbstractRoutingDataSource,并重写determineCurrentLookupKey方法,用于确定使用哪套数据源。该类又实现了ApplicationContextAware,在Spring容器初始化的时候,会执行setApplicationContext方法,将Spring容器的上下文对象注入到属性ctx中,然后就可以使用ctx.getBean(name)来获取Spring容器中的对象。
& & 2.AtomikosDynamicDataSource:基于atomikos的动态数据源类,其实我还有一个DruidDynamicDataSource类,这里没有给出,内容大部分一样,只是createDataSource的实现内容不一样,DruidDynamicDataSource只是简单地创建了一个基于Druid的数据池,而AtomikosDynamicDataSource是创建的一个可加入atomikos分布式事务的数据池。
& & 3.DBProperties是一个基于Spring注入来获取properties内容添加的方式添加的一个和数据库配置文件(db.properties)内容相同的JAVA类(参考),用于获取&数据库配置文件(db.properties)的配置信息。我这里就不贴出该类的代码,大家可以自己想办法获取配置文件信息或直接写死都可以,毕竟这里不是本文的重点。
& & 三、服务启动,根据配置文件,初始化数据源。MiddleTableService.java
package com.eya.pubservice.
import java.util.HashM
import java.util.L
import java.util.M
import org.slf4j.L
import org.slf4j.LoggerF
import org.springframework.beans.factory.annotation.A
import org.springframework.stereotype.C
import com.atomikos.jdbc.AtomikosDataSourceB
import com.eya.common.annotation.LoggerP
import com.eya.common.annotation.ParamR
import com.eya.common.exception.BusinessE
import com.eya.pubservice.InterfaceConfigS
import com.eya.pubservice.bean.interfaceConfig.InterfaceConfigMtD
import com.eya.util.ProC
import com.eya.util.ProS
* 中间表服务类
* @create ll
* @createDate 日 上午9:36:45
* @updateDate
@Component
public class MiddleTableService {
/** 日志 */
private static final Logger LOGGER = LoggerFactory.getLogger(MiddleTableService.class);
/** 接口配置服务类 */
@Autowired
private InterfaceConfigService interfaceConfigS
/** Atomikos数据源 */
@Autowired
private AtomikosDynamicDataSource atomikosDynamicDataS
* 随服务器启动,根据机构中间表信息配置,初始化数据源
* @Author : ll. create at 日 上午9:37:19
public synchronized void init() {
LOGGER.info("【根据机构中间表信息配置,初始化数据源 】");
// 清空所有数据源
atomikosDynamicDataSource.getTargetDataSources().clear();
// 这段代码是获取所有的中间表数据库配置信息,读者不用关心,按照自己的方式获取配置即可
List&InterfaceConfigMtDetail& mtDetails = interfaceConfigService.getMtDetails();
if (ProCollection.isEmpty(mtDetails)) {
LOGGER.info("【无中间表配置数据,终止中间表数据源初始化任务】");
for (InterfaceConfigMtDetail interfaceConfigMtDetail : mtDetails) {
// 判断数据源是否已经被初始化
if (atomikosDynamicDataSource.getTargetDataSources().containsKey(
interfaceConfigMtDetail.getDataSourceKey())) {
// 已经初始化
// 创建数据源
AtomikosDataSourceBean dataSource = atomikosDynamicDataSource.createDataSource(
interfaceConfigMtDetail.getDriver(), interfaceConfigMtDetail.getUrl(),
interfaceConfigMtDetail.getUsername(), interfaceConfigMtDetail.getPassword());
// 添加到targetDataSource中,缓存起来
atomikosDynamicDataSource.addTargetDataSource(
interfaceConfigMtDetail.getDataSourceKey(), dataSource);
* 数据源控制开关,用于指定数据源
* @param interfaceCode 接口的唯一吗
* @Author : ll. create at 日 下午1:56:28
@LoggerPrinter(value = "数据源控制开关,用于指定数据源")
@ParamRequired
public void dataSourceSwitch(String interfaceCode) {
InterfaceConfigMtDetail mtDetail = interfaceConfigService.getMtDetailMap().get(
interfaceCode);
if (mtDetail == null) {
throw new BusinessException("根据接口唯一码未获取到中间表配置信息");
if (ProString.isBlank(mtDetail.getDriver()) && ProString.isBlank(mtDetail.getUrl())
&& ProString.isBlank(mtDetail.getUsername())) {
throw new IllegalArgumentException(String.format("接口【%s】未配置中间表信息,无法切换数据源",
interfaceCode));
Map&String, Object& dataSourceConfigMap = new HashMap&String, Object&();
dataSourceConfigMap.put(DBContextHolder.DATASOURCE_KEY, mtDetail.getDataSourceKey());
dataSourceConfigMap.put(DBContextHolder.DATASOURCE_DRIVER, mtDetail.getDriver());
dataSourceConfigMap.put(DBContextHolder.DATASOURCE_URL, mtDetail.getUrl());
dataSourceConfigMap.put(DBContextHolder.DATASOURCE_USERNAME, mtDetail.getUsername());
dataSourceConfigMap.put(DBContextHolder.DATASOURCE_PASSWORD, mtDetail.getPassword());
LOGGER.info("【指定数据源】dataSourceConfigMap = {}", dataSourceConfigMap);
DBContextHolder.setDBType(dataSourceConfigMap);
& & 说明:
& & 1.该类的init方法在服务器启动的时候执行,根据中间表配置信息,初始化数据源。
& & 2.dataSourceSwitch:数据源开关,根据接口唯一码(每个业务都有一个唯一码,每个唯一码可能和不同系统交互的方式不同)判断是否使用中间库,如果是,则根据信息,指定到对应的数据源。
& & 3.这个类确实太简单了,没什么好说的。
& & 以上内容,完全由博主自己集合网上资料摸索出来的一套业务解决方案,如有缺陷,敬请大家指出交流。&&&&
& & 如果有问题,大家可以留言讨论,或加我QQ/发邮件交流,联系方式在我个人资料中。由于平时工作较忙,如未及时回复大家,敬请见谅。
& 著作权归作者所有
人打赏支持
码字总数 49491
引用来自“vincezheng”的评论DEMO无法运行啊,提示create connection error引用来自“十月阳光”的评论不会吧,之前很多朋友下了没有出问题,你看看是不是数据库不对,或者数据库设置不对DEMO已经解决,成功运行,需要先maven clean一下才行。非常感谢,另外,我的项目是财务系统,登陆时切换财年,所有数据表一样,只是存的数据不同年份,所以只需要切换数据库名就行,使用博主的方法只保留一个sqlSessionFactory和一个mapperScannerConfiger就可以了,已经测试运行成功,提供给大家,方便更多人。
引用来自“vincezheng”的评论DEMO无法运行啊,提示create connection error不会吧,之前很多朋友下了没有出问题,你看看是不是数据库不对,或者数据库设置不对
DEMO无法运行啊,提示create connection error
引用来自“JAVA盼盼”的评论能不能把全部代码共享一下,我按照你的例子写了一部分,后面没法继续了。不好意思,我本来是将附件传到CSDN了,当时还在审核,没贴出链接,我给你个链接http://download.csdn.net/download/llzhaoyun/9912658
能不能把全部代码共享一下,我按照你的例子写了一部分,后面没法继续了。
引用来自“云飞扬11”的评论com.eya.common.annotation.ParamRequired这个是什么类?自定义标签作什么用呢回复 : 这个是我自己定义的一个注解,用于校验参数是否为空,你可以不用这个注解
com.eya.common.annotation.ParamRequired这个是什么类?自定义标签作什么用呢
字太多了,不是很想看,先码
评论删除后,数据将无法恢复
1 系列目录 - 分布式事务系列(开篇)提出疑问和研究过程- 分布式事务系列(1.1)Spring事务管理器PlatformTransactionManager源码分析- 分布式事务系列(1.2)Spring事务体系- 分布式事务系...
项目中我们经常会遇到多数据源的问题,尤其是数据同步或定时任务等项目更是如此。多数据源让人最头痛的,不是配置多个数据源,而是如何能灵活动态的切换数据源。例如在一个spring和hibernate...
Java编程思想
嘉宾:张亮 作者:雨多田光 提起数据库中间件,我们可以很自然地联想到 OneProxy、TDSQL、Sharding-JDBC 与 MyCat 等知名项目。在众多的数据库中间件实现技术中,通常存在两种架构模式,一种...
编辑部的故事
前言:在上一篇文章 基于可靠消息方案的分布式事务:Lottor介绍 中介绍了常见的分布式事务的解决方案以及笔者基于可靠消息方案实现的分布式事务组件Lottor的原理,并展示了应用的控制台管理。...
在java中有如下三种事务, 简单的JDBC级的事务 JTA - 在EJB环境下,用户得到事务并进行控制CMP - 完全由容器控制事务,用户通过Bean配置文件来定义事务行为 二三种都支持分布式事务,但只支持...
1.1.1 Spring是什么 Spring是一个开源的轻量级Java SE(Java 标准版本)/Java EE(Java 企业版本)开发应用框架,其目的是用于简化企业级应用程序开发。应用程序是由一组相互协作的对象组成。...
摘要: 原创出处 http://www.iocoder.cn/Sharding-JDBC/transaction-bed/ 「芋道源码」欢迎转载,保留摘要,谢谢! 本文主要基于 Sharding-JDBC 1.5.0 正式版 1. 概述 2. 最大努力送达型 3. 柔...
Sharding-JDBC集分库分表、读写分离、分布式主键、柔性事务和数据治理与一身,提供一站式的解决分布式关系型数据库的解决方案。 从2.x版本开始,Sharding-JDBC正式将包名、Maven坐标、码云仓...
一、DBUtils介绍 Apache公司开发的框架。
DBUtils是java编程中的数据库操作实用工具,小巧简单实用。
DBUtils封装了对JDBC的操作,简化了JDBC操作。可以少写代码。 commons-dbutils 是...
weblogic 创建datasource时,配置注意事项,记录一下weblogic 的doc。 事务选项 使用管理控制台配置 JDBC 数据源时,WebLogic Server 会根据 JDBC 驱动程序的类型自动选择特定的事务选项: ...
没有更多内容
加载失败,请刷新页面
大体上一共分为3步,那么我们就美其名曰——三步走搞定MySQL安装 为什么说3步呢,如果你非要计较说我一次就重新安装成功了,就当我没说,这些是说给那些经常安装失败的同学看的! 切记,如若...
我们经常会碰到这样的问题,用 telnet/ssh 登录了远程的 Linux 服务器,运行了一些耗时较长的任务, 结果却由于网络的不稳定导致任务中途失败。如何让命令提交后不受本地关闭终端窗口/网络断...
越来越多的云盘宣布关闭,百度网盘也时不时8秒和谐视频,分享也会提示侵权被和谐。为了解决这些问题,我们可以搭建一个自己的个人网盘(私有云盘),常用的开源框架包括ownCloud,Seafile,N...
你可以修改你 Confluence 为用户显示的时期和时间格式。设置的句法使用的是 SimpleDateFormat class,请参考 Java SimpleDateFormat 文档中的内容来设置日期和时间格式。 有下面 3 个时间和日...
九大内置对象: request:类型是HttpServletRequest,和Servlet里的HttpServletRequest一模一样。 response:类型是HttpServletResponse,和Servlet里的HttpServletResponse一模一样。JSP里基...
14.1 NFS介绍 NFS介绍 NFS是Network File System的缩写;这个文件系统是基于网路层面,通过网络层面实现数据同步 NFS最早由Sun公司开发,分2,3,4三个版本,2和3由Sun起草开发,4.0开始Netap...
Linux学习笔记
1、设置容器 docker run -it --name nginx-test2 -v /home/nginx:/apps -v /home/nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro -p 8183:80 -p
-d nginx:stable 2、修改nginx配......
一图带你看完本文 一、运行时数据区域 首先来看看Java虚拟机所管理的内存包括哪些区域,就像我们要了解一个房子,我们得先知道这个房子大体构造。根据《Java虚拟机规范(Java SE 7 版)》的规...
Java大蜗牛
前言 之前几个章节,大部分都是算介绍springboot的一些外围配置,比如日志 配置等。这章节开始,开始总结一些关于springboot的综合开发的知识点。由于SpringBoot本身是基于Spring和SpringMvc...
如今,大型企业如金融企业和银行等,在下一代的微服务架构转型要求下,需要基础软件和数据平台能够实现原生的云化,以满足微服务架构的需求。 微服务,也就是一种面向服务的,有特定边界的松...
巨杉数据库
没有更多内容
加载失败,请刷新页面
文章删除后无法恢复,确定取消删除此文章吗?
亲,自荐的博客将通过私信方式通知管理员,优秀的博客文章审核通过后将在博客推荐列表中显示
确定推荐此文章吗?
确定推荐此博主吗?
聚合全网技术文章,根据你的阅读喜好进行个性推荐
指定官方社区
深圳市奥思网络科技有限公司版权所有

我要回帖

更多关于 excel数据库管理系统 的文章

 

随机推荐