当前位置: 首页 > news >正文

建网站维护要多少钱国内有什么网站

建网站维护要多少钱,国内有什么网站,carousel wordpress,搜索关键词查询工具基于mysql集群&mybatis-plus动态数据源实现数据库读写分离和从库负载均衡教程(详细案例) 本案例基于 Spring Boot 2.7.x MyBatis-Plus 3.5.x MySQL 8.0 实现,包含完整的项目搭建、配置、代码编写和测试验证,适合中小型项目快…

基于mysql集群&mybatis-plus动态数据源实现数据库读写分离和从库负载均衡教程(详细案例)

本案例基于 Spring Boot 2.7.x + MyBatis-Plus 3.5.x + MySQL 8.0 实现,包含完整的项目搭建、配置、代码编写和测试验证,适合中小型项目快速落地读写分离。

一、环境准备

1. 数据库环境(已搭建的主从集群)

角色IP地址数据库账号权限说明
主库192.168.1.100root/Root@123456读写权限(处理写请求)
从库1192.168.1.101read_user/Read@123456只读权限(仅SELECT,处理读请求)
从库2192.168.1.102read_user/Read@123456只读权限(仅SELECT,处理读请求)

2. 项目依赖(pom.xml)

创建 Spring Boot 项目,在 pom.xml 中引入核心依赖(动态数据源、MyBatis-Plus、MySQL 驱动等):

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.15</version> <!-- 稳定版 --><relativePath/></parent><groupId>com.example</groupId><artifactId>mysql-read-write-split</artifactId><version>1.0-SNAPSHOT</version><dependencies><!-- Spring Boot Web(用于测试接口) --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- MyBatis-Plus 核心依赖 --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.4.1</version></dependency><!-- 动态数据源插件(实现读写分离核心) --><dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>3.6.1</version></dependency><!-- MySQL 驱动(适配 MySQL 8.0) --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version><scope>runtime</scope></dependency><!-- Lombok(简化实体类代码) --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!-- Spring Boot 测试(用于单元测试) --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build>
</project>

二、核心配置(application.yml)

src/main/resources/application.yml 中配置 多数据源、负载均衡策略、MyBatis-Plus 等核心参数:

# 服务端口
server:port: 8080# 数据库配置(动态数据源)
spring:datasource:dynamic:primary: master  # 默认数据源(写请求默认走主库)strict: false    # 非严格模式:找不到指定数据源时,自动使用primary数据源load-balance: round_robin  # 从库负载均衡策略:round_robin(轮询)、random(随机)health: true     # 开启数据源健康检测(故障从库自动剔除)health-timeout: 3000  # 健康检测超时时间(毫秒)# 多数据源列表datasource:# 主库数据源(处理写请求)master:url: jdbc:mysql://192.168.1.100:3306/test?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=trueusername: rootpassword: Root@123456driver-class-name: com.mysql.cj.jdbc.Driver# 从库1数据源(处理读请求)slave1:url: jdbc:mysql://192.168.1.101:3306/test?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=trueusername: read_userpassword: Read@123456driver-class-name: com.mysql.cj.jdbc.Driver# 从库2数据源(处理读请求)slave2:url: jdbc:mysql://192.168.1.202:3306/test?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=trueusername: read_userpassword: Read@123456driver-class-name: com.mysql.cj.jdbc.Driver# 数据源分组(将从库归为一组,实现负载均衡)datasource-group:slave_group: slave1,slave2  # slave_group组包含slave1和slave2# MyBatis-Plus 配置
mybatis-plus:mapper-locations: classpath*:mapper/**/*.xml  # Mapper.xml文件路径type-aliases-package: com.example.entity       # 实体类包路径configuration:map-underscore-to-camel-case: true  # 开启下划线转驼峰(如user_name -> userName)log-impl: org.apache.ibatis.logging.stdout.StdOutImpl  # 打印SQL日志(方便测试验证)

三、代码编写(分层实现)

实体类 → Mapper → Service → Controller 分层编写代码,核心通过 @DS 注解指定数据源。

1. 实体类(Entity)

对应数据库 test 库的 user 表(提前在主库创建表):

