• SpringBoot 读写分离(配Mysql5.7) 笔记


    目录

    需求

    环境

    数据库表字段

    操作笔记

    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;

    1. mysql> use dbdemo;
    2. Database changed
    3. mysql> show tables;
    4. +------------------+
    5. | Tables_in_dbdemo |
    6. +------------------+
    7. | categories |
    8. | products |
    9. +------------------+
    10. 2 rows in set (0.02 sec)
    11. mysql> show create table categories;
    12. +------------+--------------------------------------------------------------------------------------------------------------------------------------------------
    13. --------------------------------------------------------------------------------------------------------+
    14. | Table | Create Table
    15. |
    16. +------------+--------------------------------------------------------------------------------------------------------------------------------------------------
    17. --------------------------------------------------------------------------------------------------------+
    18. | categories | CREATE TABLE `categories` (
    19. `cat_id` int(11) NOT NULL AUTO_INCREMENT,
    20. `cat_name` varchar(255) NOT NULL,
    21. `cat_description` text,
    22. `cat_date` datetime DEFAULT NULL,
    23. PRIMARY KEY (`cat_id`)
    24. ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 |
    25. +------------+--------------------------------------------------------------------------------------------------------------------------------------------------
    26. --------------------------------------------------------------------------------------------------------+
    27. 1 row in set (0.23 sec)
    28. mysql> show create table products;
    29. +----------+----------------------------------------------------------------------------------------------------------------------------------------------------
    30. ----------------------------------------------------------------------------------------------------------------------------------------------------------------
    31. -------------------------------------------------------------------------------------------------------------------------+
    32. | Table | Create Table
    33. |
    34. +----------+----------------------------------------------------------------------------------------------------------------------------------------------------
    35. ----------------------------------------------------------------------------------------------------------------------------------------------------------------
    36. -------------------------------------------------------------------------------------------------------------------------+
    37. | products | CREATE TABLE `products` (
    38. `prd_id` int(11) NOT NULL AUTO_INCREMENT,
    39. `prd_name` varchar(355) NOT NULL,
    40. `prd_price` decimal(10,0) DEFAULT NULL,
    41. `prd_date` datetime DEFAULT NULL,
    42. `cat_id` int(11) NOT NULL,
    43. PRIMARY KEY (`prd_id`),
    44. KEY `fk_cat` (`cat_id`),
    45. CONSTRAINT `products_ibfk_1` FOREIGN KEY (`cat_id`) REFERENCES `categories` (`cat_id`) ON UPDATE CASCADE
    46. ) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8 |
    47. +----------+----------------------------------------------------------------------------------------------------------------------------------------------------
    48. ----------------------------------------------------------------------------------------------------------------------------------------------------------------
    49. -------------------------------------------------------------------------------------------------------------------------+
    50. 1 row in set (0.09 sec)
    51. mysql>

    操作笔记

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

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

    项目结构如下

    完整pom.xm如下:

    1. "1.0" encoding="UTF-8"?>
    2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    4. <modelVersion>4.0.0modelVersion>
    5. <groupId>com.wdhgroupId>
    6. <artifactId>springboot-read-write-split-mysqlartifactId>
    7. <version>0.0.1-SNAPSHOTversion>
    8. <name>springboot-read-write-split-mysqlname>
    9. <description>Demo project for Spring Bootdescription>
    10. <properties>
    11. <java.version>1.8java.version>
    12. <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
    13. <project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
    14. <spring-boot.version>2.3.7.RELEASEspring-boot.version>
    15. properties>
    16. <dependencies>
    17. <dependency>
    18. <groupId>org.springframework.bootgroupId>
    19. <artifactId>spring-boot-starter-webartifactId>
    20. dependency>
    21. <dependency>
    22. <groupId>org.projectlombokgroupId>
    23. <artifactId>lombokartifactId>
    24. <optional>trueoptional>
    25. dependency>
    26. <dependency>
    27. <groupId>org.apache.commonsgroupId>
    28. <artifactId>commons-lang3artifactId>
    29. dependency>
    30. <dependency>
    31. <groupId>org.springframework.bootgroupId>
    32. <artifactId>spring-boot-starter-aopartifactId>
    33. dependency>
    34. <dependency>
    35. <groupId>org.springframework.bootgroupId>
    36. <artifactId>spring-boot-starter-data-jdbcartifactId>
    37. dependency>
    38. <dependency>
    39. <groupId>org.springframework.bootgroupId>
    40. <artifactId>spring-boot-starter-jdbcartifactId>
    41. dependency>
    42. <dependency>
    43. <groupId>org.mybatis.spring.bootgroupId>
    44. <artifactId>mybatis-spring-boot-starterartifactId>
    45. <version>2.1.4version>
    46. dependency>
    47. <dependency>
    48. <groupId>mysqlgroupId>
    49. <artifactId>mysql-connector-javaartifactId>
    50. <version>8.0.22version>
    51. dependency>
    52. <dependency>
    53. <groupId>org.springframework.bootgroupId>
    54. <artifactId>spring-boot-starter-testartifactId>
    55. <scope>testscope>
    56. <exclusions>
    57. <exclusion>
    58. <groupId>org.junit.vintagegroupId>
    59. <artifactId>junit-vintage-engineartifactId>
    60. exclusion>
    61. exclusions>
    62. dependency>
    63. dependencies>
    64. <dependencyManagement>
    65. <dependencies>
    66. <dependency>
    67. <groupId>org.springframework.bootgroupId>
    68. <artifactId>spring-boot-dependenciesartifactId>
    69. <version>${spring-boot.version}version>
    70. <type>pomtype>
    71. <scope>importscope>
    72. dependency>
    73. dependencies>
    74. dependencyManagement>
    75. <build>
    76. <plugins>
    77. <plugin>
    78. <groupId>org.apache.maven.pluginsgroupId>
    79. <artifactId>maven-compiler-pluginartifactId>
    80. <version>3.8.1version>
    81. <configuration>
    82. <source>1.8source>
    83. <target>1.8target>
    84. <encoding>UTF-8encoding>
    85. configuration>
    86. plugin>
    87. <plugin>
    88. <groupId>org.springframework.bootgroupId>
    89. <artifactId>spring-boot-maven-pluginartifactId>
    90. <version>2.3.7.RELEASEversion>
    91. <configuration>
    92. <mainClass>com.wdh.springbootreadwritesplitmysql.SpringbootReadWriteSplitMysqlApplication
    93. mainClass>
    94. configuration>
    95. <executions>
    96. <execution>
    97. <id>repackageid>
    98. <goals>
    99. <goal>repackagegoal>
    100. goals>
    101. execution>
    102. executions>
    103. plugin>
    104. <plugin>
    105. <groupId>org.mybatis.generatorgroupId>
    106. <artifactId>mybatis-generator-maven-pluginartifactId>
    107. <version>1.3.1version>
    108. <configuration>
    109. <configurationFile>src\main\resources\mybatis-generator\generatorConfig.xmlconfigurationFile>
    110. <overwrite>falseoverwrite>
    111. <verbose>trueverbose>
    112. configuration>
    113. plugin>
    114. plugins>
    115. build>
    116. project>

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

    1. # 应用名称
    2. spring.application.name=springboot-read-write-split-mysql
    3. # 应用服务 WEB 访问端口
    4. server.port=8080
    5. #这是自定义的mysql主数据库的访问配置
    6. spring.datasource.master.driver-class-name=com.mysql.cj.jdbc.Driver
    7. #以下是配合默认的spring.datasource.hikari的jdbcUrl
    8. spring.datasource.master.jdbcUrl=jdbc:mysql://192.168.7.161:3306/dbdemo?serverTimezone=UTC
    9. spring.datasource.master.username=root
    10. spring.datasource.master.[CSDN不让发]password[CSDN不让发]=XX你的密码XX
    11. #这是自定义的mysql从数据库的访问配置
    12. spring.datasource.slave.driver-class-name=com.mysql.cj.jdbc.Driver
    13. spring.datasource.slave.jdbcUrl=jdbc:mysql://192.168.7.162:3306/dbdemo?serverTimezone=UTC
    14. spring.datasource.slave.username=root
    15. 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自动生成

    1. <plugin>
    2. <groupId>org.mybatis.generatorgroupId>
    3. <artifactId>mybatis-generator-maven-pluginartifactId>
    4. <version>1.3.1version>
    5. <configuration>
    6. <configurationFile>src\main\resources\mybatis-generator\generatorConfig.xmlconfigurationFile>
    7. <overwrite>falseoverwrite>
    8. <verbose>trueverbose>
    9. configuration>
    10. plugin>

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

    1. "1.0" encoding="UTF-8"?>
    2. generatorConfiguration
    3. PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
    4. "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
    5. <generatorConfiguration>
    6. <classPathEntry location="D:\JavaDevEnv\maven_repository\Mysql\mysql-connector-java\8.0.22\mysql-connector-java-8.0.22.jar">classPathEntry>
    7. <context id="DB2Tables" targetRuntime="MyBatis3">
    8. <commentGenerator>
    9. <property name="suppressDate" value="false">property>
    10. <property name="suppressAllComments" value="false">property>
    11. commentGenerator>
    12. <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
    13. connectionURL="jdbc:mysql://localhost:3306/dbdemo?serverTimezone=UTC"
    14. userId="root"
    15. [CSDN不让发]password[CSDN不让发]="XX你的密码XX">
    16. jdbcConnection>
    17. <javaTypeResolver >
    18. <property name="forceBigDecimals" value="false" />
    19. javaTypeResolver>
    20. <javaModelGenerator targetPackage="com.wdh.springbootreadwritesplitmysql.entity" targetProject="src\main\java">
    21. <property name="enableSubPackages" value="true" />
    22. <property name="trimStrings" value="true" />
    23. javaModelGenerator>
    24. <sqlMapGenerator targetPackage="main.resources.mappers" targetProject="src">
    25. <property name="enableSubPackages" value="true"/>
    26. sqlMapGenerator>
    27. <javaClientGenerator type="XMLMAPPER" targetPackage="com.wdh.springbootreadwritesplitmysql.mapper" targetProject="src\main\java">
    28. <property name="enableSubPackages" value="true" />
    29. javaClientGenerator>
    30. <table schema="dbdemo" tableName="categories"
    31. enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"
    32. >table>
    33. <table schema="dbdemo" tableName="products"
    34. enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"
    35. >table>
    36. context>
    37. generatorConfiguration>

    注意,因主库和从库结构一致,上述配置文件中定义了按主库配置连接信息,访问并生成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】文件。

    读写分离切换的代码实现

    定义主从库枚举类型

    1. package com.wdh.springbootreadwritesplitmysql.enums;
    2. /**
    3. * @author WangDH
    4. * @create 2022-11-10 13:51
    5. *
    6. * 数据源类型枚举
    7. */
    8. public enum DBTypeEnum {
    9. //数据库主库
    10. MASTER,
    11. //数据库从库
    12. SLAVE
    13. }

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

    1. package com.wdh.springbootreadwritesplitmysql.bean;
    2. import com.wdh.springbootreadwritesplitmysql.enums.DBTypeEnum;
    3. import java.util.concurrent.atomic.AtomicInteger;
    4. /**
    5. * @author WangDH
    6. * @create 2022-11-10 13:59
    7. */
    8. public class DBContextHolder {
    9. private static final ThreadLocal<DBTypeEnum> contextHolder=new ThreadLocal<>();
    10. private static final AtomicInteger counter=new AtomicInteger(-1);
    11. public static void set(DBTypeEnum dbTypeEnum){
    12. contextHolder.set(dbTypeEnum);
    13. }
    14. public static DBTypeEnum get(){
    15. return contextHolder.get();
    16. }
    17. public static void master(){
    18. set(DBTypeEnum.MASTER);
    19. System.out.println("切换到master");
    20. }
    21. public static void slave(){
    22. set(DBTypeEnum.SLAVE);
    23. System.out.println("切换到slave");
    24. }
    25. }

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

    1. package com.wdh.springbootreadwritesplitmysql.bean;
    2. import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
    3. import org.springframework.lang.Nullable;
    4. /**
    5. * @author WangDH
    6. * @create 2022-11-10 13:57
    7. */
    8. public class MyRoutingDataSource extends AbstractRoutingDataSource {
    9. @Nullable
    10. @Override
    11. protected Object determineCurrentLookupKey() {
    12. Object obj= DBContextHolder.get();
    13. return obj;
    14. }
    15. }

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

    1. package com.wdh.springbootreadwritesplitmysql.config;
    2. import com.wdh.springbootreadwritesplitmysql.bean.MyRoutingDataSource;
    3. import com.wdh.springbootreadwritesplitmysql.enums.DBTypeEnum;
    4. import org.springframework.beans.factory.annotation.Qualifier;
    5. import org.springframework.boot.context.properties.ConfigurationProperties;
    6. import org.springframework.boot.jdbc.DataSourceBuilder;
    7. import org.springframework.context.annotation.Bean;
    8. import org.springframework.context.annotation.Configuration;
    9. import javax.sql.DataSource;
    10. import java.util.HashMap;
    11. import java.util.Map;
    12. /**
    13. * @author WangDH
    14. * @create 2022-11-10 11:42
    15. *
    16. *
    17. * 自定义两个数据源,主库数据源,从库数据源
    18. */
    19. @Configuration
    20. public class DataSourceConfig {
    21. //定义Mysql主库数据源
    22. @Bean
    23. @ConfigurationProperties("spring.datasource.master")//从配置文件读取spring.datasource.master开头的相关配置进行数据源初始化
    24. public DataSource DataSourceMaster(){
    25. return DataSourceBuilder.create().build();
    26. }
    27. //定义Mysql从库数据源
    28. @Bean
    29. @ConfigurationProperties("spring.datasource.slave")
    30. public DataSource DataSourceSlave(){
    31. return DataSourceBuilder.create().build();
    32. }
    33. @Bean
    34. public DataSource myRoutingDataSource(
    35. //@Qualifier 类似于@Autowired注解实现Spring依赖注入,但@Qualifier用来指定应该注入特定类型的bean,防止依赖注入冲突
    36. @Qualifier("DataSourceMaster") DataSource dataSourceMaster,
    37. @Qualifier("DataSourceSlave") DataSource dataSourceSlave)
    38. {
    39. Map targetDataSource=new HashMap<>(2);
    40. targetDataSource.put(DBTypeEnum.MASTER,dataSourceMaster);
    41. targetDataSource.put(DBTypeEnum.SLAVE,dataSourceSlave);
    42. MyRoutingDataSource routingDataSource=new MyRoutingDataSource();
    43. routingDataSource.setDefaultTargetDataSource(dataSourceMaster);
    44. routingDataSource.setTargetDataSources(targetDataSource);
    45. return routingDataSource;
    46. }
    47. }

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

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

    1. package com.wdh.springbootreadwritesplitmysql.config;
    2. import org.apache.ibatis.session.SqlSessionFactory;
    3. import org.mybatis.spring.SqlSessionFactoryBean;
    4. import org.springframework.context.annotation.Bean;
    5. import org.springframework.context.annotation.Configuration;
    6. import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
    7. import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    8. import org.springframework.transaction.PlatformTransactionManager;
    9. import org.springframework.transaction.annotation.EnableTransactionManagement;
    10. import javax.annotation.Resource;
    11. import javax.sql.DataSource;
    12. /**
    13. * @author WangDH
    14. * @create 2022-11-10 14:26
    15. */
    16. @EnableTransactionManagement
    17. @Configuration
    18. public class MyBatisConfig {
    19. @Resource(name="myRoutingDataSource") //@Resource默认按byName自动注入
    20. private DataSource myRoutingDataSource;
    21. @Bean
    22. public SqlSessionFactory sqlSessionFactory() throws Exception{
    23. ///org.springframework.core.io.Resource resourceMappersXml=new PathMatchingResourcePatternResolver().getResource("classpath:mappers/*.xml");
    24. //上述代码报错: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 exist
    25. org.springframework.core.io.Resource[] resourceMappersXml=new PathMatchingResourcePatternResolver().getResources("classpath:mappers/*.xml");
    26. //注意这里是getResources 不要误写成getResource
    27. //参考https://www.cnblogs.com/jev-0987/p/12839193.html
    28. //getResource(): //1.从类的根路径下获取文件
    29. //getResources(): //1.获取所有类路径下的指定文件
    30. SqlSessionFactoryBean sqlSessionFactoryBean=new SqlSessionFactoryBean();
    31. sqlSessionFactoryBean.setDataSource(myRoutingDataSource);
    32. sqlSessionFactoryBean.setMapperLocations(
    33. resourceMappersXml
    34. );
    35. SqlSessionFactory sqlSessionFactory= sqlSessionFactoryBean.getObject();
    36. return sqlSessionFactory;
    37. }
    38. @Bean
    39. public PlatformTransactionManager platformTransactionManager(){
    40. return new DataSourceTransactionManager(myRoutingDataSource);
    41. }
    42. }

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

    Master.java代码

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

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

    DataSourceAop.java代码如下
    1. package com.wdh.springbootreadwritesplitmysql.aop;
    2. import com.wdh.springbootreadwritesplitmysql.bean.DBContextHolder;
    3. import org.aspectj.lang.annotation.Aspect;
    4. import org.aspectj.lang.annotation.Before;
    5. import org.aspectj.lang.annotation.Pointcut;
    6. import org.springframework.stereotype.Component;
    7. /**
    8. * @author WangDH
    9. * @create 2022-11-10 14:53
    10. */
    11. @Aspect
    12. @Component
    13. public class DataSourceAop {
    14. // //读切面(条件:没有Master注解)
    15. // @Pointcut(
    16. // "!@annotation(com.wdh.springbootreadwritesplitmysql.annotation.Master)" //如果使用!@annotation,则必须加&&(execution指定包范围,否则会导致所有方法都被切面捕获而导致启动失败
    17. // +"&&(execution(* com.wdh.springbootreadwritesplitmysql.service.*.*(..)))"
    18. // )
    19. //切面切入点(条件:有Slave注解)的方法使用从库数据源
    20. @Pointcut(
    21. "@annotation(com.wdh.springbootreadwritesplitmysql.annotation.Slave)"
    22. )
    23. public void readPointcut(){}
    24. //切面切入点,(条件:有Master注解)的方法使用主库数据源
    25. @Pointcut(
    26. "@annotation(com.wdh.springbootreadwritesplitmysql.annotation.Master)"
    27. //+"&&(execution(* com.wdh.springbootreadwritesplitmysql.service.*.*(..)))"
    28. )
    29. public void writePointcut(){}
    30. //Before方法,读切面前设置ThreadLocal里变量为slave
    31. @Before("readPointcut()")
    32. public void read(){
    33. DBContextHolder.slave();
    34. }
    35. //Before方法,写切面前设置ThreadLocal里变量为master
    36. @Before("writePointcut()")
    37. public void write(){
    38. DBContextHolder.master();
    39. }
    40. }

    入口主类代码

    SpringbootReadWriteSplitMysqlApplication.java

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

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

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

    Controller层 ProductController.java代码

    1. package com.wdh.springbootreadwritesplitmysql.controller;
    2. import com.wdh.springbootreadwritesplitmysql.entity.Products;
    3. import com.wdh.springbootreadwritesplitmysql.service.ProductsService;
    4. import org.springframework.beans.factory.annotation.Autowired;
    5. import org.springframework.web.bind.annotation.GetMapping;
    6. import org.springframework.web.bind.annotation.PathVariable;
    7. import org.springframework.web.bind.annotation.RequestMapping;
    8. import org.springframework.web.bind.annotation.RestController;
    9. import java.util.Date;
    10. import java.util.List;
    11. /**
    12. * @author WangDH
    13. * @create 2022-11-10 16:54
    14. */
    15. @RestController
    16. @RequestMapping("/product")
    17. public class ProductController {
    18. @Autowired
    19. private ProductsService productsService;
    20. @GetMapping("/hello")
    21. public String hello(){
    22. return "ok,this is ProductController.";
    23. }
    24. @GetMapping("/allm")
    25. public List<Products> allM(){
    26. List<Products> list=productsService.getAllMaster();
    27. return list;
    28. }
    29. @GetMapping("/alls")
    30. public List<Products> allS(){
    31. List<Products> list=productsService.getAllSlave();
    32. return list;
    33. }
    34. @GetMapping("/insert/{name}")
    35. public String insert(@PathVariable("name") String prdName){
    36. Date date=new Date();
    37. String prdNameJoin="SpringRW_"+prdName+"_"+date.toString();
    38. Products prd=new Products();
    39. prd.setPrdName(prdNameJoin);
    40. prd.setPrdPrice((long)1110);
    41. prd.setPrdDate(date);
    42. prd.setCatId(2);
    43. int retIns=productsService.insert(prd);//进主库,可以测试关掉从库测试能否写成功。
    44. return "retIns="+retIns+","+(retIns>0?"ok":"fail");
    45. }
    46. }

    Service层代码,ProductsService.java

    特别注意,

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

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

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

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

    1. package com.wdh.springbootreadwritesplitmysql.service;
    2. import com.wdh.springbootreadwritesplitmysql.annotation.Master;
    3. import com.wdh.springbootreadwritesplitmysql.annotation.Slave;
    4. import com.wdh.springbootreadwritesplitmysql.entity.Products;
    5. import com.wdh.springbootreadwritesplitmysql.mapper.ProductsMapper;
    6. import org.springframework.beans.factory.annotation.Autowired;
    7. import org.springframework.stereotype.Service;
    8. import java.util.List;
    9. /**
    10. * @author WangDH
    11. * @create 2022-11-10 16:32
    12. */
    13. @Service
    14. public class ProductsService {
    15. //注意,需要所有Service层访问数据库的方法必须增加@Slave或@Master注解,以标明是操作从库还是操作主库
    16. @Autowired
    17. private ProductsMapper productsMapper;
    18. @Slave
    19. public List<Products> getAllSlave(){
    20. List<Products> listSlave= productsMapper.selectAll();
    21. return listSlave;
    22. }
    23. //标记为由主库读
    24. @Master
    25. public List<Products> getAllMaster(){
    26. List<Products> list= productsMapper.selectAll();
    27. return list;
    28. }
    29. //标记为进入主库写
    30. @Master
    31. public int insert(Products record){
    32. return productsMapper.insert(record);
    33. }
    34. }

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

    List<Products> selectAll();

    ,同步需要修改ProductsMapper.xml。

    修改部分如下

    1. <select id="selectAll" resultMap="BaseResultMap" >
    2. select
    3. <include refid="Base_Column_List" />
    4. from products
    5. select>

    ProductsMapper.java完整代码如下;

    1. package com.wdh.springbootreadwritesplitmysql.mapper;
    2. import com.wdh.springbootreadwritesplitmysql.entity.Products;
    3. import java.util.List;
    4. public interface ProductsMapper {
    5. /**
    6. * This method was generated by MyBatis Generator.
    7. * This method corresponds to the database table products
    8. *
    9. * @mbggenerated Thu Nov 10 16:13:23 CST 2022
    10. */
    11. int deleteByPrimaryKey(Integer prdId);
    12. /**
    13. * This method was generated by MyBatis Generator.
    14. * This method corresponds to the database table products
    15. *
    16. * @mbggenerated Thu Nov 10 16:13:23 CST 2022
    17. */
    18. int insert(Products record);
    19. /**
    20. * This method was generated by MyBatis Generator.
    21. * This method corresponds to the database table products
    22. *
    23. * @mbggenerated Thu Nov 10 16:13:23 CST 2022
    24. */
    25. int insertSelective(Products record);
    26. /**
    27. * This method was generated by MyBatis Generator.
    28. * This method corresponds to the database table products
    29. *
    30. * @mbggenerated Thu Nov 10 16:13:23 CST 2022
    31. */
    32. Products selectByPrimaryKey(Integer prdId);
    33. //wdh自定义增加的查询函数,需要ProductsMapper.xml有配置selectAll查询sql
    34. List<Products> selectAll();
    35. /**
    36. * This method was generated by MyBatis Generator.
    37. * This method corresponds to the database table products
    38. *
    39. * @mbggenerated Thu Nov 10 16:13:23 CST 2022
    40. */
    41. int updateByPrimaryKeySelective(Products record);
    42. /**
    43. * This method was generated by MyBatis Generator.
    44. * This method corresponds to the database table products
    45. *
    46. * @mbggenerated Thu Nov 10 16:13:23 CST 2022
    47. */
    48. int updateByPrimaryKey(Products record);
    49. }

    ProductsMapper.xml全文

    1. "1.0" encoding="UTF-8" ?>
    2. mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
    3. <mapper namespace="com.wdh.springbootreadwritesplitmysql.mapper.ProductsMapper" >
    4. <resultMap id="BaseResultMap" type="com.wdh.springbootreadwritesplitmysql.entity.Products" >
    5. <id column="prd_id" property="prdId" jdbcType="INTEGER" />
    6. <result column="prd_name" property="prdName" jdbcType="VARCHAR" />
    7. <result column="prd_price" property="prdPrice" jdbcType="DECIMAL" />
    8. <result column="prd_date" property="prdDate" jdbcType="TIMESTAMP" />
    9. <result column="cat_id" property="catId" jdbcType="INTEGER" />
    10. resultMap>
    11. <sql id="Base_Column_List" >
    12. prd_id, prd_name, prd_price, prd_date, cat_id
    13. sql>
    14. <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
    15. select
    16. <include refid="Base_Column_List" />
    17. from products
    18. where prd_id = #{prdId,jdbcType=INTEGER}
    19. select>
    20. <select id="selectAll" resultMap="BaseResultMap" >
    21. select
    22. <include refid="Base_Column_List" />
    23. from products
    24. select>
    25. <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >
    26. delete from products
    27. where prd_id = #{prdId,jdbcType=INTEGER}
    28. delete>
    29. <insert id="insert" parameterType="com.wdh.springbootreadwritesplitmysql.entity.Products" >
    30. insert into products (prd_id, prd_name, prd_price,
    31. prd_date, cat_id)
    32. values (#{prdId,jdbcType=INTEGER}, #{prdName,jdbcType=VARCHAR}, #{prdPrice,jdbcType=DECIMAL},
    33. #{prdDate,jdbcType=TIMESTAMP}, #{catId,jdbcType=INTEGER})
    34. insert>
    35. <insert id="insertSelective" parameterType="com.wdh.springbootreadwritesplitmysql.entity.Products" >
    36. insert into products
    37. <trim prefix="(" suffix=")" suffixOverrides="," >
    38. <if test="prdId != null" >
    39. prd_id,
    40. if>
    41. <if test="prdName != null" >
    42. prd_name,
    43. if>
    44. <if test="prdPrice != null" >
    45. prd_price,
    46. if>
    47. <if test="prdDate != null" >
    48. prd_date,
    49. if>
    50. <if test="catId != null" >
    51. cat_id,
    52. if>
    53. trim>
    54. <trim prefix="values (" suffix=")" suffixOverrides="," >
    55. <if test="prdId != null" >
    56. #{prdId,jdbcType=INTEGER},
    57. if>
    58. <if test="prdName != null" >
    59. #{prdName,jdbcType=VARCHAR},
    60. if>
    61. <if test="prdPrice != null" >
    62. #{prdPrice,jdbcType=DECIMAL},
    63. if>
    64. <if test="prdDate != null" >
    65. #{prdDate,jdbcType=TIMESTAMP},
    66. if>
    67. <if test="catId != null" >
    68. #{catId,jdbcType=INTEGER},
    69. if>
    70. trim>
    71. insert>
    72. <update id="updateByPrimaryKeySelective" parameterType="com.wdh.springbootreadwritesplitmysql.entity.Products" >
    73. update products
    74. <set >
    75. <if test="prdName != null" >
    76. prd_name = #{prdName,jdbcType=VARCHAR},
    77. if>
    78. <if test="prdPrice != null" >
    79. prd_price = #{prdPrice,jdbcType=DECIMAL},
    80. if>
    81. <if test="prdDate != null" >
    82. prd_date = #{prdDate,jdbcType=TIMESTAMP},
    83. if>
    84. <if test="catId != null" >
    85. cat_id = #{catId,jdbcType=INTEGER},
    86. if>
    87. set>
    88. where prd_id = #{prdId,jdbcType=INTEGER}
    89. update>
    90. <update id="updateByPrimaryKey" parameterType="com.wdh.springbootreadwritesplitmysql.entity.Products" >
    91. update products
    92. set prd_name = #{prdName,jdbcType=VARCHAR},
    93. prd_price = #{prdPrice,jdbcType=DECIMAL},
    94. prd_date = #{prdDate,jdbcType=TIMESTAMP},
    95. cat_id = #{catId,jdbcType=INTEGER}
    96. where prd_id = #{prdId,jdbcType=INTEGER}
    97. update>
    98. mapper>

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

    1. package com.wdh.springbootreadwritesplitmysql.entity;
    2. import lombok.Data;
    3. import java.util.Date;
    4. @Data
    5. public class Products {
    6. /**
    7. * This field was generated by MyBatis Generator.
    8. * This field corresponds to the database column products.prd_id
    9. *
    10. * @mbggenerated Thu Nov 10 16:13:23 CST 2022
    11. */
    12. private Integer prdId;
    13. /**
    14. * This field was generated by MyBatis Generator.
    15. * This field corresponds to the database column products.prd_name
    16. *
    17. * @mbggenerated Thu Nov 10 16:13:23 CST 2022
    18. */
    19. private String prdName;
    20. /**
    21. * This field was generated by MyBatis Generator.
    22. * This field corresponds to the database column products.prd_price
    23. *
    24. * @mbggenerated Thu Nov 10 16:13:23 CST 2022
    25. */
    26. private Long prdPrice;
    27. /**
    28. * This field was generated by MyBatis Generator.
    29. * This field corresponds to the database column products.prd_date
    30. *
    31. * @mbggenerated Thu Nov 10 16:13:23 CST 2022
    32. */
    33. private Date prdDate;
    34. /**
    35. * This field was generated by MyBatis Generator.
    36. * This field corresponds to the database column products.cat_id
    37. *
    38. * @mbggenerated Thu Nov 10 16:13:23 CST 2022
    39. */
    40. private Integer catId;
    41. /**
    42. * This method was generated by MyBatis Generator.
    43. * This method returns the value of the database column products.prd_id
    44. *
    45. * @return the value of products.prd_id
    46. *
    47. * @mbggenerated Thu Nov 10 16:13:23 CST 2022
    48. */
    49. public Integer getPrdId() {
    50. return prdId;
    51. }
    52. /**
    53. * This method was generated by MyBatis Generator.
    54. * This method sets the value of the database column products.prd_id
    55. *
    56. * @param prdId the value for products.prd_id
    57. *
    58. * @mbggenerated Thu Nov 10 16:13:23 CST 2022
    59. */
    60. public void setPrdId(Integer prdId) {
    61. this.prdId = prdId;
    62. }
    63. /**
    64. * This method was generated by MyBatis Generator.
    65. * This method returns the value of the database column products.prd_name
    66. *
    67. * @return the value of products.prd_name
    68. *
    69. * @mbggenerated Thu Nov 10 16:13:23 CST 2022
    70. */
    71. public String getPrdName() {
    72. return prdName;
    73. }
    74. /**
    75. * This method was generated by MyBatis Generator.
    76. * This method sets the value of the database column products.prd_name
    77. *
    78. * @param prdName the value for products.prd_name
    79. *
    80. * @mbggenerated Thu Nov 10 16:13:23 CST 2022
    81. */
    82. public void setPrdName(String prdName) {
    83. this.prdName = prdName == null ? null : prdName.trim();
    84. }
    85. /**
    86. * This method was generated by MyBatis Generator.
    87. * This method returns the value of the database column products.prd_price
    88. *
    89. * @return the value of products.prd_price
    90. *
    91. * @mbggenerated Thu Nov 10 16:13:23 CST 2022
    92. */
    93. public Long getPrdPrice() {
    94. return prdPrice;
    95. }
    96. /**
    97. * This method was generated by MyBatis Generator.
    98. * This method sets the value of the database column products.prd_price
    99. *
    100. * @param prdPrice the value for products.prd_price
    101. *
    102. * @mbggenerated Thu Nov 10 16:13:23 CST 2022
    103. */
    104. public void setPrdPrice(Long prdPrice) {
    105. this.prdPrice = prdPrice;
    106. }
    107. /**
    108. * This method was generated by MyBatis Generator.
    109. * This method returns the value of the database column products.prd_date
    110. *
    111. * @return the value of products.prd_date
    112. *
    113. * @mbggenerated Thu Nov 10 16:13:23 CST 2022
    114. */
    115. public Date getPrdDate() {
    116. return prdDate;
    117. }
    118. /**
    119. * This method was generated by MyBatis Generator.
    120. * This method sets the value of the database column products.prd_date
    121. *
    122. * @param prdDate the value for products.prd_date
    123. *
    124. * @mbggenerated Thu Nov 10 16:13:23 CST 2022
    125. */
    126. public void setPrdDate(Date prdDate) {
    127. this.prdDate = prdDate;
    128. }
    129. /**
    130. * This method was generated by MyBatis Generator.
    131. * This method returns the value of the database column products.cat_id
    132. *
    133. * @return the value of products.cat_id
    134. *
    135. * @mbggenerated Thu Nov 10 16:13:23 CST 2022
    136. */
    137. public Integer getCatId() {
    138. return catId;
    139. }
    140. /**
    141. * This method was generated by MyBatis Generator.
    142. * This method sets the value of the database column products.cat_id
    143. *
    144. * @param catId the value for products.cat_id
    145. *
    146. * @mbggenerated Thu Nov 10 16:13:23 CST 2022
    147. */
    148. public void setCatId(Integer catId) {
    149. this.catId = catId;
    150. }
    151. }

    验证读写分离

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

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

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

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

    1. "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
    2. . ____ _ __ _ _
    3. /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
    4. ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
    5. \\/ ___)| |_)| | | | | || (_| | ) ) ) )
    6. ' |____| .__|_| |_|_| |_\__, | / / / /
    7. =========|_|==============|___/=/_/_/_/
    8. :: Spring Boot :: (v2.3.7.RELEASE)
    9. 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)
    10. 2022-11-11 16:43:26.762 INFO 2452 --- [ main] SpringbootReadWriteSplitMysqlApplication : No active profile set, falling back to default profiles: default
    11. 2022-11-11 16:43:28.525 INFO 2452 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
    12. 2022-11-11 16:43:28.541 INFO 2452 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
    13. 2022-11-11 16:43:28.541 INFO 2452 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.41]
    14. 2022-11-11 16:43:28.606 INFO 2452 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
    15. 2022-11-11 16:43:28.606 INFO 2452 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1781 ms
    16. 2022-11-11 16:43:30.028 INFO 2452 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
    17. 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 ''
    18. 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“的日志。

    1. "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
    2. . ____ _ __ _ _
    3. /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
    4. ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
    5. \\/ ___)| |_)| | | | | || (_| | ) ) ) )
    6. ' |____| .__|_| |_|_| |_\__, | / / / /
    7. =========|_|==============|___/=/_/_/_/
    8. :: Spring Boot :: (v2.3.7.RELEASE)
    9. 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)
    10. 2022-11-11 16:43:26.762 INFO 2452 --- [ main] SpringbootReadWriteSplitMysqlApplication : No active profile set, falling back to default profiles: default
    11. 2022-11-11 16:43:28.525 INFO 2452 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
    12. 2022-11-11 16:43:28.541 INFO 2452 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
    13. 2022-11-11 16:43:28.541 INFO 2452 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.41]
    14. 2022-11-11 16:43:28.606 INFO 2452 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
    15. 2022-11-11 16:43:28.606 INFO 2452 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1781 ms
    16. 2022-11-11 16:43:30.028 INFO 2452 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
    17. 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 ''
    18. 2022-11-11 16:43:30.511 INFO 2452 --- [ main] SpringbootReadWriteSplitMysqlApplication : Started SpringbootReadWriteSplitMysqlApplication in 4.093 seconds (JVM running for 4.693)
    19. 2022-11-11 16:44:12.596 INFO 2452 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
    20. 2022-11-11 16:44:12.596 INFO 2452 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
    21. 2022-11-11 16:44:12.610 INFO 2452 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 14 ms
    22. 切换到master
    23. 2022-11-11 16:46:07.003 INFO 2452 --- [nio-8080-exec-4] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
    24. 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“的日志。

    1. "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
    2. . ____ _ __ _ _
    3. /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
    4. ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
    5. \\/ ___)| |_)| | | | | || (_| | ) ) ) )
    6. ' |____| .__|_| |_|_| |_\__, | / / / /
    7. =========|_|==============|___/=/_/_/_/
    8. :: Spring Boot :: (v2.3.7.RELEASE)
    9. 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)
    10. 2022-11-11 16:43:26.762 INFO 2452 --- [ main] SpringbootReadWriteSplitMysqlApplication : No active profile set, falling back to default profiles: default
    11. 2022-11-11 16:43:28.525 INFO 2452 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
    12. 2022-11-11 16:43:28.541 INFO 2452 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
    13. 2022-11-11 16:43:28.541 INFO 2452 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.41]
    14. 2022-11-11 16:43:28.606 INFO 2452 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
    15. 2022-11-11 16:43:28.606 INFO 2452 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1781 ms
    16. 2022-11-11 16:43:30.028 INFO 2452 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
    17. 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 ''
    18. 2022-11-11 16:43:30.511 INFO 2452 --- [ main] SpringbootReadWriteSplitMysqlApplication : Started SpringbootReadWriteSplitMysqlApplication in 4.093 seconds (JVM running for 4.693)
    19. 2022-11-11 16:44:12.596 INFO 2452 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
    20. 2022-11-11 16:44:12.596 INFO 2452 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
    21. 2022-11-11 16:44:12.610 INFO 2452 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 14 ms
    22. 切换到master
    23. 2022-11-11 16:46:07.003 INFO 2452 --- [nio-8080-exec-4] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
    24. 2022-11-11 16:46:07.146 INFO 2452 --- [nio-8080-exec-4] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
    25. 切换到slave
    26. 2022-11-11 16:49:04.559 INFO 2452 --- [nio-8080-exec-7] com.zaxxer.hikari.HikariDataSource : HikariPool-2 - Starting...
    27. 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做了主从复制,所以主库的变更自动复制到从库了)

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

    1. "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
    2. . ____ _ __ _ _
    3. /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
    4. ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
    5. \\/ ___)| |_)| | | | | || (_| | ) ) ) )
    6. ' |____| .__|_| |_|_| |_\__, | / / / /
    7. =========|_|==============|___/=/_/_/_/
    8. :: Spring Boot :: (v2.3.7.RELEASE)
    9. 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)
    10. 2022-11-11 16:43:26.762 INFO 2452 --- [ main] SpringbootReadWriteSplitMysqlApplication : No active profile set, falling back to default profiles: default
    11. 2022-11-11 16:43:28.525 INFO 2452 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
    12. 2022-11-11 16:43:28.541 INFO 2452 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
    13. 2022-11-11 16:43:28.541 INFO 2452 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.41]
    14. 2022-11-11 16:43:28.606 INFO 2452 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
    15. 2022-11-11 16:43:28.606 INFO 2452 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1781 ms
    16. 2022-11-11 16:43:30.028 INFO 2452 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
    17. 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 ''
    18. 2022-11-11 16:43:30.511 INFO 2452 --- [ main] SpringbootReadWriteSplitMysqlApplication : Started SpringbootReadWriteSplitMysqlApplication in 4.093 seconds (JVM running for 4.693)
    19. 2022-11-11 16:44:12.596 INFO 2452 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
    20. 2022-11-11 16:44:12.596 INFO 2452 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
    21. 2022-11-11 16:44:12.610 INFO 2452 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 14 ms
    22. 切换到master
    23. 2022-11-11 16:46:07.003 INFO 2452 --- [nio-8080-exec-4] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
    24. 2022-11-11 16:46:07.146 INFO 2452 --- [nio-8080-exec-4] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
    25. 切换到slave
    26. 2022-11-11 16:49:04.559 INFO 2452 --- [nio-8080-exec-7] com.zaxxer.hikari.HikariDataSource : HikariPool-2 - Starting...
    27. 2022-11-11 16:49:04.660 INFO 2452 --- [nio-8080-exec-7] com.zaxxer.hikari.HikariDataSource : HikariPool-2 - Start completed.
    28. 切换到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 读写分离

  • 相关阅读:
    鹤壁-食品、餐饮、工厂一定要运行HACCP吗?
    【面试题】智力题
    Linux内核源码分析 (B.10)构建 Linux 页表体系 —— 详解虚拟内存如何与物理内存进行映射
    记忆科技携手中国电信,一站式存储打造坚实数字底座
    Comparator之用最少数量的箭引爆气球
    Hyperledger Fabric 部署在多个主机上
    了解网络黑客的关键攻击方法
    .NET餐厅管理系统sql数据帮助类执行对单个Entity的更新(这个可以添加额外的约束条件)
    免密登录和Jenkins自动复制jar包以及启动
    关于DOS/DDOS攻击和防御
  • 原文地址:https://blog.csdn.net/wangdonghao137/article/details/127805751