SpringBoot 读写分离(配Mysql5.7) 笔记
创始人
2024-04-06 17:10:35

目录

需求

环境

数据库表字段

操作笔记

MyBatis自动生成mapper、xml的配置

读写分离切换的代码实现

入口主类代码

创建WebAPI实现读主库、读从库、写主库

验证读写分离

拓展读写分离(写一个库,读多个库)


需求

有主从两个数据库(结构一致),期望在SpringBoot程序层面实现读写分离。

具体需求:SpringBoot程序的写操作均进入主库;SpringBoot程序的读操作均访问从库。

(这里为便于区分主从库,二者初始数据不一致,但结构完全一致)

环境

开发环境:win7 x64+IDEA2018

java version :"1.8.0_111"

mysql数据库版本5.7.10

mysql主库:192.168.7.161:3306

mysql从库:192.168.7.162:3306

SpringBoot版本2.3.7

数据库表字段

数据库名:dbdemo

数据表:categories和products;

mysql> use dbdemo;
Database changed
mysql> show tables;
+------------------+
| Tables_in_dbdemo |
+------------------+
| categories       |
| products         |
+------------------+
2 rows in set (0.02 sec)mysql> show create table categories;
+------------+--------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------+
| Table      | Create Table|
+------------+--------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------+
| categories | CREATE TABLE `categories` (`cat_id` int(11) NOT NULL AUTO_INCREMENT,`cat_name` varchar(255) NOT NULL,`cat_description` text,`cat_date` datetime DEFAULT NULL,PRIMARY KEY (`cat_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 |
+------------+--------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------+
1 row in set (0.23 sec)mysql> show create table products;
+----------+----------------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------+
| Table    | Create Table|
+----------+----------------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------+
| products | CREATE TABLE `products` (`prd_id` int(11) NOT NULL AUTO_INCREMENT,`prd_name` varchar(355) NOT NULL,`prd_price` decimal(10,0) DEFAULT NULL,`prd_date` datetime DEFAULT NULL,`cat_id` int(11) NOT NULL,PRIMARY KEY (`prd_id`),KEY `fk_cat` (`cat_id`),CONSTRAINT `products_ibfk_1` FOREIGN KEY (`cat_id`) REFERENCES `categories` (`cat_id`) ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8 |
+----------+----------------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.09 sec)mysql>

操作笔记

IDEA新建SpringBoot应用程序,添加了mybatis-generator-maven-plugin,jdbc,aop等依赖。

基于切面和自定义注解实现了读写分离。

项目结构如下

完整pom.xm如下:


4.0.0com.wdhspringboot-read-write-split-mysql0.0.1-SNAPSHOTspringboot-read-write-split-mysqlDemo project for Spring Boot1.8UTF-8UTF-82.3.7.RELEASEorg.springframework.bootspring-boot-starter-weborg.projectlomboklomboktrueorg.apache.commonscommons-lang3org.springframework.bootspring-boot-starter-aoporg.springframework.bootspring-boot-starter-data-jdbcorg.springframework.bootspring-boot-starter-jdbcorg.mybatis.spring.bootmybatis-spring-boot-starter2.1.4mysqlmysql-connector-java8.0.22org.springframework.bootspring-boot-starter-testtestorg.junit.vintagejunit-vintage-engineorg.springframework.bootspring-boot-dependencies${spring-boot.version}pomimportorg.apache.maven.pluginsmaven-compiler-plugin3.8.11.81.8UTF-8org.springframework.bootspring-boot-maven-plugin2.3.7.RELEASEcom.wdh.springbootreadwritesplitmysql.SpringbootReadWriteSplitMysqlApplicationrepackagerepackageorg.mybatis.generatormybatis-generator-maven-plugin1.3.1src\main\resources\mybatis-generator\generatorConfig.xmlfalsetrue

application.properties内容如下,配置了mysql主库和从库的连接信息

# 应用名称
spring.application.name=springboot-read-write-split-mysql
# 应用服务 WEB 访问端口
server.port=8080#这是自定义的mysql主数据库的访问配置
spring.datasource.master.driver-class-name=com.mysql.cj.jdbc.Driver
#以下是配合默认的spring.datasource.hikari的jdbcUrl
spring.datasource.master.jdbcUrl=jdbc:mysql://192.168.7.161:3306/dbdemo?serverTimezone=UTC
spring.datasource.master.username=root
spring.datasource.master.[CSDN不让发]password[CSDN不让发]=XX你的密码XX#这是自定义的mysql从数据库的访问配置
spring.datasource.slave.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.slave.jdbcUrl=jdbc:mysql://192.168.7.162:3306/dbdemo?serverTimezone=UTC
spring.datasource.slave.username=root
spring.datasource.slave.[CSDN不让发]password[CSDN不让发]=XX你的密码XX

MyBatis自动生成mapper、xml的配置

在src\main\resources下新建mybatis-generator目录及目录下generatorConfig.xml。

src\main\resources\mybatis-generator\generatorConfig.xml

前述pom.xml中的以下内容是指定使用此文件进行mybatis自动生成

org.mybatis.generatormybatis-generator-maven-plugin1.3.1src\main\resources\mybatis-generator\generatorConfig.xmlfalsetrue

generatorConfig.xml完整内容如下。(说明见注释)



注意,因主库和从库结构一致,上述配置文件中定义了按主库配置连接信息,访问并生成mapper和xml.

配置完generatorConfig.xml后,在idea右侧Maven面板-本项目-Plugins-刷新-找到mybatis-generate-点击右键Run Maven Build即可生成代码。生成过程及日志见idea的控制台输出。

(pom.xml中配置mybatis-generator后需要手动在idea的maven面板左上角点击刷新按钮才会在Plugins下显示mybatis-generator)

执行之后将自动在【src\main\java\com\wdh\springbootreadwritesplitmysql\mapper】目录下生成【xx表名xxMapper.java】

自动在【src\main\resources\mappers】目录下生成【xx表名xxMapper.xml】文件。

读写分离切换的代码实现

定义主从库枚举类型

package com.wdh.springbootreadwritesplitmysql.enums;/*** @author WangDH* @create 2022-11-10 13:51** 数据源类型枚举*/
public enum DBTypeEnum {//数据库主库MASTER,//数据库从库SLAVE
}

定义DBContextHolder用于访问枚举和枚举变量记录切换,DBContextHolder.java代码如下

package com.wdh.springbootreadwritesplitmysql.bean;import com.wdh.springbootreadwritesplitmysql.enums.DBTypeEnum;import java.util.concurrent.atomic.AtomicInteger;/*** @author WangDH* @create 2022-11-10 13:59*/
public class DBContextHolder {private static final ThreadLocal contextHolder=new ThreadLocal<>();private static final AtomicInteger counter=new AtomicInteger(-1);public static void set(DBTypeEnum dbTypeEnum){contextHolder.set(dbTypeEnum);}public static DBTypeEnum get(){return contextHolder.get();}public static void master(){set(DBTypeEnum.MASTER);System.out.println("切换到master");}public static void slave(){set(DBTypeEnum.SLAVE);System.out.println("切换到slave");}}

自定义MyRoutingDataSource实现AbstractRoutingDataSource,AbstractRoutingDataSource提供了程序运行时动态切换数据源的方法。MyRoutingDataSource.java代码如下。

package com.wdh.springbootreadwritesplitmysql.bean;import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.lang.Nullable;/*** @author WangDH* @create 2022-11-10 13:57*/
public class MyRoutingDataSource extends AbstractRoutingDataSource {@Nullable@Overrideprotected Object determineCurrentLookupKey() {Object obj= DBContextHolder.get();return obj;}
}

定义DataSourceConfig数据源配置类初始化两个数据源和获取动态数据源。DataSourceConfig.java代码如下

package com.wdh.springbootreadwritesplitmysql.config;import com.wdh.springbootreadwritesplitmysql.bean.MyRoutingDataSource;
import com.wdh.springbootreadwritesplitmysql.enums.DBTypeEnum;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;/*** @author WangDH* @create 2022-11-10 11:42*** 自定义两个数据源,主库数据源,从库数据源*/
@Configuration
public class DataSourceConfig {//定义Mysql主库数据源@Bean@ConfigurationProperties("spring.datasource.master")//从配置文件读取spring.datasource.master开头的相关配置进行数据源初始化public DataSource DataSourceMaster(){return DataSourceBuilder.create().build();}//定义Mysql从库数据源@Bean@ConfigurationProperties("spring.datasource.slave")public DataSource DataSourceSlave(){return DataSourceBuilder.create().build();}@Beanpublic DataSource myRoutingDataSource(//@Qualifier 类似于@Autowired注解实现Spring依赖注入,但@Qualifier用来指定应该注入特定类型的bean,防止依赖注入冲突@Qualifier("DataSourceMaster") DataSource dataSourceMaster,@Qualifier("DataSourceSlave") DataSource dataSourceSlave){Map targetDataSource=new HashMap<>(2);targetDataSource.put(DBTypeEnum.MASTER,dataSourceMaster);targetDataSource.put(DBTypeEnum.SLAVE,dataSourceSlave);MyRoutingDataSource routingDataSource=new MyRoutingDataSource();routingDataSource.setDefaultTargetDataSource(dataSourceMaster);routingDataSource.setTargetDataSources(targetDataSource);return routingDataSource;}}

创建MyBatisConfig.java,其中构建SqlSessionFactory 对象访问动态数据源,以便这获取到mybatis操作数据库的 SqlSession 对象,进而通过mybatis操作数据库。

MyBatisConfig.java代码如下。(这里有个坑,报错是【FileNotFoundException: class path resource [mappers/*.xml] cannot be opened because it does not exist】,原因是,要写成getResources 不要误写成getResource,见注释)

package com.wdh.springbootreadwritesplitmysql.config;import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;import javax.annotation.Resource;
import javax.sql.DataSource;/*** @author WangDH* @create 2022-11-10 14:26*/
@EnableTransactionManagement
@Configuration
public class MyBatisConfig {@Resource(name="myRoutingDataSource") //@Resource默认按byName自动注入private DataSource myRoutingDataSource;@Beanpublic SqlSessionFactory sqlSessionFactory() throws Exception{///org.springframework.core.io.Resource resourceMappersXml=new PathMatchingResourcePatternResolver().getResource("classpath:mappers/*.xml");//上述代码报错:Factory method 'sqlSessionFactory' threw exception; nested exception is org.springframework.core.NestedIOException: Failed to parse mapping resource: 'class path resource [mappers/*.xml]'; nested exception is java.io.FileNotFoundException: class path resource [mappers/*.xml] cannot be opened because it does not existorg.springframework.core.io.Resource[] resourceMappersXml=new PathMatchingResourcePatternResolver().getResources("classpath:mappers/*.xml");//注意这里是getResources 不要误写成getResource//参考https://www.cnblogs.com/jev-0987/p/12839193.html//getResource():        //1.从类的根路径下获取文件//getResources():        //1.获取所有类路径下的指定文件SqlSessionFactoryBean sqlSessionFactoryBean=new SqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(myRoutingDataSource);sqlSessionFactoryBean.setMapperLocations(resourceMappersXml);SqlSessionFactory sqlSessionFactory= sqlSessionFactoryBean.getObject();return sqlSessionFactory;}@Beanpublic PlatformTransactionManager platformTransactionManager(){return new DataSourceTransactionManager(myRoutingDataSource);}}

编码两个自定义注解,用于标记方法是操作主库还是从库。

Master.java代码

package com.wdh.springbootreadwritesplitmysql.annotation;/*** @author WangDH* @create 2022-11-10 14:03** 定义一种注解,加此注解的方法查询主库(主数据库)*/
public @interface Master {
}
Slave.java代码
package com.wdh.springbootreadwritesplitmysql.annotation;/*** @author WangDH* @create 2022-11-11 11:25* 定义一种注解,加此注解的方法查询从库(从数据库)*/
public @interface Slave {
}

关键部分来了,切面编程,aop。

DataSourceAop.java代码如下
package com.wdh.springbootreadwritesplitmysql.aop;import com.wdh.springbootreadwritesplitmysql.bean.DBContextHolder;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;/*** @author WangDH* @create 2022-11-10 14:53*/
@Aspect
@Component
public class DataSourceAop {//    //读切面(条件:没有Master注解)
//    @Pointcut(
//            "!@annotation(com.wdh.springbootreadwritesplitmysql.annotation.Master)"  //如果使用!@annotation,则必须加&&(execution指定包范围,否则会导致所有方法都被切面捕获而导致启动失败
//            +"&&(execution(* com.wdh.springbootreadwritesplitmysql.service.*.*(..)))"
//    )//切面切入点(条件:有Slave注解)的方法使用从库数据源@Pointcut("@annotation(com.wdh.springbootreadwritesplitmysql.annotation.Slave)")public void readPointcut(){}//切面切入点,(条件:有Master注解)的方法使用主库数据源@Pointcut("@annotation(com.wdh.springbootreadwritesplitmysql.annotation.Master)"//+"&&(execution(* com.wdh.springbootreadwritesplitmysql.service.*.*(..)))")public void writePointcut(){}//Before方法,读切面前设置ThreadLocal里变量为slave@Before("readPointcut()")public void read(){DBContextHolder.slave();}//Before方法,写切面前设置ThreadLocal里变量为master@Before("writePointcut()")public void write(){DBContextHolder.master();}}

入口主类代码

SpringbootReadWriteSplitMysqlApplication.java

注意,增加了@MapperScan扫描指定包,以便mybatis扫描到XXXMapper.java进行自动注入。

package com.wdh.springbootreadwritesplitmysql;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
@MapperScan("com.wdh.springbootreadwritesplitmysql.mapper")
public class SpringbootReadWriteSplitMysqlApplication {public static void main(String[] args) {SpringApplication.run(SpringbootReadWriteSplitMysqlApplication.class, args);//参考https://blog.csdn.net/qq_37171353/article/details/111999618//参考https://github.com/cbeann/Demooo/tree/master/springboot-readwrite-separation-deno/src//前提:需要主从两个数据库//启动springboot后浏览器访问【http://localhost:8080/product/hello】测试是否正常//浏览器访问【http://localhost:8080/product/allm】读取主库//浏览器访问【http://localhost:8080/product/alls】读取从库//浏览器访问【http://localhost:8080/product/insert/M1336】写入主库。(如mysql做了主从复制,则自动复制到从库)}}

创建WebAPI实现读主库、读从库、写主库

Controller层 ProductController.java代码

package com.wdh.springbootreadwritesplitmysql.controller;import com.wdh.springbootreadwritesplitmysql.entity.Products;
import com.wdh.springbootreadwritesplitmysql.service.ProductsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.Date;
import java.util.List;/*** @author WangDH* @create 2022-11-10 16:54*/
@RestController
@RequestMapping("/product")
public class ProductController {@Autowiredprivate ProductsService productsService;@GetMapping("/hello")public String hello(){return "ok,this is ProductController.";}@GetMapping("/allm")public List allM(){List list=productsService.getAllMaster();return list;}@GetMapping("/alls")public List allS(){List list=productsService.getAllSlave();return list;}@GetMapping("/insert/{name}")public String insert(@PathVariable("name") String prdName){Date date=new Date();String prdNameJoin="SpringRW_"+prdName+"_"+date.toString();Products prd=new Products();prd.setPrdName(prdNameJoin);prd.setPrdPrice((long)1110);prd.setPrdDate(date);prd.setCatId(2);int retIns=productsService.insert(prd);//进主库,可以测试关掉从库测试能否写成功。return "retIns="+retIns+","+(retIns>0?"ok":"fail");}}

Service层代码,ProductsService.java

特别注意,

Service层写主库的方法上增加了@Master注解,例如insert方法;

Service层读主库的方法上增加了@Master注解,例如getAllMaster();

Service层读从库的方法上增加了@Slave注解,例如getAllSlave();

通过添加不同注解的方式标记哪个方法操作主库,哪个方法操作从库。当然也有博友在aop中通过表达式方式匹配不同方法名,也可。DataSourceAop.java的注释中也有。

package com.wdh.springbootreadwritesplitmysql.service;import com.wdh.springbootreadwritesplitmysql.annotation.Master;
import com.wdh.springbootreadwritesplitmysql.annotation.Slave;
import com.wdh.springbootreadwritesplitmysql.entity.Products;
import com.wdh.springbootreadwritesplitmysql.mapper.ProductsMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;/*** @author WangDH* @create 2022-11-10 16:32*/
@Service
public class ProductsService {//注意,需要所有Service层访问数据库的方法必须增加@Slave或@Master注解,以标明是操作从库还是操作主库@Autowiredprivate ProductsMapper productsMapper;@Slavepublic List getAllSlave(){List listSlave= productsMapper.selectAll();return listSlave;}//标记为由主库读@Masterpublic List getAllMaster(){List list= productsMapper.selectAll();return list;}//标记为进入主库写@Masterpublic int insert(Products record){return productsMapper.insert(record);}}

Mapper层修改,ProductsMapper.java是自动生成的,由于没有查询全表的方法,这里手动增加一个方法

List selectAll();

,同步需要修改ProductsMapper.xml。

修改部分如下

  

ProductsMapper.java完整代码如下;

package com.wdh.springbootreadwritesplitmysql.mapper;import com.wdh.springbootreadwritesplitmysql.entity.Products;import java.util.List;public interface ProductsMapper {/*** This method was generated by MyBatis Generator.* This method corresponds to the database table products** @mbggenerated Thu Nov 10 16:13:23 CST 2022*/int deleteByPrimaryKey(Integer prdId);/*** This method was generated by MyBatis Generator.* This method corresponds to the database table products** @mbggenerated Thu Nov 10 16:13:23 CST 2022*/int insert(Products record);/*** This method was generated by MyBatis Generator.* This method corresponds to the database table products** @mbggenerated Thu Nov 10 16:13:23 CST 2022*/int insertSelective(Products record);/*** This method was generated by MyBatis Generator.* This method corresponds to the database table products** @mbggenerated Thu Nov 10 16:13:23 CST 2022*/Products selectByPrimaryKey(Integer prdId);//wdh自定义增加的查询函数,需要ProductsMapper.xml有配置selectAll查询sqlList selectAll();/*** This method was generated by MyBatis Generator.* This method corresponds to the database table products** @mbggenerated Thu Nov 10 16:13:23 CST 2022*/int updateByPrimaryKeySelective(Products record);/*** This method was generated by MyBatis Generator.* This method corresponds to the database table products** @mbggenerated Thu Nov 10 16:13:23 CST 2022*/int updateByPrimaryKey(Products record);
}

ProductsMapper.xml全文



prd_id, prd_name, prd_price, prd_date, cat_iddelete from productswhere prd_id = #{prdId,jdbcType=INTEGER}insert into products (prd_id, prd_name, prd_price, prd_date, cat_id)values (#{prdId,jdbcType=INTEGER}, #{prdName,jdbcType=VARCHAR}, #{prdPrice,jdbcType=DECIMAL}, #{prdDate,jdbcType=TIMESTAMP}, #{catId,jdbcType=INTEGER})insert into productsprd_id,prd_name,prd_price,prd_date,cat_id,#{prdId,jdbcType=INTEGER},#{prdName,jdbcType=VARCHAR},#{prdPrice,jdbcType=DECIMAL},#{prdDate,jdbcType=TIMESTAMP},#{catId,jdbcType=INTEGER},update productsprd_name = #{prdName,jdbcType=VARCHAR},prd_price = #{prdPrice,jdbcType=DECIMAL},prd_date = #{prdDate,jdbcType=TIMESTAMP},cat_id = #{catId,jdbcType=INTEGER},where prd_id = #{prdId,jdbcType=INTEGER}update productsset prd_name = #{prdName,jdbcType=VARCHAR},prd_price = #{prdPrice,jdbcType=DECIMAL},prd_date = #{prdDate,jdbcType=TIMESTAMP},cat_id = #{catId,jdbcType=INTEGER}where prd_id = #{prdId,jdbcType=INTEGER}

entity层的Products.java代码是自动生成的,代码未变,也附上。

package com.wdh.springbootreadwritesplitmysql.entity;import lombok.Data;import java.util.Date;@Data
public class Products {/*** This field was generated by MyBatis Generator.* This field corresponds to the database column products.prd_id** @mbggenerated Thu Nov 10 16:13:23 CST 2022*/private Integer prdId;/*** This field was generated by MyBatis Generator.* This field corresponds to the database column products.prd_name** @mbggenerated Thu Nov 10 16:13:23 CST 2022*/private String prdName;/*** This field was generated by MyBatis Generator.* This field corresponds to the database column products.prd_price** @mbggenerated Thu Nov 10 16:13:23 CST 2022*/private Long prdPrice;/*** This field was generated by MyBatis Generator.* This field corresponds to the database column products.prd_date** @mbggenerated Thu Nov 10 16:13:23 CST 2022*/private Date prdDate;/*** This field was generated by MyBatis Generator.* This field corresponds to the database column products.cat_id** @mbggenerated Thu Nov 10 16:13:23 CST 2022*/private Integer catId;/*** This method was generated by MyBatis Generator.* This method returns the value of the database column products.prd_id** @return the value of products.prd_id** @mbggenerated Thu Nov 10 16:13:23 CST 2022*/public Integer getPrdId() {return prdId;}/*** This method was generated by MyBatis Generator.* This method sets the value of the database column products.prd_id** @param prdId the value for products.prd_id** @mbggenerated Thu Nov 10 16:13:23 CST 2022*/public void setPrdId(Integer prdId) {this.prdId = prdId;}/*** This method was generated by MyBatis Generator.* This method returns the value of the database column products.prd_name** @return the value of products.prd_name** @mbggenerated Thu Nov 10 16:13:23 CST 2022*/public String getPrdName() {return prdName;}/*** This method was generated by MyBatis Generator.* This method sets the value of the database column products.prd_name** @param prdName the value for products.prd_name** @mbggenerated Thu Nov 10 16:13:23 CST 2022*/public void setPrdName(String prdName) {this.prdName = prdName == null ? null : prdName.trim();}/*** This method was generated by MyBatis Generator.* This method returns the value of the database column products.prd_price** @return the value of products.prd_price** @mbggenerated Thu Nov 10 16:13:23 CST 2022*/public Long getPrdPrice() {return prdPrice;}/*** This method was generated by MyBatis Generator.* This method sets the value of the database column products.prd_price** @param prdPrice the value for products.prd_price** @mbggenerated Thu Nov 10 16:13:23 CST 2022*/public void setPrdPrice(Long prdPrice) {this.prdPrice = prdPrice;}/*** This method was generated by MyBatis Generator.* This method returns the value of the database column products.prd_date** @return the value of products.prd_date** @mbggenerated Thu Nov 10 16:13:23 CST 2022*/public Date getPrdDate() {return prdDate;}/*** This method was generated by MyBatis Generator.* This method sets the value of the database column products.prd_date** @param prdDate the value for products.prd_date** @mbggenerated Thu Nov 10 16:13:23 CST 2022*/public void setPrdDate(Date prdDate) {this.prdDate = prdDate;}/*** This method was generated by MyBatis Generator.* This method returns the value of the database column products.cat_id** @return the value of products.cat_id** @mbggenerated Thu Nov 10 16:13:23 CST 2022*/public Integer getCatId() {return catId;}/*** This method was generated by MyBatis Generator.* This method sets the value of the database column products.cat_id** @param catId the value for products.cat_id** @mbggenerated Thu Nov 10 16:13:23 CST 2022*/public void setCatId(Integer catId) {this.catId = catId;}
}

验证读写分离

背景,主库和从库中Products表的数据行数是不一样的。主库此表内记录多,从库此表内记录少。

如果执行方法可以根据@Master或@Slave实现读写分离,目的即为达成。

验证前准备:主从两个数据库已启动且可访问。

启动springboot,IDEA控制台打印的成功日志如下

"C:\Program Files\Java\jdk1.8.0_111\bin\java.exe" -XX:TieredStopAtLevel=1 -noverify -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true "-javaagent:D:\JavaDevEnv\JetBrains\IntelliJ IDEA 2018.3.6\lib\idea_rt.jar=62267:D:\JavaDevEnv\JetBrains\IntelliJ IDEA 2018.3.6\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_111\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\rt.jar;D:\JavaWorkspace\IdeaProjects\SpringInAction\springboot-read-write-split-mysql\target\classes;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-starter-web\2.3.7.RELEASE\spring-boot-starter-web-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-starter\2.3.7.RELEASE\spring-boot-starter-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot\2.3.7.RELEASE\spring-boot-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-autoconfigure\2.3.7.RELEASE\spring-boot-autoconfigure-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-starter-logging\2.3.7.RELEASE\spring-boot-starter-logging-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;D:\JavaDevEnv\maven_repository\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;D:\JavaDevEnv\maven_repository\org\apache\logging\log4j\log4j-to-slf4j\2.13.3\log4j-to-slf4j-2.13.3.jar;D:\JavaDevEnv\maven_repository\org\apache\logging\log4j\log4j-api\2.13.3\log4j-api-2.13.3.jar;D:\JavaDevEnv\maven_repository\org\slf4j\jul-to-slf4j\1.7.30\jul-to-slf4j-1.7.30.jar;D:\JavaDevEnv\maven_repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;D:\JavaDevEnv\maven_repository\org\yaml\snakeyaml\1.26\snakeyaml-1.26.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-starter-json\2.3.7.RELEASE\spring-boot-starter-json-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\com\fasterxml\jackson\core\jackson-databind\2.11.3\jackson-databind-2.11.3.jar;D:\JavaDevEnv\maven_repository\com\fasterxml\jackson\core\jackson-annotations\2.11.3\jackson-annotations-2.11.3.jar;D:\JavaDevEnv\maven_repository\com\fasterxml\jackson\core\jackson-core\2.11.3\jackson-core-2.11.3.jar;D:\JavaDevEnv\maven_repository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.11.3\jackson-datatype-jdk8-2.11.3.jar;D:\JavaDevEnv\maven_repository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.11.3\jackson-datatype-jsr310-2.11.3.jar;D:\JavaDevEnv\maven_repository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.11.3\jackson-module-parameter-names-2.11.3.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-starter-tomcat\2.3.7.RELEASE\spring-boot-starter-tomcat-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\apache\tomcat\embed\tomcat-embed-core\9.0.41\tomcat-embed-core-9.0.41.jar;D:\JavaDevEnv\maven_repository\org\glassfish\jakarta.el\3.0.3\jakarta.el-3.0.3.jar;D:\JavaDevEnv\maven_repository\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.41\tomcat-embed-websocket-9.0.41.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-web\5.2.12.RELEASE\spring-web-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-beans\5.2.12.RELEASE\spring-beans-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-webmvc\5.2.12.RELEASE\spring-webmvc-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-context\5.2.12.RELEASE\spring-context-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-expression\5.2.12.RELEASE\spring-expression-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\projectlombok\lombok\1.18.16\lombok-1.18.16.jar;D:\JavaDevEnv\maven_repository\org\apache\commons\commons-lang3\3.10\commons-lang3-3.10.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-starter-aop\2.3.7.RELEASE\spring-boot-starter-aop-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-aop\5.2.12.RELEASE\spring-aop-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\aspectj\aspectjweaver\1.9.6\aspectjweaver-1.9.6.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-starter-data-jdbc\2.3.7.RELEASE\spring-boot-starter-data-jdbc-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\data\spring-data-jdbc\2.0.6.RELEASE\spring-data-jdbc-2.0.6.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\data\spring-data-relational\2.0.6.RELEASE\spring-data-relational-2.0.6.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\data\spring-data-commons\2.3.6.RELEASE\spring-data-commons-2.3.6.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-tx\5.2.12.RELEASE\spring-tx-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-starter-jdbc\2.3.7.RELEASE\spring-boot-starter-jdbc-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\com\zaxxer\HikariCP\3.4.5\HikariCP-3.4.5.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-jdbc\5.2.12.RELEASE\spring-jdbc-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\mybatis\spring\boot\mybatis-spring-boot-starter\2.1.4\mybatis-spring-boot-starter-2.1.4.jar;D:\JavaDevEnv\maven_repository\org\mybatis\spring\boot\mybatis-spring-boot-autoconfigure\2.1.4\mybatis-spring-boot-autoconfigure-2.1.4.jar;D:\JavaDevEnv\maven_repository\org\mybatis\mybatis\3.5.6\mybatis-3.5.6.jar;D:\JavaDevEnv\maven_repository\org\mybatis\mybatis-spring\2.0.6\mybatis-spring-2.0.6.jar;D:\JavaDevEnv\maven_repository\Mysql\mysql-connector-java\8.0.22\mysql-connector-java-8.0.22.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-core\5.2.12.RELEASE\spring-core-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-jcl\5.2.12.RELEASE\spring-jcl-5.2.12.RELEASE.jar" com.wdh.springbootreadwritesplitmysql.SpringbootReadWriteSplitMysqlApplication.   ____          _            __ _ _/\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \\\/  ___)| |_)| | | | | || (_| |  ) ) ) )'  |____| .__|_| |_|_| |_\__, | / / / /=========|_|==============|___/=/_/_/_/:: Spring Boot ::        (v2.3.7.RELEASE)2022-11-11 16:43:26.762  INFO 2452 --- [           main] SpringbootReadWriteSplitMysqlApplication : Starting SpringbootReadWriteSplitMysqlApplication on 14JPYI7CBESDNFK with PID 2452 (D:\JavaWorkspace\IdeaProjects\SpringInAction\springboot-read-write-split-mysql\target\classes started by Administrator in D:\JavaWorkspace\IdeaProjects\SpringInAction\springboot-read-write-split-mysql)
2022-11-11 16:43:26.762  INFO 2452 --- [           main] SpringbootReadWriteSplitMysqlApplication : No active profile set, falling back to default profiles: default
2022-11-11 16:43:28.525  INFO 2452 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2022-11-11 16:43:28.541  INFO 2452 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2022-11-11 16:43:28.541  INFO 2452 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.41]
2022-11-11 16:43:28.606  INFO 2452 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2022-11-11 16:43:28.606  INFO 2452 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1781 ms
2022-11-11 16:43:30.028  INFO 2452 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2022-11-11 16:43:30.511  INFO 2452 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2022-11-11 16:43:30.511  INFO 2452 --- [           main] SpringbootReadWriteSplitMysqlApplication : Started SpringbootReadWriteSplitMysqlApplication in 4.093 seconds (JVM running for 4.693)

浏览器访问【http://localhost:8080/product/hello】测试未访问数据库时,仅rest服务是否正常,以下是正常截图。

浏览器访问【http://localhost:8080/product/allm】读取主库,成功图示如下

读取主库,IDEA控制台日志如下。可以看到在访问数据库时DBContextHolder.java打印出”切换到master“的日志。

"C:\Program Files\Java\jdk1.8.0_111\bin\java.exe" -XX:TieredStopAtLevel=1 -noverify -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true "-javaagent:D:\JavaDevEnv\JetBrains\IntelliJ IDEA 2018.3.6\lib\idea_rt.jar=62267:D:\JavaDevEnv\JetBrains\IntelliJ IDEA 2018.3.6\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_111\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\rt.jar;D:\JavaWorkspace\IdeaProjects\SpringInAction\springboot-read-write-split-mysql\target\classes;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-starter-web\2.3.7.RELEASE\spring-boot-starter-web-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-starter\2.3.7.RELEASE\spring-boot-starter-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot\2.3.7.RELEASE\spring-boot-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-autoconfigure\2.3.7.RELEASE\spring-boot-autoconfigure-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-starter-logging\2.3.7.RELEASE\spring-boot-starter-logging-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;D:\JavaDevEnv\maven_repository\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;D:\JavaDevEnv\maven_repository\org\apache\logging\log4j\log4j-to-slf4j\2.13.3\log4j-to-slf4j-2.13.3.jar;D:\JavaDevEnv\maven_repository\org\apache\logging\log4j\log4j-api\2.13.3\log4j-api-2.13.3.jar;D:\JavaDevEnv\maven_repository\org\slf4j\jul-to-slf4j\1.7.30\jul-to-slf4j-1.7.30.jar;D:\JavaDevEnv\maven_repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;D:\JavaDevEnv\maven_repository\org\yaml\snakeyaml\1.26\snakeyaml-1.26.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-starter-json\2.3.7.RELEASE\spring-boot-starter-json-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\com\fasterxml\jackson\core\jackson-databind\2.11.3\jackson-databind-2.11.3.jar;D:\JavaDevEnv\maven_repository\com\fasterxml\jackson\core\jackson-annotations\2.11.3\jackson-annotations-2.11.3.jar;D:\JavaDevEnv\maven_repository\com\fasterxml\jackson\core\jackson-core\2.11.3\jackson-core-2.11.3.jar;D:\JavaDevEnv\maven_repository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.11.3\jackson-datatype-jdk8-2.11.3.jar;D:\JavaDevEnv\maven_repository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.11.3\jackson-datatype-jsr310-2.11.3.jar;D:\JavaDevEnv\maven_repository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.11.3\jackson-module-parameter-names-2.11.3.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-starter-tomcat\2.3.7.RELEASE\spring-boot-starter-tomcat-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\apache\tomcat\embed\tomcat-embed-core\9.0.41\tomcat-embed-core-9.0.41.jar;D:\JavaDevEnv\maven_repository\org\glassfish\jakarta.el\3.0.3\jakarta.el-3.0.3.jar;D:\JavaDevEnv\maven_repository\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.41\tomcat-embed-websocket-9.0.41.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-web\5.2.12.RELEASE\spring-web-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-beans\5.2.12.RELEASE\spring-beans-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-webmvc\5.2.12.RELEASE\spring-webmvc-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-context\5.2.12.RELEASE\spring-context-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-expression\5.2.12.RELEASE\spring-expression-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\projectlombok\lombok\1.18.16\lombok-1.18.16.jar;D:\JavaDevEnv\maven_repository\org\apache\commons\commons-lang3\3.10\commons-lang3-3.10.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-starter-aop\2.3.7.RELEASE\spring-boot-starter-aop-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-aop\5.2.12.RELEASE\spring-aop-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\aspectj\aspectjweaver\1.9.6\aspectjweaver-1.9.6.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-starter-data-jdbc\2.3.7.RELEASE\spring-boot-starter-data-jdbc-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\data\spring-data-jdbc\2.0.6.RELEASE\spring-data-jdbc-2.0.6.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\data\spring-data-relational\2.0.6.RELEASE\spring-data-relational-2.0.6.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\data\spring-data-commons\2.3.6.RELEASE\spring-data-commons-2.3.6.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-tx\5.2.12.RELEASE\spring-tx-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-starter-jdbc\2.3.7.RELEASE\spring-boot-starter-jdbc-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\com\zaxxer\HikariCP\3.4.5\HikariCP-3.4.5.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-jdbc\5.2.12.RELEASE\spring-jdbc-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\mybatis\spring\boot\mybatis-spring-boot-starter\2.1.4\mybatis-spring-boot-starter-2.1.4.jar;D:\JavaDevEnv\maven_repository\org\mybatis\spring\boot\mybatis-spring-boot-autoconfigure\2.1.4\mybatis-spring-boot-autoconfigure-2.1.4.jar;D:\JavaDevEnv\maven_repository\org\mybatis\mybatis\3.5.6\mybatis-3.5.6.jar;D:\JavaDevEnv\maven_repository\org\mybatis\mybatis-spring\2.0.6\mybatis-spring-2.0.6.jar;D:\JavaDevEnv\maven_repository\Mysql\mysql-connector-java\8.0.22\mysql-connector-java-8.0.22.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-core\5.2.12.RELEASE\spring-core-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-jcl\5.2.12.RELEASE\spring-jcl-5.2.12.RELEASE.jar" com.wdh.springbootreadwritesplitmysql.SpringbootReadWriteSplitMysqlApplication.   ____          _            __ _ _/\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \\\/  ___)| |_)| | | | | || (_| |  ) ) ) )'  |____| .__|_| |_|_| |_\__, | / / / /=========|_|==============|___/=/_/_/_/:: Spring Boot ::        (v2.3.7.RELEASE)2022-11-11 16:43:26.762  INFO 2452 --- [           main] SpringbootReadWriteSplitMysqlApplication : Starting SpringbootReadWriteSplitMysqlApplication on 14JPYI7CBESDNFK with PID 2452 (D:\JavaWorkspace\IdeaProjects\SpringInAction\springboot-read-write-split-mysql\target\classes started by Administrator in D:\JavaWorkspace\IdeaProjects\SpringInAction\springboot-read-write-split-mysql)
2022-11-11 16:43:26.762  INFO 2452 --- [           main] SpringbootReadWriteSplitMysqlApplication : No active profile set, falling back to default profiles: default
2022-11-11 16:43:28.525  INFO 2452 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2022-11-11 16:43:28.541  INFO 2452 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2022-11-11 16:43:28.541  INFO 2452 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.41]
2022-11-11 16:43:28.606  INFO 2452 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2022-11-11 16:43:28.606  INFO 2452 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1781 ms
2022-11-11 16:43:30.028  INFO 2452 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2022-11-11 16:43:30.511  INFO 2452 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2022-11-11 16:43:30.511  INFO 2452 --- [           main] SpringbootReadWriteSplitMysqlApplication : Started SpringbootReadWriteSplitMysqlApplication in 4.093 seconds (JVM running for 4.693)
2022-11-11 16:44:12.596  INFO 2452 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2022-11-11 16:44:12.596  INFO 2452 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2022-11-11 16:44:12.610  INFO 2452 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 14 ms
切换到master
2022-11-11 16:46:07.003  INFO 2452 --- [nio-8080-exec-4] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2022-11-11 16:46:07.146  INFO 2452 --- [nio-8080-exec-4] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.

浏览器访问【http://localhost:8080/product/alls】读取从库。成功图示如下。

 读取从库,IDEA控制台日志如下。可以看到在访问数据库时DBContextHolder.java打印出”切换到slave“的日志。

"C:\Program Files\Java\jdk1.8.0_111\bin\java.exe" -XX:TieredStopAtLevel=1 -noverify -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true "-javaagent:D:\JavaDevEnv\JetBrains\IntelliJ IDEA 2018.3.6\lib\idea_rt.jar=62267:D:\JavaDevEnv\JetBrains\IntelliJ IDEA 2018.3.6\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_111\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\rt.jar;D:\JavaWorkspace\IdeaProjects\SpringInAction\springboot-read-write-split-mysql\target\classes;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-starter-web\2.3.7.RELEASE\spring-boot-starter-web-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-starter\2.3.7.RELEASE\spring-boot-starter-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot\2.3.7.RELEASE\spring-boot-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-autoconfigure\2.3.7.RELEASE\spring-boot-autoconfigure-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-starter-logging\2.3.7.RELEASE\spring-boot-starter-logging-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;D:\JavaDevEnv\maven_repository\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;D:\JavaDevEnv\maven_repository\org\apache\logging\log4j\log4j-to-slf4j\2.13.3\log4j-to-slf4j-2.13.3.jar;D:\JavaDevEnv\maven_repository\org\apache\logging\log4j\log4j-api\2.13.3\log4j-api-2.13.3.jar;D:\JavaDevEnv\maven_repository\org\slf4j\jul-to-slf4j\1.7.30\jul-to-slf4j-1.7.30.jar;D:\JavaDevEnv\maven_repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;D:\JavaDevEnv\maven_repository\org\yaml\snakeyaml\1.26\snakeyaml-1.26.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-starter-json\2.3.7.RELEASE\spring-boot-starter-json-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\com\fasterxml\jackson\core\jackson-databind\2.11.3\jackson-databind-2.11.3.jar;D:\JavaDevEnv\maven_repository\com\fasterxml\jackson\core\jackson-annotations\2.11.3\jackson-annotations-2.11.3.jar;D:\JavaDevEnv\maven_repository\com\fasterxml\jackson\core\jackson-core\2.11.3\jackson-core-2.11.3.jar;D:\JavaDevEnv\maven_repository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.11.3\jackson-datatype-jdk8-2.11.3.jar;D:\JavaDevEnv\maven_repository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.11.3\jackson-datatype-jsr310-2.11.3.jar;D:\JavaDevEnv\maven_repository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.11.3\jackson-module-parameter-names-2.11.3.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-starter-tomcat\2.3.7.RELEASE\spring-boot-starter-tomcat-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\apache\tomcat\embed\tomcat-embed-core\9.0.41\tomcat-embed-core-9.0.41.jar;D:\JavaDevEnv\maven_repository\org\glassfish\jakarta.el\3.0.3\jakarta.el-3.0.3.jar;D:\JavaDevEnv\maven_repository\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.41\tomcat-embed-websocket-9.0.41.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-web\5.2.12.RELEASE\spring-web-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-beans\5.2.12.RELEASE\spring-beans-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-webmvc\5.2.12.RELEASE\spring-webmvc-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-context\5.2.12.RELEASE\spring-context-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-expression\5.2.12.RELEASE\spring-expression-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\projectlombok\lombok\1.18.16\lombok-1.18.16.jar;D:\JavaDevEnv\maven_repository\org\apache\commons\commons-lang3\3.10\commons-lang3-3.10.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-starter-aop\2.3.7.RELEASE\spring-boot-starter-aop-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-aop\5.2.12.RELEASE\spring-aop-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\aspectj\aspectjweaver\1.9.6\aspectjweaver-1.9.6.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-starter-data-jdbc\2.3.7.RELEASE\spring-boot-starter-data-jdbc-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\data\spring-data-jdbc\2.0.6.RELEASE\spring-data-jdbc-2.0.6.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\data\spring-data-relational\2.0.6.RELEASE\spring-data-relational-2.0.6.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\data\spring-data-commons\2.3.6.RELEASE\spring-data-commons-2.3.6.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-tx\5.2.12.RELEASE\spring-tx-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-starter-jdbc\2.3.7.RELEASE\spring-boot-starter-jdbc-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\com\zaxxer\HikariCP\3.4.5\HikariCP-3.4.5.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-jdbc\5.2.12.RELEASE\spring-jdbc-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\mybatis\spring\boot\mybatis-spring-boot-starter\2.1.4\mybatis-spring-boot-starter-2.1.4.jar;D:\JavaDevEnv\maven_repository\org\mybatis\spring\boot\mybatis-spring-boot-autoconfigure\2.1.4\mybatis-spring-boot-autoconfigure-2.1.4.jar;D:\JavaDevEnv\maven_repository\org\mybatis\mybatis\3.5.6\mybatis-3.5.6.jar;D:\JavaDevEnv\maven_repository\org\mybatis\mybatis-spring\2.0.6\mybatis-spring-2.0.6.jar;D:\JavaDevEnv\maven_repository\Mysql\mysql-connector-java\8.0.22\mysql-connector-java-8.0.22.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-core\5.2.12.RELEASE\spring-core-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-jcl\5.2.12.RELEASE\spring-jcl-5.2.12.RELEASE.jar" com.wdh.springbootreadwritesplitmysql.SpringbootReadWriteSplitMysqlApplication.   ____          _            __ _ _/\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \\\/  ___)| |_)| | | | | || (_| |  ) ) ) )'  |____| .__|_| |_|_| |_\__, | / / / /=========|_|==============|___/=/_/_/_/:: Spring Boot ::        (v2.3.7.RELEASE)2022-11-11 16:43:26.762  INFO 2452 --- [           main] SpringbootReadWriteSplitMysqlApplication : Starting SpringbootReadWriteSplitMysqlApplication on 14JPYI7CBESDNFK with PID 2452 (D:\JavaWorkspace\IdeaProjects\SpringInAction\springboot-read-write-split-mysql\target\classes started by Administrator in D:\JavaWorkspace\IdeaProjects\SpringInAction\springboot-read-write-split-mysql)
2022-11-11 16:43:26.762  INFO 2452 --- [           main] SpringbootReadWriteSplitMysqlApplication : No active profile set, falling back to default profiles: default
2022-11-11 16:43:28.525  INFO 2452 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2022-11-11 16:43:28.541  INFO 2452 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2022-11-11 16:43:28.541  INFO 2452 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.41]
2022-11-11 16:43:28.606  INFO 2452 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2022-11-11 16:43:28.606  INFO 2452 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1781 ms
2022-11-11 16:43:30.028  INFO 2452 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2022-11-11 16:43:30.511  INFO 2452 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2022-11-11 16:43:30.511  INFO 2452 --- [           main] SpringbootReadWriteSplitMysqlApplication : Started SpringbootReadWriteSplitMysqlApplication in 4.093 seconds (JVM running for 4.693)
2022-11-11 16:44:12.596  INFO 2452 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2022-11-11 16:44:12.596  INFO 2452 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2022-11-11 16:44:12.610  INFO 2452 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 14 ms
切换到master
2022-11-11 16:46:07.003  INFO 2452 --- [nio-8080-exec-4] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2022-11-11 16:46:07.146  INFO 2452 --- [nio-8080-exec-4] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
切换到slave
2022-11-11 16:49:04.559  INFO 2452 --- [nio-8080-exec-7] com.zaxxer.hikari.HikariDataSource       : HikariPool-2 - Starting...
2022-11-11 16:49:04.660  INFO 2452 --- [nio-8080-exec-7] com.zaxxer.hikari.HikariDataSource       : HikariPool-2 - Start completed.

浏览器访问【http://localhost:8080/product/insert/M1651】写入主库。(因本示例mysql做了主从复制,所以主库的变更自动复制到从库了)

 日志如下,可以看到在调用写操作时自动切换到主库了。

"C:\Program Files\Java\jdk1.8.0_111\bin\java.exe" -XX:TieredStopAtLevel=1 -noverify -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true "-javaagent:D:\JavaDevEnv\JetBrains\IntelliJ IDEA 2018.3.6\lib\idea_rt.jar=62267:D:\JavaDevEnv\JetBrains\IntelliJ IDEA 2018.3.6\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_111\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\rt.jar;D:\JavaWorkspace\IdeaProjects\SpringInAction\springboot-read-write-split-mysql\target\classes;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-starter-web\2.3.7.RELEASE\spring-boot-starter-web-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-starter\2.3.7.RELEASE\spring-boot-starter-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot\2.3.7.RELEASE\spring-boot-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-autoconfigure\2.3.7.RELEASE\spring-boot-autoconfigure-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-starter-logging\2.3.7.RELEASE\spring-boot-starter-logging-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;D:\JavaDevEnv\maven_repository\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;D:\JavaDevEnv\maven_repository\org\apache\logging\log4j\log4j-to-slf4j\2.13.3\log4j-to-slf4j-2.13.3.jar;D:\JavaDevEnv\maven_repository\org\apache\logging\log4j\log4j-api\2.13.3\log4j-api-2.13.3.jar;D:\JavaDevEnv\maven_repository\org\slf4j\jul-to-slf4j\1.7.30\jul-to-slf4j-1.7.30.jar;D:\JavaDevEnv\maven_repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;D:\JavaDevEnv\maven_repository\org\yaml\snakeyaml\1.26\snakeyaml-1.26.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-starter-json\2.3.7.RELEASE\spring-boot-starter-json-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\com\fasterxml\jackson\core\jackson-databind\2.11.3\jackson-databind-2.11.3.jar;D:\JavaDevEnv\maven_repository\com\fasterxml\jackson\core\jackson-annotations\2.11.3\jackson-annotations-2.11.3.jar;D:\JavaDevEnv\maven_repository\com\fasterxml\jackson\core\jackson-core\2.11.3\jackson-core-2.11.3.jar;D:\JavaDevEnv\maven_repository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.11.3\jackson-datatype-jdk8-2.11.3.jar;D:\JavaDevEnv\maven_repository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.11.3\jackson-datatype-jsr310-2.11.3.jar;D:\JavaDevEnv\maven_repository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.11.3\jackson-module-parameter-names-2.11.3.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-starter-tomcat\2.3.7.RELEASE\spring-boot-starter-tomcat-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\apache\tomcat\embed\tomcat-embed-core\9.0.41\tomcat-embed-core-9.0.41.jar;D:\JavaDevEnv\maven_repository\org\glassfish\jakarta.el\3.0.3\jakarta.el-3.0.3.jar;D:\JavaDevEnv\maven_repository\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.41\tomcat-embed-websocket-9.0.41.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-web\5.2.12.RELEASE\spring-web-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-beans\5.2.12.RELEASE\spring-beans-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-webmvc\5.2.12.RELEASE\spring-webmvc-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-context\5.2.12.RELEASE\spring-context-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-expression\5.2.12.RELEASE\spring-expression-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\projectlombok\lombok\1.18.16\lombok-1.18.16.jar;D:\JavaDevEnv\maven_repository\org\apache\commons\commons-lang3\3.10\commons-lang3-3.10.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-starter-aop\2.3.7.RELEASE\spring-boot-starter-aop-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-aop\5.2.12.RELEASE\spring-aop-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\aspectj\aspectjweaver\1.9.6\aspectjweaver-1.9.6.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-starter-data-jdbc\2.3.7.RELEASE\spring-boot-starter-data-jdbc-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\data\spring-data-jdbc\2.0.6.RELEASE\spring-data-jdbc-2.0.6.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\data\spring-data-relational\2.0.6.RELEASE\spring-data-relational-2.0.6.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\data\spring-data-commons\2.3.6.RELEASE\spring-data-commons-2.3.6.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-tx\5.2.12.RELEASE\spring-tx-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;D:\JavaDevEnv\maven_repository\org\springframework\boot\spring-boot-starter-jdbc\2.3.7.RELEASE\spring-boot-starter-jdbc-2.3.7.RELEASE.jar;D:\JavaDevEnv\maven_repository\com\zaxxer\HikariCP\3.4.5\HikariCP-3.4.5.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-jdbc\5.2.12.RELEASE\spring-jdbc-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\mybatis\spring\boot\mybatis-spring-boot-starter\2.1.4\mybatis-spring-boot-starter-2.1.4.jar;D:\JavaDevEnv\maven_repository\org\mybatis\spring\boot\mybatis-spring-boot-autoconfigure\2.1.4\mybatis-spring-boot-autoconfigure-2.1.4.jar;D:\JavaDevEnv\maven_repository\org\mybatis\mybatis\3.5.6\mybatis-3.5.6.jar;D:\JavaDevEnv\maven_repository\org\mybatis\mybatis-spring\2.0.6\mybatis-spring-2.0.6.jar;D:\JavaDevEnv\maven_repository\Mysql\mysql-connector-java\8.0.22\mysql-connector-java-8.0.22.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-core\5.2.12.RELEASE\spring-core-5.2.12.RELEASE.jar;D:\JavaDevEnv\maven_repository\org\springframework\spring-jcl\5.2.12.RELEASE\spring-jcl-5.2.12.RELEASE.jar" com.wdh.springbootreadwritesplitmysql.SpringbootReadWriteSplitMysqlApplication.   ____          _            __ _ _/\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \\\/  ___)| |_)| | | | | || (_| |  ) ) ) )'  |____| .__|_| |_|_| |_\__, | / / / /=========|_|==============|___/=/_/_/_/:: Spring Boot ::        (v2.3.7.RELEASE)2022-11-11 16:43:26.762  INFO 2452 --- [           main] SpringbootReadWriteSplitMysqlApplication : Starting SpringbootReadWriteSplitMysqlApplication on 14JPYI7CBESDNFK with PID 2452 (D:\JavaWorkspace\IdeaProjects\SpringInAction\springboot-read-write-split-mysql\target\classes started by Administrator in D:\JavaWorkspace\IdeaProjects\SpringInAction\springboot-read-write-split-mysql)
2022-11-11 16:43:26.762  INFO 2452 --- [           main] SpringbootReadWriteSplitMysqlApplication : No active profile set, falling back to default profiles: default
2022-11-11 16:43:28.525  INFO 2452 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2022-11-11 16:43:28.541  INFO 2452 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2022-11-11 16:43:28.541  INFO 2452 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.41]
2022-11-11 16:43:28.606  INFO 2452 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2022-11-11 16:43:28.606  INFO 2452 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1781 ms
2022-11-11 16:43:30.028  INFO 2452 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2022-11-11 16:43:30.511  INFO 2452 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2022-11-11 16:43:30.511  INFO 2452 --- [           main] SpringbootReadWriteSplitMysqlApplication : Started SpringbootReadWriteSplitMysqlApplication in 4.093 seconds (JVM running for 4.693)
2022-11-11 16:44:12.596  INFO 2452 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2022-11-11 16:44:12.596  INFO 2452 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2022-11-11 16:44:12.610  INFO 2452 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 14 ms
切换到master
2022-11-11 16:46:07.003  INFO 2452 --- [nio-8080-exec-4] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2022-11-11 16:46:07.146  INFO 2452 --- [nio-8080-exec-4] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
切换到slave
2022-11-11 16:49:04.559  INFO 2452 --- [nio-8080-exec-7] com.zaxxer.hikari.HikariDataSource       : HikariPool-2 - Starting...
2022-11-11 16:49:04.660  INFO 2452 --- [nio-8080-exec-7] com.zaxxer.hikari.HikariDataSource       : HikariPool-2 - Start completed.
切换到master

再查询主库,ok,新增的数据已可查出。

再查询从库(在Mysql实现了主从复制的场景下,主库新增的数据已经自动同步到从库了),ok

拓展读写分离(写一个库,读多个库)

思路:

1.Mysql先实现一主多从,

2.然后用Nginx为多个Mysql服务器建立反向代理在多个mysql上轮询实现负载均衡。例如Nginx将IP:3333端口暴露为多个Mysql负载均衡后对外的统一端口。

3.将Nginx暴露出的对外数据访问端口IP:3333配置到springboot的application.propertities中读数据库的连接[spring.datasource.slave.jdbcUrl]中即可。

4.上述仅改个springboot配置文件即可实现【mysql一主一从+springboot读写分离】或【mysql一主多从+springboot读写分离】,简单易用。

mysql主从复制及Nginx读写分离可参考本人其他博文

MySql 主从复制 双机热备 笔记_既择远方-风雨兼程的博客-CSDN博客

Nginx 负载均衡 初步配置&验证 笔记_既择远方-风雨兼程的博客-CSDN博客

Nginx Mysql负载均衡 初步配置及验证 笔记_既择远方-风雨兼程的博客-CSDN博客

读写分离参考资料

SpringBoot读写分离_CBeann的博客-CSDN博客_springboot 读写分离

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...