您好,登錄后才能下訂單哦!
本篇文章為大家展示了mybatis中怎么實(shí)現(xiàn)讀寫分離,內(nèi)容簡(jiǎn)明扼要并且容易理解,絕對(duì)能使你眼前一亮,通過這篇文章的詳細(xì)介紹希望你能有所收獲。
1、spring aop實(shí)現(xiàn)
首先application-test.yml增加如下數(shù)據(jù)源的配置
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上下文,將當(dāng)前線程的數(shù)據(jù)源進(jìn)行動(dòng)態(tài)修改
public class DBContextHolder { private static volatile ThreadLocal<DBTypeEnum> 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); } // 清除數(shù)據(jù)源名 public static void clearDB() { contextHolder.remove(); } }
重寫mybatis數(shù)據(jù)源路由接口,在此修改數(shù)據(jù)源為我們上一塊代碼設(shè)置的上下文的數(shù)據(jù)源
public class MyRoutingDataSource extends AbstractRoutingDataSource { @Nullable @Override protected Object determineCurrentLookupKey() { DBTypeEnum dbTypeEnum=DBContextHolder.get(); return dbTypeEnum; } }
將yml配置的多數(shù)據(jù)源手動(dòng)指定注入
@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<Object, Object> 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項(xiàng)目集成mybatis打包為jar運(yùn)行時(shí)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.getObject(); } @Bean public PlatformTransactionManager platformTransactionManager() { return new DataSourceTransactionManager(myRoutingDataSource); } }
spring aop攔截指定前綴的service方法,并設(shè)置對(duì)應(yīng)所屬的上下文
@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(); } }
以上最后一個(gè)方法的作用,在攔截器中獲取后及時(shí)清除避免導(dǎo)致來回切換當(dāng)前線程變量延遲問題導(dǎo)致某些操作的數(shù)據(jù)源錯(cuò)誤
DBContextHolder.clearDB();
@After("readPointcut()||writePointcut()")
public void afterSwitchDS(){
DBContextHolder.clearDB();
}
這個(gè)方式配置簡(jiǎn)單,代碼少,很多事情mybatis-plus都已經(jīng)做好了,推薦使用
yml配置如下
datasource: dynamic: primary: master #設(shè)置默認(rèn)的數(shù)據(jù)源或者數(shù)據(jù)源組,默認(rèn)值即為master strict: false #設(shè)置嚴(yán)格模式,默認(rèn)false不啟動(dòng). 啟動(dòng)后在未匹配到指定數(shù)據(jù)源時(shí)候會(huì)拋出異常,不啟動(dòng)則使用默認(rèn)數(shù)據(jù)源. 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
使用起來非常簡(jiǎn)單,只需要加上這個(gè)master的注解即可
@Override @DS("master") public DestMedia getOneByCodeFromEpg(String code) { QueryWrapper queryWrapper = new QueryWrapper(); queryWrapper.eq("code", code); return super.getOne(queryWrapper); }
上述內(nèi)容就是mybatis中怎么實(shí)現(xiàn)讀寫分離,你們學(xué)到知識(shí)或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識(shí)儲(chǔ)備,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。