零基础尝试mybatis-plus读写分离

打印 上一主题 下一主题

主题 863|帖子 863|积分 2591

 看了好几篇博友写的文章,关于spring-boot整合mybatis-plus实现读写分离,不过都是缺这少那的,跑不起来,所以自己实操了一次,做个记录
  实现方式为使用Aop切面
1、增加数据库枚举类
  1. /**
  2. * 数据库类型
  3. */
  4. public enum DBTypeEnum {
  5.     /**
  6.      * 主节点
  7.      */
  8.     MASTER,
  9.     /**
  10.      * 从
  11.      */
  12.     SLAVE
  13. }
复制代码
2、配置数据源
  1. /**
  2. * 多数据源配置
  3. */
  4. @AutoConfigureBefore(DruidDataSourceAutoConfigure.class)
  5. @Configuration
  6. @ConfigurationProperties(prefix = "spring.datasource.druid")
  7. @Data
  8. public class DataSourceConfig {
  9.     private int initialSize;
  10.     private int maxActive;
  11.     private int minIdle;
  12.     private long maxWait;
  13.     private long minEvictableIdleTimeMillis;
  14.     private long timeBetweenEvictionRunsMillis;
  15.     private boolean testWhileIdle;
  16.     /**
  17.      * 配置主数据源
  18.      *
  19.      * @return 数据源
  20.      */
  21.     @Bean(name = "masterDataSource")
  22.     @ConfigurationProperties(prefix = "spring.datasource.druid.master" )
  23.     public DataSource masterDataSource() {
  24.         DruidDataSource druidDataSource = new DruidDataSource();
  25.         parseDruidConfig(druidDataSource);
  26.         return druidDataSource;
  27.     }
  28.     /**
  29.      * 配置从数据源
  30.      *
  31.      * @return 数据源
  32.      */
  33.     @Bean(name = "slaveDataSource")
  34.     @ConfigurationProperties(prefix = "spring.datasource.druid.slave")
  35.     public DataSource slaveDataSource() {
  36.         DruidDataSource druidDataSource = new DruidDataSource();
  37.         parseDruidConfig(druidDataSource);
  38.         return druidDataSource;
  39.     }
  40.     private void parseDruidConfig(DruidDataSource dataSource) {
  41.         dataSource.setInitialSize(initialSize);
  42.         dataSource.setMaxActive(maxActive);
  43.         dataSource.setMinIdle(minIdle);
  44.         dataSource.setMaxWait(maxWait);
  45.         dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
  46.         dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
  47.         dataSource.setTestWhileIdle(testWhileIdle);
  48.     }
  49.     /**
  50.      * 配置路由数据源
  51.      *
  52.      * @param masterDataSource 主节点
  53.      * @param slaveDataSource 从节点
  54.      * @return 数据源
  55.      */
  56.     @Bean(name = "myRoutingDataSource")
  57.     @DependsOn({"masterDataSource", "slaveDataSource"})
  58.     @Primary
  59.     public DataSource myRoutingDataSource(@Qualifier("masterDataSource") DataSource masterDataSource,
  60.                                           @Qualifier("slaveDataSource") DataSource slaveDataSource) {
  61.         Map<Object, Object> targetDataSources = new HashMap<>(3);
  62.         targetDataSources.put(DBTypeEnum.MASTER, masterDataSource);
  63.         targetDataSources.put(DBTypeEnum.SLAVE, slaveDataSource);
  64.         MyRoutingDataSource myRoutingDataSource = new MyRoutingDataSource();
  65.         //设置默认数据源
  66.         myRoutingDataSource.setDefaultTargetDataSource(masterDataSource);
  67.         myRoutingDataSource.setTargetDataSources(targetDataSources);
  68.         return myRoutingDataSource;
  69.     }
  70. }
复制代码
3、线程轮循切换主从数据库(多主多从的情况下适用)
  1. /**
  2. * 通过ThreadLocal将数据源设置到每个线程上下文中
  3. */
  4. public class DataSourceContextHolder {
  5.     private static final ThreadLocal<DBTypeEnum> CONTEXT_HOLDER = new ThreadLocal<>();
  6.     private static final AtomicInteger COUNTER = new AtomicInteger(-1);
  7.     public static void set(DBTypeEnum dbType) {
  8.         CONTEXT_HOLDER.set(dbType);
  9.     }
  10.     public static DBTypeEnum get() {
  11.         return CONTEXT_HOLDER.get();
  12.     }
  13.     public static void clear(){
  14.         CONTEXT_HOLDER.remove();
  15.     }
  16.     public static void master() {
  17.         set(DBTypeEnum.MASTER);
  18.         System.out.println("切换到master");
  19.     }
  20.     public static void slave() {
  21.         //  轮询
  22.         int index = COUNTER.getAndIncrement() % 2;
  23.         if (COUNTER.get() > 9999) {
  24.             COUNTER.set(-1);
  25.         }
  26. //        if (index == 0) {
  27. //            set(DBTypeEnum.SLAVE1);
  28. //            System.out.println("切换到slave1");
  29. //        } else {
  30. //            set(DBTypeEnum.SLAVE2);
  31. //            System.out.println("切换到slave2");
  32. //        }
  33.         set(DBTypeEnum.SLAVE);
  34.         System.out.println("切换到slave2");
  35.     }
  36. }
