Spring-Mybatis读写分离笔记整理

  1. 编写Spring动态数据源实现类
    public class ReadWriteDataSource extends AbstractRoutingDataSource {
        @Nullable
        @Override
        protected Object determineCurrentLookupKey() {
            return DsTypeHolder.get().getCode();
        }
    }
    
  2. 编写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}),
       @Signature(type = Executor.class, method = "query",
               args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class})
    })
    public class DynamicDataSourceInterceptor implements Interceptor {
        private static final String REGEX = ".*insert\\u0020.*|.*delete\\u0020.*|.*update\\u0020.*" ;
        @Override
        public Object intercept(Invocation invocation) throws Throwable {
            boolean transactionActive = TransactionSynchronizationManager.isActualTransactionActive();
            DsType dsType = DsType.MASTER;
            if (!transactionActive){
                Object[] args = invocation.getArgs();
                MappedStatement ms = (MappedStatement) args[0] ;
                if (ms.getSqlCommandType().equals(SqlCommandType.SELECT)){
                    // 如果selectKey为自增id查询主键,使用主库
                    if (ms.getId().contains(SelectKeyGenerator.SELECT_KEY_SUFFIX)){
                        dsType = DsType.MASTER;
                    }else {
                        BoundSql boundSql = ms.getSqlSource().getBoundSql(args[1]);
                        String sql = boundSql.getSql().toLowerCase(Locale.CHINA).replaceAll("[\\t\\n\\r]]", "");
                        // 如果是更新操作则切换到主库
                        if (sql.matches(REGEX)){
                            dsType = DsType.MASTER;
                        }else {
                            // 非更新操作则使用从库
                            dsType = DsType.SLAVE;
                        }
                    }
                }
            }else {
                dsType = DsType.MASTER;
            }
            DsTypeHolder.set(dsType);
            return invocation.proceed();
        }
        @Override
        public Object plugin(Object target) {
            if (target instanceof Executor){
                return Plugin.wrap(target, this);
            }
            return target ;
        }
    }
    
  3. 数据源切换工具类
    @Getter
    public enum DsType {
        MASTER("master"),
        SLAVE("slave");
    
        private final String code ;
    
        DsType(String code){
            this.code = code ;
        }
    }
    public class DsTypeHolder {
        private static ThreadLocal<DsType> dsTypeThreadLocal = new ThreadLocal<>();
    
        public static void set(DsType dsType) {
            dsTypeThreadLocal.set(dsType);
        }
    
        public static DsType get() {
            if (dsTypeThreadLocal.get() == null){
                return DsType.MASTER ;
            }
            return dsTypeThreadLocal.get();
        }
    
        public static void clear() {
            dsTypeThreadLocal.remove();
        }
    }
    
  4. 编写数据源配置
    spring:
      application:
        name: hello-read-write-app
      jackson:
        time-zone: GMT+8
      datasource:
        master:
          driver-class-name: com.mysql.cj.jdbc.Driver
          jdbc-url: jdbc:mysql://127.0.0.1:3306/test
          username: root
          password: root
        slave:
          driver-class-name: com.mysql.cj.jdbc.Driver
          jdbc-url: jdbc:mysql://127.0.0.1:3306/test
          username: root
          password: root
    logging:
      level:
        root: info
        com.yicj.study.rw.repository.mapper: debug
    mybatis-plus:
      mapper-locations: classpath:/mapper/*Mapper.xml
    
  5. 将数据源注入到spring容器中
    @Configuration
    public class DataSourceConfig {
        @Bean
        @ConfigurationProperties("spring.datasource.master")
        public DataSource masterDataSource() {
            return DataSourceBuilder.create().build();
        }
    
        @Bean
        @ConfigurationProperties("spring.datasource.slave")
        public DataSource slaveDataSource() {
            return DataSourceBuilder.create().build();
        }
    
        @Bean
        public ReadWriteDataSource readWriteDataSource(
                @Qualifier("masterDataSource") DataSource masterDataSource,
                @Qualifier("slaveDataSource") DataSource slaveDataSource) {
            Map<Object, Object> targetDataSources = new HashMap<>();
            targetDataSources.put(DsType.MASTER.getCode(), masterDataSource);
            targetDataSources.put(DsType.SLAVE.getCode(), slaveDataSource);
            //
            ReadWriteDataSource readWriteDataSource = new ReadWriteDataSource();
            readWriteDataSource.setDefaultTargetDataSource(masterDataSource);
            readWriteDataSource.setTargetDataSources(targetDataSources);
            return readWriteDataSource;
        }
    }
    
  6. Mybatis-plus配置
    @Configuration
    public class MyBatisConfig {
    
        @Autowired
        private ReadWriteDataSource readWriteDataSource ;
    
        @Bean
        public SqlSessionFactory sqlSessionFactory() throws Exception {
            MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
            sqlSessionFactory.setDataSource(readWriteDataSource);
            MybatisConfiguration configuration = new MybatisConfiguration();
            configuration.setJdbcTypeForNull(JdbcType.NULL);
            configuration.setMapUnderscoreToCamelCase(true);
            configuration.setCacheEnabled(false);
            // 动态数据源拦截器配置
            configuration.addInterceptor(new DynamicDataSourceInterceptor());
            //如果配置多个插件,切记分页最后添加
            MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
            interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
            configuration.addInterceptor(interceptor);
            sqlSessionFactory.setConfiguration(configuration);
            return sqlSessionFactory.getObject();
        }
    
        @Bean
        public PlatformTransactionManager platformTransactionManager() {
            return new DataSourceTransactionManager(readWriteDataSource);
        }
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring-MyBatis整合是一种常见的开发方式,其中spring-mybatis.xml文件是用来配置SpringMyBatis框架集成的配置文件。在这个文件中,我们会定义数据源、事务管理器、扫描Mapper接口等配置信息。同时,我们还需要将MyBatis的SqlSessionFactory注入到Spring容器中,以便其他组件可以使用它来执行数据库操作。以下是一个简单的spring-mybatis.xml文件示例: ```xml <?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:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- 配置数据源 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="${jdbc.driverClass}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <!-- 配置SqlSessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="typeAliasesPackage" value="com.example.entity" /> <property name="mapperLocations" value="classpath*:com/example/mapper/*.xml" /> </bean> <!-- 配置Mapper扫描 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.example.mapper" /> </bean> <!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 开启Spring的注解功能 --> <context:annotation-config /> <!-- 开启Spring的AOP功能 --> <aop:aspectj-autoproxy /> <!-- 开启Spring的事务管理功能 --> <tx:annotation-driven transaction-manager="transactionManager" /> </beans> ``` 在这个配置文件中,我们使用了Spring的注解功能、AOP功能和事务管理功能,以及MyBatis的Mapper扫描和SqlSessionFactory配置。其中,数据源、事务管理器和Mapper扫描的配置信息需要根据实际情况进行修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值