当前位置 : 主页 > 编程语言 > java >

Mybatis+Spring实现Mysql读写分离

来源:互联网 收集:自由互联 发布时间:2021-06-28
使用spring AbstractRoutingDatasource实现多数据源 public class DynamicDataSource extends AbstractRoutingDataSource { //写数据源 private Object writeDataSource; //读数据源 private Object readDataSource; @Override public void a
使用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
 
   targetDataSources = new HashMap
  
   (); 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
 
   DATASOURCES = new ThreadLocal
  
   (); 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
 
   cachaMap = new HashMap
  
   (); @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) { } }
  
 
网友评论