使用spring AbstractRoutingDatasource实现多数据源


public class DynamicDataSource extends AbstractRoutingDataSource {
//写数据源
private Object writeDataSource;
//读数据源
private Object readDataSource; @Override
public void afterPropertiesSet() {
Assert.isNull(writeDataSource, "Property 'writeDataSource' is required");
setDefaultTargetDataSource(writeDataSource);
Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
targetDataSources.put(DBTypeEnum.WRITE.name(), writeDataSource);
if (null != readDataSource)
targetDataSources.put(DBTypeEnum.READ.name(), readDataSource);
setTargetDataSources(targetDataSources);
super.afterPropertiesSet();
} /**
* 获取当前使用那个数据源
*/
@Override
protected Object determineCurrentLookupKey() {
DBTypeEnum dataSource = DbContextHolder.getDbType();
if (null == dataSource || dataSource == DBTypeEnum.WRITE)
return DBTypeEnum.WRITE.name();
return DBTypeEnum.READ.name();
} public Object getWriteDataSource() {
return writeDataSource;
} public void setWriteDataSource(Object writeDataSource) {
this.writeDataSource = writeDataSource;
} public Object getReadDataSource() {
return readDataSource;
} public void setReadDataSource(Object readDataSource) {
this.readDataSource = readDataSource;
}
}

读写数据库类型


public enum DBTypeEnum {
WRITE, READ;
}

当前数据库配置上下文


public class DbContextHolder {
private static final ThreadLocal<DBTypeEnum> DATASOURCES = new ThreadLocal<DBTypeEnum>(); private DbContextHolder() {
} /**
* 设置数据源
*
* @param dbType
*/
public static void setDbType(DBTypeEnum dbType) {
DATASOURCES.set(dbType.WRITE);
} /*
* 获取当前数据源
* @return DBTypeEnum
* */
public static DBTypeEnum getDbType() {
return DATASOURCES.get();
} /**
* 清除上下文数据
*/
public static void clearDbType() {
DATASOURCES.remove();
}
}

自定义事务管理器


public class DynamicDataSourceTransactionManager extends DataSourceTransactionManager {
/**
* 设置数据源
*/
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
boolean readOnly = definition.isReadOnly();
if (readOnly)
DbContextHolder.setDbType(DBTypeEnum.READ);
DbContextHolder.setDbType(DBTypeEnum.WRITE);
super.doBegin(transaction, definition);
} /**
* 清理本地线程数据源
*/
@Override
protected void doCleanupAfterCompletion(Object transaction) {
super.doCleanupAfterCompletion(transaction);
DbContextHolder.clearDbType();
}
}

mybatis插件(拦截器)


@Intercepts({
@Signature(type = Executor.class, method = "update", args = {
MappedStatement.class, Object.class}),
@Signature(type = Executor.class, method = "query", args = {
MappedStatement.class, Object.class, RowBounds.class,
ResultHandler.class})})
public class DynamicPlugin implements Interceptor {
private static final Logger _log = LoggerFactory.getLogger(DynamicPlugin.class);
private static final String REGEX = ".*insert\\u0020.*|.*delete\\u0020.*|.*update\\u0020.*";
private static final Map<String, DBTypeEnum> cachaMap = new HashMap<String, DBTypeEnum>(); @Override
public Object intercept(Invocation invocation) throws Throwable {
boolean isSynchronizationActive = TransactionSynchronizationManager.isSynchronizationActive();
if (!isSynchronizationActive) {
MappedStatement ms = (MappedStatement) invocation.getArgs()[0];
DBTypeEnum dbTypeEnum = null;
if ((dbTypeEnum = cachaMap.get(ms.getId())) == null) {
//读方法
if (ms.getSqlCommandType().equals(SqlCommandType.SELECT)) {
//!selectKeu为自增id查询主键(SELECT LAST_INSERT_ID)方法,使用主库
if (ms.getId().contains(SelectKeyGenerator.SELECT_KEY_SUFFIX))
dbTypeEnum = DBTypeEnum.WRITE;
else {
BoundSql boundSql = ms.getSqlSource().getBoundSql(invocation.getArgs()[1]);
String sql = boundSql.getSql().toLowerCase(Locale.CHINA).replaceAll("[\\t\\n\\r]", " ");
if (sql.matches(REGEX))
dbTypeEnum = DBTypeEnum.WRITE;
dbTypeEnum = DBTypeEnum.READ;
}
} else {
dbTypeEnum = DBTypeEnum.WRITE;
}
_log.warn("设置方法[{}] use [{}] Strategy, SqlCommandType [{}]..", ms.getId(), dbTypeEnum.name(), ms.getSqlCommandType().name());
cachaMap.put(ms.getId(), dbTypeEnum);
}
DbContextHolder.setDbType(dbTypeEnum);
}
return invocation.proceed();
} @Override
public Object plugin(Object target) {
if (target instanceof Executor) {
return Plugin.wrap(target, this);
} else {
return target;
}
} @Override
public void setProperties(Properties properties) { }
}

最新文章

  1. 【java】Naming.bind和Registry.bind区别
  2. Java:对象的强、软、弱、虚引用
  3. Laravel学习笔记(五)数据库 数据库迁移案例2——创建数据结构,数据表,修改数据结构
  4. NOIp 2006 作业调度方案 Label:坑 模拟(tyvj你不给我ac,我就把名字献给附中oj)
  5. NSDateFormatter中时间格式串的含义
  6. TFS的使用
  7. ajax页面数据的传递
  8. 新版的DEV RichEdit很强悍,兼容docx,排版更强
  9. WebService(2)-XML系列之Java和Xml之间相互转换
  10. jenkins集群加入Windows 2012 server作为slave
  11. 定向爬虫之爬一爬各个学校新闻的认识(【1】对Url的认识)
  12. DAY6-小变化(java提示框)-2018-1-16
  13. php提供的sapi有哪些?CGI、FastCGI、php-fpm、php-cgi解释
  14. WC2019滚粗记
  15. 【安全测试自学】初探web安全处测试(三)
  16. 周一要做的事情Sd31y5YE
  17. js多个异步请求,按顺序执行next
  18. [.NET MVC4 入门系列01]Helloworld MVC 4 第一个MVC4程序
  19. php中模糊查询并关联三个select框
  20. C++中 set(集合容器)的用法

热门文章

  1. 带权二分图——KM算法hdu2255 poj3565
  2. DuiLib学习笔记1.编译运行demo
  3. 前端面试题之一JAVASCRIPT(算法类)
  4. 89 k数和
  5. 在Linux中使用selenium(环境部署)
  6. Leetcode240. Search a 2D Matrix II搜索二维矩阵2
  7. C++与Matlab混合编程之:矩阵数据结构
  8. Collection接口和Map接口
  9. LUOGU NOIP 2018 模拟赛 DAY1
  10. IIS+PHP+MYSQL搭建