复制代码
4、声明路由数据源key(多主多从的情况下适用)
  1. /**
  2. * 声明路由数据源key
  3. */
  4. public class MyRoutingDataSource extends AbstractRoutingDataSource {
  5.     @Nullable
  6.     @Override
  7.     protected Object determineCurrentLookupKey() {
  8.         return DataSourceContextHolder.get();
  9.     }
  10. }
复制代码
5、强制使用主/从数据库注解
  1. /**
  2. * 强制使用主数据库注解
  3. */
  4. @Retention(RetentionPolicy.RUNTIME)
  5. @Target({ElementType.METHOD})
  6. public @interface DataSourceMaster {
  7. }
复制代码
  1. /**
  2. * 强制使用从数据库注解
  3. */
  4. @Retention(RetentionPolicy.RUNTIME)
  5. @Target({ElementType.METHOD})
  6. public @interface DataSourceSlave {
  7. }
复制代码
6、切面类(从库注解会报错,不知道什么原因)
  1. /**
  2. * 使用aop实现数据源切换
  3. */
  4. @Aspect
  5. @Component
  6. public class DataSourceAop {
  7. //    /**
  8. //     * 需要读的方法,切面
  9. //     */
  10. //    @Pointcut("!@annotation(com.readWriteSeparation.annotation.DataSourceSlave)" +
  11. //            "|| execution(* com.readWriteSeparation.service..*.select*(..)) " +
  12. //            "|| execution(* com.readWriteSeparation.service..*.get*(..))" +
  13. //            "|| execution(* com.readWriteSeparation.service..*.query*(..))" +
  14. //            "|| execution(* com.readWriteSeparation.service..*.find*(..)))")
  15. //    public void readPointcut() { }
  16.     /**
  17.      * 需要读的方法,切面
  18.      */
  19.     @Pointcut("execution(* com.readWriteSeparation.service..*.select*(..)) " +
  20.             "|| execution(* com.readWriteSeparation.service..*.get*(..))" +
  21.             "|| execution(* com.readWriteSeparation.service..*.query*(..))" +
  22.             "|| execution(* com.readWriteSeparation.service..*.find*(..)))")
  23.     public void readPointcut() { }
  24.     /**
  25.      * 写切面
  26.      */
  27.     @Pointcut("@annotation(com.readWriteSeparation.annotation.DataSourceMaster) " +
  28.             "|| execution(* com.readWriteSeparation.service..*.insert*(..))" +
  29.             "|| execution(* com.readWriteSeparation.service..*.save*(..))" +
  30.             "|| execution(* com.readWriteSeparation.service..*.add*(..))" +
  31.             "|| execution(* com.readWriteSeparation.service..*.update*(..))" +
  32.             "|| execution(* com.readWriteSeparation.service..*.edit*(..))" +
  33.             "|| execution(* com.readWriteSeparation.service..*.delete*(..))" +
  34.             "|| execution(* com.readWriteSeparation.service..*.remove*(..))")
  35.     public void writePointcut() { }
  36.     @Before("readPointcut()")
  37.     public void read() {
  38.         DataSourceContextHolder.slave();
  39.     }
  40.     @Before("writePointcut()")
  41.     public void write() {
  42.         DataSourceContextHolder.master();
  43.     }
  44.     @After("readPointcut()")
  45.     public void readAfter() {
  46.         DataSourceContextHolder.clear();
  47.     }
  48.     @After("writePointcut()")
  49.     public void writeAfter() {
  50.         DataSourceContextHolder.clear();
  51.     }
  52. }
复制代码
7、.yml文件配置
  1. spring:
  2.   datasource:
  3.     druid:
  4.       master:
  5.         username: root
  6.         password: 12345678
  7.         url: jdbc:mysql://192.168.10.15/zeroStart?characterEncoding=UTF-8&useSSL=true&requireSSL=false&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&allowMultiQueries=true
  8.         driver-class-name: com.mysql.cj.jdbc.Driver
  9.         type: com.zaxxer.hikari.HikariDataSource
  10.       slave:
  11.         username: root
  12.         password: 12345678
  13.         url: jdbc:mysql://localhost:3306/zeroStart?characterEncoding=UTF-8&useSSL=true&requireSSL=false&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&allowMultiQueries=true
  14.         driver-class-name: com.mysql.cj.jdbc.Driver
  15.         type: com.zaxxer.hikari.HikariDataSource
复制代码
8、引入的依赖
  1.         <dependency>
  2.             <groupId>com.baomidou</groupId>
  3.             <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
  4.             <version>2.4.2</version>
  5.         </dependency>
  6.         <dependency>
  7.             <groupId>com.baomidou</groupId>
  8.             <artifactId>mybatis-plus-extension</artifactId>
  9.             <version>${mybatis-plus.version}</version>
  10.         </dependency>
  11.         
  12.         <dependency>
  13.             <groupId>com.alibaba</groupId>
  14.             <artifactId>druid</artifactId>
  15.             <version>1.2.7</version>
  16.         </dependency>
  17.         <dependency>
  18.             <groupId>com.alibaba</groupId>
  19.             <artifactId>druid-spring-boot-starter</artifactId>
  20.             <version>1.2.16</version>
  21.         </dependency>
复制代码
配置到这就好了,业务代码就不展示了
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

tsx81428

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表