package com.example.entity;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;import java.time.LocalDateTime;/*** 用户实体类(对应test.user表)*/
@Data
@TableName("user")  // 关联数据库表名
public class User {@TableId(type = IdType.AUTO)  // 主键自增private Long id;              // 用户IDprivate String username;      // 用户名private String password;      // 密码(实际项目需加密存储)private Integer age;          // 年龄private LocalDateTime createTime;  // 创建时间(默认当前时间)
}

2. 数据库表创建(主库执行)

在主库 test 库中创建 user 表(从库会自动同步):

CREATE TABLE IF NOT EXISTS `user` (`id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户ID',`username` varchar(50) NOT NULL COMMENT '用户名',`password` varchar(100) NOT NULL COMMENT '密码',`age` int DEFAULT NULL COMMENT '年龄',`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

3. Mapper 接口(数据访问层)

继承 MyBatis-Plus 的 BaseMapper,无需手动写 SQL(简单CRUD):

package com.example.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.entity.User;
import org.apache.ibatis.annotations.Mapper;/*** User Mapper 接口(MyBatis-Plus自动实现CRUD)*/
@Mapper  // 标记为MyBatis Mapper接口
public interface UserMapper extends BaseMapper<User> {// 无需额外方法,BaseMapper已提供:insert、deleteById、updateById、selectById、selectList等
}

4. Service 层(业务逻辑层)

核心层:通过 @DS 注解指定数据源,实现读写分离与负载均衡。

4.1 Service 接口
package com.example.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.example.entity.User;import java.util.List;/*** User Service 接口*/
public interface UserService extends IService<User> {// 写操作:新增用户(走主库)boolean addUser(User user);// 读操作:按ID查询用户(走从库集群,负载均衡)User getUserById(Long id);// 读操作:查询所有用户(走从库1,指定单个从库)List<User> listAllUserFromSlave1();// 读操作:按年龄查询用户(走从库2,指定单个从库)List<User> listUserByAge(Integer age);
}
4.2 Service 实现类(核心:@DS 注解使用)
package com.example.service.impl;import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.entity.User;
import com.example.mapper.UserMapper;
import com.example.service.UserService;
import org.springframework.stereotype.Service;import java.util.List;
import java.util.Map;/*** User Service 实现类* 关键:@DS注解指定数据源,未指定则默认走primary(master)*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {/*** 写操作:新增用户* 未加@DS注解 → 默认走primary(master主库),符合"写请求走主库"原则*/@Overridepublic boolean addUser(User user) {return save(user);  // MyBatis-Plus提供的save方法(INSERT操作)}/*** 读操作:按ID查询用户* @DS("slave_group") → 走从库集群(slave1和slave2),按轮询策略负载均衡*/@Override@DS("slave_group")public User getUserById(Long id) {return getById(id);  // MyBatis-Plus提供的getById方法(SELECT操作)}/*** 读操作:查询所有用户* @DS("slave1") → 强制走slave1从库*/@Override@DS("slave1")public List<User> listAllUserFromSlave1() {return list();  // MyBatis-Plus提供的list方法(SELECT * FROM user)}/*** 读操作:按年龄查询用户* @DS("slave2") → 强制走slave2从库* 自定义SQL(需在Mapper.xml中编写)*/@Override@DS("slave2")public List<User> listUserByAge(Integer age) {// 调用Mapper自定义方法(参数用Map传递,或用@Param注解)return baseMapper.selectListByAge(age);}
}

5. Mapper 自定义 SQL(可选,复杂查询)

若需要复杂查询(如按条件筛选),在 src/main/resources/mapper/UserMapper.xml 中编写 SQL:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapper"><!-- 自定义查询:按年龄查询用户 --><select id="selectListByAge" resultType="com.example.entity.User">SELECT id, username, password, age, create_time AS createTimeFROM userWHERE age = #{age}</select></mapper>

同时在 UserMapper 接口中添加对应方法:

// UserMapper.java 中新增方法
List<User> selectListByAge(@Param("age") Integer age);

6. Controller 层(接口层,用于测试)

编写 REST 接口,通过 Postman 或浏览器测试读写分离效果:

package com.example.controller;import com.example.entity.User;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.util.List;/*** User 控制器(测试读写分离接口)*/
@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;/*** 1. 写操作:新增用户(走主库)* 请求方式:POST* 请求体:{"username":"test1","password":"123456","age":20}*/@PostMapping("/add")public String addUser(@RequestBody User user) {boolean success = userService.addUser(user);return success ? "新增用户成功(走主库)" : "新增用户失败";}/*** 2. 读操作:按ID查询用户(走从库集群,负载均衡)* 请求方式:GET* 示例:http://localhost:8080/user/get/1*/@GetMapping("/get/{id}")public User getUserById(@PathVariable Long id) {User user = userService.getUserById(id);return user;}/*** 3. 读操作:查询所有用户(走slave1从库)* 请求方式:GET* 示例:http://localhost:8080/user/list/slave1*/@GetMapping("/list/slave1")public List<User> listAllUserFromSlave1() {return userService.listAllUserFromSlave1();}/*** 4. 读操作:按年龄查询用户(走slave2从库)* 请求方式:GET* 示例:http://localhost:8080/user/list/age?age=20*/@GetMapping("/list/age")public List<User> listUserByAge(@RequestParam Integer age) {return userService.listUserByAge(age);}
}

