Linux上搭建基于SpringBoot利用MyCat实现对MySQL的读写分离

mac2026-08-10  8

前言

首先为什么要做读写分离呢,大多数项目都是读的操作的次数远远要比写操作的次数多,所以让MySQL的主服务器做写操作,从服务器做读操作,下面详细的说一下如何利用MyCat做读写分离,至于MySQL的安装和搭建MySQL的主从复制请看我另一篇博客 Linux上MySQL安装和搭建MySQL的主从复制和读写分离

MyCat的安装及启动

环境装备

虚拟机:192.168.50.152(MyCat) 虚拟机:192.168.50.150(MySQl主) 虚拟机:192.168.50.151(MySQl从)

我们从网上下载一个MyCat的压缩包,放到了/usr/local这个路径,并解压,解压完之后有一个mycat的文件夹

我们进入mycat的这个文件夹,编辑conf文件夹下的schema.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mycat:schema SYSTEM "schema.dtd"> <mycat:schema xmlns:mycat="http://io.mycat/"> <!-- mycat_testdb是mycat的逻辑库名称 --> <schema name="mycat_testdb" checkSQLschema="true" sqlMaxLimit="100" > </schema> <!-- database 是MySQL数据库的库名 --> <dataNode name="dn1" dataHost="localhost1" database="test" /> <dataHost name="localhost1" maxCon="1000" minCon="10" balance="3" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100"> <heartbeat>select user()</heartbeat> <!-- 可以配置多个主从 --> <writeHost host="hostM1" url="192.168.50.150:3306" user="root" password="root"> <!-- 可以配置多个从库 --> <readHost host="hostS2" url="192.168.50.151:3306" user="root" password="root" /> </writeHost> </dataHost> </mycat:schema> 启动MyCat,进入MyCat下的bin目录,执行如下命令 ./mycat start 查看是否启动成功,查看MyCat下的logs文件夹下的wrapper.log,看到successfully就算启动成功

配置SpringBoot项目

新建yml文件,配置读和写的JDBC连接 spring: datasource: ###可读数据源 select: jdbc-url: jdbc:mysql://192.168.50.152:8066/mycat_testdb driver-class-name: com.mysql.jdbc.Driver username: user password: user ####可写数据源 update: jdbc-url: jdbc:mysql://192.168.50.152:8066/mycat_testdb driver-class-name: com.mysql.jdbc.Driver username: root password: 123456 type: com.alibaba.druid.pool.DruidDataSource 三个配置文件 @Configuration public class DataSourceConfig { // 创建可读数据源 @Bean(name = "selectDataSource") @ConfigurationProperties(prefix = "spring.datasource.select") // application.properteis中对应属性的前缀 public DataSource dataSource1() { return DataSourceBuilder.create().build(); } // 创建可写数据源 @Bean(name = "updateDataSource") @ConfigurationProperties(prefix = "spring.datasource.update") // application.properteis中对应属性的前缀 public DataSource dataSource2() { return DataSourceBuilder.create().build(); } } @Component @Lazy(false) public class DataSourceContextHolder { // 采用ThreadLocal 保存本地多数据源 private static final ThreadLocal<String> contextHolder = new ThreadLocal<>(); // 设置数据源类型 public static void setDbType(String dbType) { contextHolder.set(dbType); } public static String getDbType() { return contextHolder.get(); } public static void clearDbType() { contextHolder.remove(); } } @Component @Primary public class DynamicDataSource extends AbstractRoutingDataSource { @Autowired @Qualifier("selectDataSource") private DataSource selectDataSource; @Autowired @Qualifier("updateDataSource") private DataSource updateDataSource; /** * 这个是主要的方法,返回的是生效的数据源名称 */ @Override protected Object determineCurrentLookupKey() { System.out.println("DataSourceContextHolder:::" + DataSourceContextHolder.getDbType()); return DataSourceContextHolder.getDbType(); } /** * 配置数据源信息 */ @Override public void afterPropertiesSet() { Map<Object, Object> map = new HashMap<>(); map.put("selectDataSource", selectDataSource); map.put("updateDataSource", updateDataSource); setTargetDataSources(map); setDefaultTargetDataSource(updateDataSource); super.afterPropertiesSet(); } } 配置aop // 使用AOP动态切换不同的数据源 @Aspect @Component @Lazy(false) @Order(0) // Order设定AOP执行顺序 使之在数据库事务上先执行 public class SwitchDataSourceAOP { // 这里切到你的方法目录 @Before("execution(* com.example.demo.service.*.*(..))") public void process(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); if (methodName.startsWith("get") || methodName.startsWith("count") || methodName.startsWith("find") || methodName.startsWith("list") || methodName.startsWith("select") || methodName.startsWith("check")) { DataSourceContextHolder.setDbType("selectDataSource"); } else { // 切换dataSource DataSourceContextHolder.setDbType("updateDataSource"); } } } controller、entity、mapper、service的编写 @RestController public class UserController { @Autowired private UserService userService; @RequestMapping("/findUser") public List<UserEntity> findUser() { return userService.findUser(); } @RequestMapping("/insertUser") public List<UserEntity> insertUser(String userName) { return userService.insertUser(userName); } } public class UserEntity { private String userName; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } } public interface UserMapper { @Select("SELECT * FROM test ") public List<UserEntity> findUser(); @Select("insert into test values (#{userName}); ") public List<UserEntity> insertUser(@Param("userName") String userName); } @Service public class UserService { @Autowired private UserMapper userMapper; public List<UserEntity> findUser() { return userMapper.findUser(); } public List<UserEntity> insertUser(String userName) { return userMapper.insertUser(userName); } } 启动项目,进行测试 我们插入一条userName为123456的数据 IDEA控制台打出来的日志为updateDataSource数据源

然后我们查询一下刚才插入的数据

IDEA控制台打出来的日志为selectDataSource数据源

至此基于SpringBootl利用MyCat实现对MySQL的读写分离就搭建完毕了

总结

通过这次颗粒归仓,发现自己对这个东西还是不熟练,还是要多多学习,积累自己!

最新回复(0)