亚洲精品久久久中文字幕-亚洲精品久久片久久-亚洲精品久久青草-亚洲精品久久婷婷爱久久婷婷-亚洲精品久久午夜香蕉

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

帶你了解mybatis如何實(shí)現(xiàn)讀寫分離

瀏覽:3日期:2023-10-18 13:13:30
目錄1、spring aop實(shí)現(xiàn)2、mybatis-plus的實(shí)現(xiàn)方式總結(jié)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)指定注入

@Configurationpublic 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@Componentpublic 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();

}

2、mybatis-plus的實(shí)現(xiàn)方式

這個(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 1slave1: 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 1slave2: 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); }總結(jié)

本篇文章就到這里了,希望能給你帶來幫助,也希望您能夠多多關(guān)注好吧啦網(wǎng)的更多內(nèi)容!

相關(guān)文章:
主站蜘蛛池模板: 国语自产自拍秒拍在线视频 | 成人午夜性a一级毛片美女 成人午夜性影院视频 | 永久在线观看视频 | 中文字幕亚洲欧美一区 | 又爽又黄又无遮挡的激情视频免费 | 一级aa毛片| 黄色大片在线免费看 | 毛片免费观看的视频在线 | 免费簧网站永久在线播放国产 | 国产亚洲精品成人a在线 | 在线无限看免费网站 | 啪啪三级 | 91亚洲国产成人久久精品网站 | 欧美在线精品一区二区在线观看 | 亚洲日日| 全部免费特别黄的视频播放 | 国产精品免费小视频 | 黄色动态视频 | 久热re在线视频精品免费 | 日本xxx高清免费视频 | 香蕉乱码成人久久天堂爱免费 | 成人国产在线视频在线观看 | 国产一级一片免费播放刺激 | 中美日韩在线网免费毛片视频 | 国产日韩欧美成人 | 国产在线观看成人 | 久久精品免视着国产成人 | 人与牲动交xxxxbbbb | xvideos国产| 欧美乱妇欲仙欲死视频免费 | 国产欧美亚洲精品综合在线 | 国产精品合集久久久久青苹果 | 中文字幕亚洲精品第一区 | 成年人免费观看网站 | 亚洲最大色视频 | 不卡一区二区在线 | 91久久精品国产一区二区 | 麻豆传媒在线视频 | 9久9久女女热精品视频免费观看 | 99久久综合狠狠综合久久男同 | 香港a毛片 |