四、项目启动类

添加 @MapperScan 注解,扫描 Mapper 接口:

package com.example;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;/*** 项目启动类*/
@SpringBootApplication
@MapperScan("com.example.mapper")  // 扫描Mapper接口所在包
public class MysqlReadWriteSplitApplication {public static void main(String[] args) {SpringApplication.run(MysqlReadWriteSplitApplication.class, args);}}

五、测试验证(核心步骤)

启动项目后,通过 SQL日志数据库数据 验证读写分离与负载均衡效果。

1. 验证“写操作走主库”

步骤1:调用新增用户接口

用 Postman 发送 POST 请求:

  • URL:http://localhost:8080/user/add
  • 请求体:
    {"username": "test_user1","password": "123456","age": 25
    }
    
步骤2:查看 SQL 日志

控制台会打印新增用户的 SQL,且数据源为 master

JDBC Connection [com.zaxxer.hikari.HikariProxyConnection@xxxx] will be used by dynamic datasource
==>  Preparing: INSERT INTO user ( username, password, age, create_time ) VALUES ( ?, ?, ?, ? )
==> Parameters: test_user1(String), 123456(String), 25(Integer), 2025-09-10T10:00:00(LocalDateTime)
<==  Updates: 1
步骤3:验证主从数据同步
  • 主库查询:SELECT * FROM test.user; → 能看到 test_user1
  • 从库1/2查询:SELECT * FROM test.user; → 也能看到 test_user1(主从同步生效)。

2. 验证“读操作走从库集群(负载均衡)”

步骤1:多次调用“按ID查询”接口

用浏览器或 Postman 多次访问:http://localhost:8080/user/get/1(假设新增用户的ID为1)。

步骤2:查看 SQL 日志(轮询效果)

第一次请求:数据源为 slave1

JDBC Connection [com.zaxxer.hikari.HikariProxyConnection@xxxx] will be used by dynamic datasource : slave1
==>  Preparing: SELECT id,username,password,age,create_time AS createTime FROM user WHERE id=?
==> Parameters: 1(Long)
<==  Total: 1

第二次请求:数据源自动切换为 slave2(轮询策略生效):

JDBC Connection [com.zaxxer.hikari.HikariProxyConnection@xxxx] will be used by dynamic datasource : slave2
==>  Preparing: SELECT id,username,password,age,create_time AS createTime FROM user WHERE id=?
==> Parameters: 1(Long)
<==  Total: 1

第三次请求:又切换回 slave1,以此循环,证明从库负载均衡生效。

3. 验证“指定从库读取”

步骤1:调用“查询所有用户(slave1)”接口

访问:http://localhost:8080/user/list/slave1,日志显示数据源为 slave1

