• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

带你了解mybatis如何实现读写分离

java 搞代码 4年前 (2022-01-05) 81次浏览 已收录 0个评论
文章目录[隐藏]

本篇文章主要介绍了MyBatis实现数据读写分离的实例代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能给你带来帮助

1、spring aop实现

首先application-test.yml增加如下数据源的配置

 spring: datasource: master: jdbc-url: jdbc:mysql://master域名:3306/test username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver slave1: jdbc-url: jdbc:mysql://slave域名:3306/test username: root   # 只读账户 password: 123456 driver-class-name: com.mysql.jdbc.Driver slave2: jdbc-url: jdbc:mysql://slave域名:3306/test username: root   # 只读账户 password: 123456 driver-class-name: com.mysql.jdbc.Driver 
 package com.cjs.example.enums; public enum DBTypeEnum { MASTER, SLAVE1, SLAVE2; } 

定义ThreadLocal上下文,将当前线程的数据源进行动态修改

 public class DBContextHolder { private static  volatile ThreadLocal contextHolder = new ThreadLocal(); public static synchronized void set(DBTypeEnum dbType) { contextHolder.set(dbType); } public static synchronized DBTypeEnum get() { return contextHolder.get(); } public static void master() { set(DBTypeEnum.MASTER); } public static void slave() { set(DBTypeEnum.SLAVE1); } public static void slave2(){ set(DBTypeEnum.SLAVE2); } // 清除数据源名 public static void clearDB() { contextHolder.remove(); } } 

重写mybatis数据源路由接口,在此修改数据源为我们上一块代码设置的上下文的数据源

 public class MyRoutingDataSource extends AbstractRoutingDataSource { @Nullable @Override protected Object determineCurrentLookupKey() { DBTypeEnum dbTypeEnum=DBContextHolder.get(); return dbTypeEnum; } } 

将yml配置的多数据源手动指定注入

 @Configuration public class DataSourceConfig { @Bean @ConfigurationProperties("spring.datasource.master") public DataSource masterDataSource() { return DataSourceBuilder.create().build(); } @Bean @ConfigurationProperties("spring.datasource.slave1") public DataSource slave1DataSource() { return DataSourceBuilder.create().build(); } @Bean public DataSource myRoutingDataSource(@Qualifier("masterDataSource") DataSource masterDataSource, @Qualifier("slave1DataSource") DataSource slave1DataSource) { Map targetDataSources = new HashMap(); targetDataSources.put(DBTypeEnum.MASTER, masterDataSource); targetDataSources.put(DBTypeEnum.SLAVE1, slave1DataSource); MyRoutingDataSource myRoutingDataSource = new MyRoutingDataSource(); myRoutingDataSource.setDefaultTargetDataSource(masterDataSource); myRoutingDataSource.setTargetDataSources(targetDataSources); return myRoutingDataSource; } } 

sqlsession注入以上我们配置的datasource路由

 @EnableTransactionManagement @Configuration @Import({TableSegInterceptor.class}) public class MyBatisConfig { @Resource(name = "myRoutingDataSource") private DataSource myRoutingDataSource; @Autowired private MybatisConfigProperty mybatisConfigProperty; @Autowired private TableSegInterceptor tableSegInterceptor; @Bean public SqlSessionFactory sqlSessionFactory() throws Exception { SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); sqlSessionFactoryBean.setDataSource(myRoutingDataSource); // SpringBoot项目集成mybatis打包为jar运行时setTypeAliasesPackage无效解决 VFS.addImplClass(SpringBootVFS.class); sqlSessionFactoryBean.setMapperLocations( new PathMatchingResourcePatternResolver().getResources(mybatisConfigProperty.getMapperLocations())); sqlSessionFactoryBean.setTypeAliasesPackage(mybatisConfigProperty.getTypeAliasesPackage()); sqlSessionFactoryBean.setConfigLocation( new PathMatchingResourcePatternResolver().getResource(mybatisConfigProperty.getConfigLocation())); sqlSessionFactoryBean.setPlugins(new Interceptor[]{tableSegInterceptor}); return sqlSessionFactoryBean.<em style="color:transparent">来源[email protected]搞@^&代*@码)网</em>getObject(); } @Bean public PlatformTransactionManager platformTransactionManager() { return new DataSourceTransactionManager(myRoutingDataSource); } } 

spring aop拦截指定前缀的service方法,并设置对应所属的上下文

 @Aspect @Component public class DataSourceAop { @Pointcut("!@annotation(com.ask.student.interceptor.annotation.Master) " + "&& (execution(* com.ask.student.service..*.select*(..)) " + "|| execution(* com.ask.student.service..*.get*(..))" + "|| execution(* com.ask.student.service..*.find*(..))" + ")") public void readPointcut() { } @Pointcut("@annotation(com.ask.student.interceptor.annotation.Master) " + "|| execution(* com.ask.student.service..*.insert*(..)) " + "|| execution(* com.ask.student.service..*.clean*(..)) " + "|| execution(* com.ask.student.service..*.reset*(..)) " + "|| execution(* com.ask.student.service..*.add*(..)) " + "|| execution(* com.ask.student.service..*.update*(..)) " + "|| execution(* com.ask.student.service..*.edit*(..)) " + "|| execution(* com.ask.student.service..*.delete*(..)) " + "|| execution(* com.ask.student.service..*.remove*(..))") public void writePointcut() { } @Before("readPointcut()") public void read() { DBContextHolder.slave(); } @Before("writePointcut()") public void write() { DBContextHolder.master(); } @After("readPointcut()||writePointcut()") public void afterSwitchDS(){ DBContextHolder.clearDB(); } } 

以上最后一个方法的作用,在拦截器中获取后及时清除避免导致来回切换当前线程变量延迟问题导致某些操作的数据源错误

DBContextHolder.clearDB();

@After(“readPointcut()||writePointcut()”)

public void afterSwitchDS(){

DBContextHolder.clearDB();

}

2、mybatis-plus的实现方式

这个方式配置简单,代码少,很多事情mybatis-plus都已经做好了,推荐使用

yml配置如下

 datasource: dynamic: primary: master  #设置默认的数据源或者数据源组,默认值即为master strict: false #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候会抛出异常,不启动则使用默认数据源. datasource: master: url: jdbc:mysql://xxx:3306/db0?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai username: admin password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver type: com.zaxxer.hikari.HikariDataSource hikari: minimum-idle: 5 maximum-pool-size: 15 auto-commit: true idle-timeout: 30000 pool-name: springHikariCP max-lifetime: 1800000 connection-timeout: 30000 connection-test-query: SELECT 1 slave1: url: jdbc:mysql://xxx:3306/db2?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai username: admin password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver type: com.zaxxer.hikari.HikariDataSource hikari: minimum-idle: 5 maximum-pool-size: 15 auto-commit: true idle-timeout: 30000 pool-name: springHikariCP max-lifetime: 1800000 connection-timeout: 30000 connection-test-query: SELECT 1 slave2: url: jdbc:mysql://xxx:3306/db3?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai username: admin password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver type: com.zaxxer.hikari.HikariDataSource hikari: minimum-idle: 5 maximum-pool-size: 15 auto-commit: true idle-timeout: 30000 pool-name: springHikariCP max-lifetime: 1800000 connection-timeout: 30000 connection-test-query: SELECT 1 

使用起来非常简单,只需要加上这个master的注解即可

 @Override @DS("master") public DestMedia getOneByCodeFromEpg(String code) { QueryWrapper queryWrapper = new QueryWrapper(); queryWrapper.eq("code", code); return super.getOne(queryWrapper); } 

总结

本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注gaodaima搞代码网的更多内容!

以上就是带你了解mybatis如何实现读写分离的详细内容,更多请关注gaodaima搞代码网其它相关文章!


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:带你了解mybatis如何实现读写分离

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址