JDBC Connection [com.zaxxer.hikari.HikariProxyConnection@xxxx] will be used by dynamic datasource : slave1
==>  Preparing: SELECT id,username,password,age,create_time AS createTime FROM user
==> Parameters: 
<==  Total: 1
步骤2:调用“按年龄查询(slave2)”接口

访问:http://localhost:8080/user/list/age?age=25,日志显示数据源为 slave2

JDBC Connection [com.zaxxer.hikari.HikariProxyConnection@xxxx] will be used by dynamic datasource : slave2
==>  Preparing: SELECT id, username, password, age, create_time AS createTime FROM user WHERE age = ?
==> Parameters: 25(Integer)
<==  Total: 1

六、常见问题处理

1. 从库连接失败(日志显示“Access denied”)

  • 原因:从库 read_user 账号密码错误,或未授予 SELECT 权限。
  • 解决:在从库执行授权语句:
    -- 从库执行:授予read_user只读权限
    GRANT SELECT ON test.* TO 'read_user'@'%' IDENTIFIED WITH mysql_native_password BY 'Read@123456';
    FLUSH PRIVILEGES;
    

2. 负载均衡不生效(始终走同一个从库)

  • 原因:application.yml 中未配置 datasource-group,或 @DS 注解指定的是单个从库(如 @DS("slave1"))。
  • 解决:确保 datasource-group 配置正确,且读操作注解为 @DS("slave_group")

3. 主从延迟导致读不到新数据

  • 原因:主库写入后,数据同步到从库有延迟(如1秒),立即读从库会看到旧数据。
  • 解决:核心读请求(如“刚新增完用户就查询”)强制走主库,添加 @DS("master") 注解:
    @Override
    @DS("master")  // 强制走主库,避免主从延迟
    public User getNewUserById(Long id) {return getById(id);
    }
    

七、总结

本案例通过 MyBatis-Plus 动态数据源插件 实现了:

  1. 读写分离:写操作默认走主库,读操作通过 @DS 注解走从库;
  2. 从库负载均衡:从库集群(slave_group)按轮询策略分发读请求;
  3. 灵活路由:支持指定单个从库(如 @DS("slave1"))或强制走主库(如 @DS("master"))。

该方案无需额外中间件,代码侵入性低,适合中小型 Spring Boot 项目快速落地读写分离,且后续可通过自定义负载均衡策略(如权重)进一步优化。

http://www.dtcms.com/a/552611.html

相关文章:

  • 网站数据分析指标百度最新收录方法
  • 重庆忠县网站建设公司电话网站制作建设有哪些
  • 网站开发系统学习手机企业网站怎么做
  • 小迪网站建设世界软件公司排名
  • 网站建设验收方发言稿昆明快速做网站
  • 刚开今天新开传奇网站咸阳网
  • 建站公司费用网页图片不清晰怎么办
  • 网站建设转正申请报告东阿网站建设价格
  • 评价一个网站wordpress 极致优化
  • 可以悬赏做任务的叫什么网站长垣做网站
  • 网站开发用python吗云服务器搭建个人网站
  • 网站建设收费标准市场网络服务提供者知道网络用户利用其网络服务侵害他人
  • 没有公司网站如何做推广少儿编程网
  • 大连企业网站设计欣赏网络销售公司产品推广方案
  • 网站首页幻灯片代码个人网站建立
  • 礼县住房和城乡建设局网站舟山外贸营销网站建站
  • 网站软件定制开发公司十大不收费看盘软件排名
  • 哪些网站做免费送东西的广告6沈阳网下载
  • 网站首页设计制作教程温州做网站seo
  • 购物商城网站开发目的文档深圳电器公司招聘
  • 网站大数据怎么做的网上商城网站 找什么做
  • 设建网站贵州最新消息今天
  • 五金外贸网站模板全球最大的平面设计网站
  • 现代郑州网站建设自贡建设能源开发有限公司网站
  • 海南景区网站建设方案wordpress 文章连续
  • 网站建设怎么添加背景音乐有空间域名服务器怎么做网站
  • 广东模板网站建设报价企业网站的建设怎么收费
  • 站长工具域名电商网站成品案例
  • 冬创网站建设培训中心批量 发布 wordpress
  • 网站制作应用网站制作系统哪个好