SpringBoot框架简单整合ShardingSphere-JDBC实现MySQL分库分表和读写分离及加密混合

1. 主从配置

1.1 主机1(IP:192.168.186.77)

1.1.1 docker-compose.yml

version: '3.8'services:mysql-master:image: mysql:latestcontainer_name: mysql-masterenvironment:MYSQL_ROOT_PASSWORD: 123456MYSQL_USER: masterMYSQL_PASSWORD: 123456MYSQL_DATABASE: db1  ports:- "3306:3306"volumes:- mysql-master-data:/var/lib/mysqlcommand: --server-id=1 --log-bin=mysql-bin --binlog-format=ROWcap_add:- SYS_NICEsecurity_opt:- seccomp:unconfinedmysql-slave:image: mysql:latestcontainer_name: mysql-slaveenvironment:MYSQL_ROOT_PASSWORD: 123456MYSQL_USER: slaveMYSQL_PASSWORD: 123456MYSQL_DATABASE: db1ports:- "3307:3306"volumes:- mysql-slave-data:/var/lib/mysqlcommand: --server-id=2 --log-bin=mysql-bin --binlog-format=ROW --relay-log=relay-bin --relay-log-index=relay-bin.indexdepends_on:- mysql-mastercap_add:- SYS_NICEsecurity_opt:- seccomp:unconfinedvolumes:mysql-master-data:mysql-slave-data:

说明:端口3306充当主库,端口3307充当从库,创建的时候同时创建新用户和密码,如用户master,同时创建的时候也创建数据库db1。在MySQL 的主从复制架构中,每个实例都必须有一个唯一的 server-id。即使实例位于不同的 IP 地址上,每个实例的 server-id 也必须是唯一的。

1.1.2 启动主从数据库

docker-compose up -d

1.1.3 主数据库用户授权

# 给mater用户授全部权限
GRANT ALL PRIVILEGES ON *.* TO 'master'@'%';
FLUSH PRIVILEGES;

1.1.4 配置主从数据库

1.1.4.1 配置主数据库
# 创建主从配置之间的用户
CREATE USER 'master_slave'@'%' IDENTIFIED BY '123456' REQUIRE SSL;
GRANT REPLICATION SLAVE ON *.* TO 'master_slave'@'%';
FLUSH PRIVILEGES;
# 查看FILE 和 Position 文件
SHOW MASTER STATUS;

说明:FILE 和 Position 是配置从数据库的关键,需要自行查看并修改对应坐标。 

1.1.4.2 配置从数据库 
CHANGE MASTER TOMASTER_HOST ='192.168.186.77', # 主服务器的 IP 地址MASTER_USER ='master_slave', # 主服务器上配置的复制用户MASTER_PASSWORD ='123456', # 复制用户的密码MASTER_LOG_FILE ='mysql-bin.000003', # 主服务器的日志文件名MASTER_LOG_POS =1358, # 日志文件的位置MASTER_SSL=1;
START SLAVE;
SHOW SLAVE STATUS;

 说明:出现 Slave_IO_Running 和 Slave_SQL_Running 都是YES说明主从配置成功。

 1.1.4.3 创建数据库表
use db1;
CREATE TABLE t_order_0
(order_id   INT PRIMARY KEY,user_id    INT,order_date DATE,status     VARCHAR(255)
);CREATE TABLE t_order_1
(order_id   INT PRIMARY KEY,user_id    INT,order_date DATE,status     VARCHAR(255)
);

 说明 :需要在不同IP的主数据库上执行该数据库语句,创建真实物理表,从数据库会自动同步复制数据库的结构。ShardingSphere会创建逻辑数据库数据表根据分库规则实现分库分表。

注意:主机2和主机3的配置流程几乎相同,如果个人能力允许可以跳过该部分。

1.2 主机2(IP:192.168.186.216)

1.2.1 docker-compose.yml

version: '3.8'services:mysql-master:image: mysql:latestcontainer_name: mysql-masterenvironment:MYSQL_ROOT_PASSWORD: 123456MYSQL_USER: masterMYSQL_PASSWORD: 123456MYSQL_DATABASE: db2  ports:- "3306:3306"volumes:- mysql-master-data:/var/lib/mysqlcommand: --server-id=3 --log-bin=mysql-bin --binlog-format=ROWcap_add:- SYS_NICEsecurity_opt:- seccomp:unconfinedmysql-slave:image: mysql:latestcontainer_name: mysql-slaveenvironment:MYSQL_ROOT_PASSWORD: 123456MYSQL_USER: slaveMYSQL_PASSWORD: 123456MYSQL_DATABASE: db2  ports:- "3307:3306"volumes:- mysql-slave-data:/var/lib/mysqlcommand: --server-id=4 --log-bin=mysql-bin --binlog-format=ROW --relay-log=relay-bin --relay-log-index=relay-bin.indexdepends_on:- mysql-mastercap_add:- SYS_NICEsecurity_opt:- seccomp:unconfinedvolumes:mysql-master-data:mysql-slave-data:

说明:通过server-id 区分不同的主从数据库。

1.2.2 启动主从数据库

docker-compose up -d

1.2.3 主数据库用户授权

# 给mater用户授全部权限
GRANT ALL PRIVILEGES ON *.* TO 'master'@'%';
FLUSH PRIVILEGES;

1.2.4 配置主从数据库

1.2.4.1 配置主数据库
# 创建主从配置之间的用户
CREATE USER 'master_slave'@'%' IDENTIFIED BY '123456' REQUIRE SSL;
GRANT REPLICATION SLAVE ON *.* TO 'master_slave'@'%';
FLUSH PRIVILEGES;
# 查看FILE 和 Position 文件
SHOW MASTER STATUS;

说明:FILE 和 Position 是配置从数据库的关键,需要自行查看并修改对应坐标。

 1.2.4.2 配置从数据库 
CHANGE MASTER TOMASTER_HOST ='192.168.186.216', # 主服务器的 IP 地址MASTER_USER ='master_slave', # 主服务器上配置的复制用户MASTER_PASSWORD ='123456', # 复制用户的密码MASTER_LOG_FILE ='mysql-bin.000003', # 主服务器的日志文件名MASTER_LOG_POS =1781, # 日志文件的位置MASTER_SSL=1;
START SLAVE;
SHOW SLAVE STATUS;

说明:出现 Slave_IO_Running 和 Slave_SQL_Running 都是YES说明主从配置成功。

1.2.4.3 创建数据库表
use db2;
CREATE TABLE t_order_0
(order_id   INT PRIMARY KEY,user_id    INT,order_date DATE,status     VARCHAR(255)
);CREATE TABLE t_order_1
(order_id   INT PRIMARY KEY,user_id    INT,order_date DATE,status     VARCHAR(255)
);

说明 :需要在不同IP的主数据库上执行该数据库语句,创建真实物理表,从数据库会自动同步复制数据库的结构。ShardingSphere会创建逻辑数据库数据表根据分库规则实现分库分表。

1.3 主机3(IP:192.168.186.18) 

1.3.1 docker-compose.yml

version: '3.8'services:mysql-master:image: mysql:latestcontainer_name: mysql-masterenvironment:MYSQL_ROOT_PASSWORD: 123456MYSQL_USER: masterMYSQL_PASSWORD: 123456MYSQL_DATABASE: db3  ports:- "3306:3306"volumes:- mysql-master-data:/var/lib/mysqlcommand: --server-id=5 --log-bin=mysql-bin --binlog-format=ROWcap_add:- SYS_NICEsecurity_opt:- seccomp:unconfinedmysql-slave:image: mysql:latestcontainer_name: mysql-slaveenvironment:MYSQL_ROOT_PASSWORD: 123456MYSQL_USER: slaveMYSQL_PASSWORD: 123456MYSQL_DATABASE: db3 ports:- "3307:3306"volumes:- mysql-slave-data:/var/lib/mysqlcommand: --server-id=6 --log-bin=mysql-bin --binlog-format=ROW --relay-log=relay-bin --relay-log-index=relay-bin.indexdepends_on:- mysql-mastercap_add:- SYS_NICEsecurity_opt:- seccomp:unconfinedvolumes:mysql-master-data:mysql-slave-data:

说明:通过server-id不同的主从数据库。

1.3.2 启动主从数据库

docker-compose up -d

1.3.3 主数据库用户授权

# 给mater用户授全部权限
GRANT ALL PRIVILEGES ON *.* TO 'master'@'%';
FLUSH PRIVILEGES;

1.3.4 配置主从数据库

1.3.4.1 配置主数据库
# 创建主从配置之间的用户
CREATE USER 'master_slave'@'%' IDENTIFIED BY '123456' REQUIRE SSL;
GRANT REPLICATION SLAVE ON *.* TO 'master_slave'@'%';
FLUSH PRIVILEGES;
# 查看FILE 和 Position 文件
SHOW MASTER STATUS;

说明:FILE 和 Position 是配置从数据库的关键,需要自行查看并修改对应坐标。  

1.3.4.2 配置从数据库  

说明:出现 Slave_IO_Running 和 Slave_SQL_Running 都是YES说明主从配置成功。

1.3.4.3 创建数据库表
use db3;
CREATE TABLE t_order_0
(order_id   INT PRIMARY KEY,user_id    INT,order_date DATE,status     VARCHAR(255)
);CREATE TABLE t_order_1
(order_id   INT PRIMARY KEY,user_id    INT,order_date DATE,status     VARCHAR(255)
);

1.4 其他

ERROR:

Coordinator stopped because there were error(s) in the worker(s). The most recent failure being: Worker 1 failed executing transaction 'ANONYMOUS' at master log mysql-bin.000003, end_log_pos 3890. See error log and/or performance_schema.replication_applier_status_by_worker table for more details about this failure or others, if any.

        如果遇到主从复制错误(我遇到是给用户重新授权的时候出现的),可以尝试以下解决方法: 

-- 停止从库复制
STOP SLAVE;-- 跳过一个错误的事务
SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;-- 重新启动从库复制
START SLAVE;

2. ShardingSphere-JDBC

2.1 项目结构

2.2 Maven依赖 

<?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 https://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>3.3.2</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>org.example</groupId><artifactId>ShardingSphere-JDBC</artifactId><version>0.0.1-SNAPSHOT</version><properties><java.version>17</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- https://mvnrepository.com/artifact/org.apache.shardingsphere/shardingsphere-jdbc --><dependency><groupId>org.apache.shardingsphere</groupId><artifactId>shardingsphere-jdbc</artifactId><version>5.5.0</version><exclusions><exclusion><groupId>org.apache.shardingsphere</groupId><artifactId>shardingsphere-test-util</artifactId></exclusion></exclusions></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>

2.3 Order.java

package org.example.entity;import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Data;
import java.util.Date;@Entity
@Table(name = "t_order")
@Data
public class Order {@Id@Column(name = "order_id")private int orderId;@Column(name = "user_id")private int userId;@Column(name = "order_date")private Date orderDate;@Column(name = "status")private String status;
}

 2.4 orderRepository.java

package org.example.repository;import org.example.entity.Order;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;@Repository
public interface orderRepository extends JpaRepository<Order, Long> {
}

2.5 ShardingSphereConfig.java

package org.example.config;import org.apache.shardingsphere.driver.api.yaml.YamlShardingSphereDataSourceFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;import javax.sql.DataSource;import java.io.IOException;
import java.sql.SQLException;@Configuration
public class ShardingSphereConfig{@Value("shardingsphere.yaml")private ClassPathResource config;@Beanpublic DataSource dataSource() throws SQLException, IOException {return YamlShardingSphereDataSourceFactory.createDataSource(config.getContentAsByteArray());}
}

说明:通过@Value注入shardingsphere.yaml并创建dataSource的Bean。

数据分片 :: ShardingSphere 

2.6 application.yaml 

spring:application:name: ShardingSphere-JDBC

2.7 logback.xml 

<configuration><!-- 定义过滤器,用于过滤出包含 "Logic SQL:" 或 "Actual SQL:" 的日志消息 --><appender name="SQL_FILTER" class="ch.qos.logback.core.ConsoleAppender"><encoder><!-- 只打印消息部分 --><pattern>%msg%n</pattern></encoder><filter class="ch.qos.logback.core.filter.EvaluatorFilter"><evaluator class="ch.qos.logback.classic.boolex.JaninoEventEvaluator"><expression>return message.contains("Logic SQL:") || message.contains("Actual SQL:");</expression></evaluator><OnMismatch>DENY</OnMismatch><OnMatch>ACCEPT</OnMatch></filter></appender><!-- 配置针对 ShardingSphere-SQL 的日志输出 --><logger name="ShardingSphere-SQL" level="INFO" additivity="false"><appender-ref ref="SQL_FILTER" /></logger>
</configuration>

2.8 shardingsphere.yaml

2.8.1 逻辑数据库名称

databaseName: my_database # 数据库配置名称。

2.8.2 数据源配置

dataSources:ds_77_master:# 主数据库服务器的配置,IP 为 192.168.186.77,端口为 3306。dataSourceClassName: com.zaxxer.hikari.HikariDataSource# HikariCP 数据源的完整类名。url: jdbc:mysql://192.168.186.77:3306/db1?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true# 用于连接 MySQL 数据库的 JDBC URL。# serverTimezone=UTC 确保服务器时区设置为 UTC。# useSSL=false 禁用 SSL。# allowPublicKeyRetrieval=true 允许客户端从服务器检索公钥。username: master# 用于连接数据库的用户名。password: 123456# 数据库用户的密码。connectionTimeoutMilliseconds: 30000# 客户端等待从连接池获取连接的最大时间(以毫秒为单位)。# 默认值为 30000 毫秒(30 秒)。idleTimeoutMilliseconds: 60000# 连接在连接池中闲置的最长时间(以毫秒为单位)。# 默认值为 600000 毫秒(10 分钟)。maxLifetimeMilliseconds: 1800000# 连接在连接池中的最长存活时间(以毫秒为单位)。# 默认值为 1800000 毫秒(30 分钟)。maxPoolSize: 50# 连接池将维持的最大连接数。# 默认值为 10。minPoolSize: 1# 连接池将维持的最小闲置连接数。# 默认值为 1。ds_77_slave:# 从数据库服务器的配置,IP 为 192.168.186.77,端口为 3307。dataSourceClassName: com.zaxxer.hikari.HikariDataSourceurl: jdbc:mysql://192.168.186.77:3307/db1?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=trueusername: slavepassword: 123456connectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50minPoolSize: 1ds_216_master:# 主数据库服务器的配置,IP 为 192.168.186.216,端口为 3306。dataSourceClassName: com.zaxxer.hikari.HikariDataSourceurl: jdbc:mysql://192.168.186.216:3306/db2?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=trueusername: masterpassword: 123456connectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50minPoolSize: 1ds_216_slave:# 从数据库服务器的配置,IP 为 192.168.186.216,端口为 3307。dataSourceClassName: com.zaxxer.hikari.HikariDataSourceurl: jdbc:mysql://192.168.186.216:3307/db2?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=trueusername: slavepassword: 123456connectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50minPoolSize: 1ds_18_master:# 主数据库服务器的配置,IP 为 192.168.186.18,端口为 3306。dataSourceClassName: com.zaxxer.hikari.HikariDataSourceurl: jdbc:mysql://192.168.186.18:3306/db3?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=trueusername: masterpassword: 123456connectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50minPoolSize: 1ds_18_slave:# 从数据库服务器的配置,IP 为 192.168.186.18,端口为 3307。dataSourceClassName: com.zaxxer.hikari.HikariDataSourceurl: jdbc:mysql://192.168.186.18:3307/db3?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=trueusername: slavepassword: 123456connectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50minPoolSize: 1

 2.8.3 读写分离规则

rules:- !READWRITE_SPLITTING# 配置读写分离规则。dataSources:# 定义数据源组。readwrite_77:# 名为 readwrite_77 的读写分离数据源组配置。writeDataSourceName: ds_77_master  # 写操作的数据源名称,指向 ds_77_master 数据源。readDataSourceNames:               # 读操作的数据源名称列表,这里指定为 ds_77_slave 数据源。- ds_77_slavetransactionalReadQueryStrategy: DYNAMIC  # 事务性读查询策略,DYNAMIC 表示根据实际情况动态选择数据源。loadBalancerName: random                 # 负载均衡器名称,指向名为 random 的负载均衡策略。readwrite_216:# 名为 readwrite_216 的读写分离数据源组配置。writeDataSourceName: ds_216_master  # 写操作的数据源名称,指向 ds_216_master 数据源。readDataSourceNames:                # 读操作的数据源名称列表,这里指定为 ds_216_slave 数据源。- ds_216_slavetransactionalReadQueryStrategy: DYNAMIC  # 事务性读查询策略,DYNAMIC 表示根据实际情况动态选择数据源。loadBalancerName: random                 # 负载均衡器名称,指向名为 random 的负载均衡策略。readwrite_18:# 名为 readwrite_18 的读写分离数据源组配置。writeDataSourceName: ds_18_master  # 写操作的数据源名称,指向 ds_18_master 数据源。readDataSourceNames:               # 读操作的数据源名称列表,这里指定为 ds_18_slave 数据源。- ds_18_slavetransactionalReadQueryStrategy: DYNAMIC  # 事务性读查询策略,DYNAMIC 表示根据实际情况动态选择数据源。loadBalancerName: random                 # 负载均衡器名称,指向名为 random 的负载均衡策略。loadBalancers:# 定义负载均衡策略。random:# 名为 random 的负载均衡策略配置。type: RANDOM  # 负载均衡策略类型,这里设置为随机(RANDOM)。

说明:transactionalReadQueryStrategy对应参数 PRIMARYFIXEDDYNAMIC 对应不同的读写分离策略:

  1. PRIMARY: 只从主库读取。这通常用于需要确保读取到最新数据的情况。

  2. FIXED: 固定从库读取。这种情况下会根据配置的从库列表选择特定的从库读取数据。

  3. DYNAMIC: 动态从库读取。根据负载均衡策略动态选择从库读取数据。

     如果想让读操作从从库读取,可以配置 FIXEDDYNAMIC 策略。

2.8.4 分片规则

- !SHARDING# 配置分片规则。tables:t_order:# 针对表 t_order 的分片配置。actualDataNodes: readwrite_77.t_order_${0..1}, readwrite_216.t_order_${0..1}, readwrite_18.t_order_${0..1}# 实际数据节点,表示 t_order 表在三个数据源组(readwrite_77, readwrite_216, readwrite_18)的分片情况。tableStrategy:standard:shardingColumn: order_id  # 分片键为 order_id。shardingAlgorithmName: t_order_inline  # 分片算法名称为 t_order_inline。keyGenerateStrategy:column: order_id  # 主键生成策略,针对 order_id 列。keyGeneratorName: snowflake  # 主键生成器名称为 snowflake。defaultDatabaseStrategy:standard:# 默认数据库策略。shardingColumn: user_id  # 分片键为 user_id。shardingAlgorithmName: database_inline  # 分片算法名称为 database_inline。defaultTableStrategy:none:  # 默认表策略为 none,表示不进行默认表分片。bindingTables:- t_order  # 绑定表配置,表示 t_order 是一个绑定表。shardingAlgorithms:database_inline:# 分片算法名称为 database_inline。type: INLINE  # 算法类型为 INLINE。props:algorithm-expression: "readwrite_${(user_id % 3 == 0) ? '77' : ((user_id % 3 == 1) ? '216' : '18')}"# 算法表达式,根据 user_id 的值将数据分片到不同的数据源组:# 如果 user_id % 3 == 0,则选择 readwrite_77;# 如果 user_id % 3 == 1,则选择 readwrite_216;# 否则选择 readwrite_18。t_order_inline:# 分片算法名称为 t_order_inline。type: INLINE  # 算法类型为 INLINE。props:algorithm-expression: "t_order_${order_id % 2}"# 算法表达式,根据 order_id 的值将数据分片到 t_order_0 或 t_order_1:# 如果 order_id % 2 == 0,则选择 t_order_0;# 否则选择 t_order_1。keyGenerators:snowflake:# 主键生成器名称为 snowflake。type: SNOWFLAKE  # 主键生成器类型为 SNOWFLAKE。props:worker-id: 123  # SNOWFLAKE 算法的 worker-id 配置,值为 123。- !ENCRYPT# 配置加密规则。encryptors:aes_encryptor:# 加密器名称为 aes_encryptor。type: AES  # 加密器类型为 AES(对称加密算法)。props:aes-key-value: 123456abc  # AES 加密的密钥值,必须是长度为 16、24 或 32 字节的密钥。tables:t_order:# 针对表 t_order 的加密配置。columns:status:# 针对 status 列进行加密配置。cipher:name: status  # 加密后列的名称仍为 status。encryptorName: aes_encryptor  # 使用名称为 aes_encryptor 的加密器进行加密。props:sql-show: true  # 显示生成的 SQL 语句,便于调试。

2.8.5 加密规则

- !ENCRYPT# 配置加密规则。encryptors:aes_encryptor:# 加密器名称为 aes_encryptor。type: AES  # 加密器类型为 AES(对称加密算法)。props:aes-key-value: 123456abc  # AES 加密的密钥值,必须是长度为 16、24 或 32 字节的密钥。tables:t_order:# 针对表 t_order 的加密配置。columns:status:# 针对 status 列进行加密配置。cipher:name: status  # 加密后列的名称仍为 status。encryptorName: aes_encryptor  # 使用名称为 aes_encryptor 的加密器进行加密。

2.8.6 其他

props:sql-show: true  # 显示生成的 SQL 语句,便于调试。

2.8.7 完整文件 

databaseName: my_database
dataSources:ds_77_master:dataSourceClassName: com.zaxxer.hikari.HikariDataSourceurl: jdbc:mysql://192.168.186.77:3306/db1?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=trueusername: masterpassword: 123456connectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50minPoolSize: 1ds_77_slave:dataSourceClassName: com.zaxxer.hikari.HikariDataSourceurl: jdbc:mysql://192.168.186.77:3307/db1?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=trueusername: slavepassword: 123456connectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50minPoolSize: 1ds_216_master:dataSourceClassName: com.zaxxer.hikari.HikariDataSourceurl: jdbc:mysql://192.168.186.216:3306/db2?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=trueusername: masterpassword: 123456connectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50minPoolSize: 1ds_216_slave:dataSourceClassName: com.zaxxer.hikari.HikariDataSourceurl: jdbc:mysql://192.168.186.216:3307/db2?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=trueusername: slavepassword: 123456connectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50minPoolSize: 1ds_18_master:dataSourceClassName: com.zaxxer.hikari.HikariDataSourceurl: jdbc:mysql://192.168.186.18:3306/db3?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=trueusername: masterpassword: 123456connectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50minPoolSize: 1ds_18_slave:dataSourceClassName: com.zaxxer.hikari.HikariDataSourceurl: jdbc:mysql://192.168.186.18:3307/db3?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=trueusername: slavepassword: 123456connectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50minPoolSize: 1
rules:- !READWRITE_SPLITTINGdataSources:readwrite_77:writeDataSourceName: ds_77_masterreadDataSourceNames:- ds_77_slavetransactionalReadQueryStrategy: DYNAMICloadBalancerName: randomreadwrite_216:writeDataSourceName: ds_216_masterreadDataSourceNames:- ds_216_slavetransactionalReadQueryStrategy: DYNAMICloadBalancerName: randomreadwrite_18:writeDataSourceName: ds_18_masterreadDataSourceNames:- ds_18_slavetransactionalReadQueryStrategy: DYNAMICloadBalancerName: randomloadBalancers:random:type: RANDOM- !SHARDINGtables:t_order:actualDataNodes: readwrite_77.t_order_${0..1}, readwrite_216.t_order_${0..1}, readwrite_18.t_order_${0..1}tableStrategy:standard:shardingColumn: order_idshardingAlgorithmName: t_order_inlinekeyGenerateStrategy:column: order_idkeyGeneratorName: snowflakedefaultDatabaseStrategy:standard:shardingColumn: user_idshardingAlgorithmName: database_inlinedefaultTableStrategy:none:bindingTables:- t_ordershardingAlgorithms:database_inline:type: INLINEprops:algorithm-expression: "readwrite_${(user_id % 3 == 0) ? '77' : ((user_id % 3 == 1) ? '216' : '18')}"t_order_inline:type: INLINEprops:algorithm-expression: "t_order_${order_id % 2}"keyGenerators:snowflake:type: SNOWFLAKEprops:worker-id: 123- !ENCRYPTencryptors:aes_encryptor:type: AESprops:aes-key-value: 123456abctables:t_order:columns:status:cipher:name: statusencryptorName: aes_encryptor
props:sql-show: true

2.9 ShardingSphereJdbcApplicationTests.java

package org.example;import org.example.entity.Order;
import org.example.repository.orderRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Date;@SpringBootTest
class ShardingSphereJdbcApplicationTests {@AutowiredorderRepository repo;@Testvoid contextLoads() {repo.findAll().forEach(System.out::println);}@Testvoid insert(){Order newOrder = new Order();newOrder.setOrderId(1);newOrder.setUserId(10);newOrder.setOrderDate(new Date());newOrder.setStatus("INSERT");repo.save(newOrder);System.out.println("Inserted Order: " + newOrder);}@Testvoid delete(){repo.deleteById(1L);}
}

2.10 验证结果

2.10.1 分片结果

# 根据 user_id 的值将数据分片到不同的数据源组:
        # 如果 user_id % 3 == 0,则选择 readwrite_77;
        # 如果 user_id % 3 == 1,则选择 readwrite_216;
        # 否则选择 readwrite_18。

# 根据 order_id 的值将数据分片到 t_order_0 或 t_order_1:
        # 如果 order_id % 2 == 0,则选择 t_order_0;
        # 否则选择 t_order_1。

Logic SQL: insert into t_order (order_date,status,user_id,order_id) values (?,?,?,?)
Actual SQL: ds_216_master ::: insert into t_order_1 (order_date,status,user_id,order_id) values (?, ?, ?, ?) ::: [2024-07-26 10:05:21.914, 1jyA91B85/gs5gPPkYF3WA==, 10, 1]
Inserted Order: Order(orderId=1, userId=10, orderDate=Fri Jul 26 10:05:21 CST 2024, status=INSERT)

解释:10%3=1,1%2=1,所以位于主机2(ds_216_master )的数据库, t_order_1表。 

2.10.2 加密结果

Logic SQL: insert into t_order (order_date,status,user_id,order_id) values (?,?,?,?)
Actual SQL: ds_216_master ::: insert into t_order_1 (order_date,status,user_id,order_id) values (?, ?, ?, ?) ::: [2024-07-26 10:05:21.914, 1jyA91B85/gs5gPPkYF3WA==, 10, 1]
Inserted Order: Order(orderId=1, userId=10, orderDate=Fri Jul 26 10:05:21 CST 2024, status=INSERT)

 ​​​​

2.10.3 读写分离结果 

Logic SQL: select o1_0.order_id,o1_0.order_date,o1_0.status,o1_0.user_id from t_order o1_0
Actual SQL: ds_77_slave ::: select o1_0.order_id,o1_0.order_date,o1_0.status AS status,o1_0.user_id from t_order_0 o1_0 UNION ALL select o1_0.order_id,o1_0.order_date,o1_0.status AS status,o1_0.user_id from t_order_1 o1_0
Actual SQL: ds_216_slave ::: select o1_0.order_id,o1_0.order_date,o1_0.status AS status,o1_0.user_id from t_order_0 o1_0 UNION ALL select o1_0.order_id,o1_0.order_date,o1_0.status AS status,o1_0.user_id from t_order_1 o1_0
Actual SQL: ds_18_slave ::: select o1_0.order_id,o1_0.order_date,o1_0.status AS status,o1_0.user_id from t_order_0 o1_0 UNION ALL select o1_0.order_id,o1_0.order_date,o1_0.status AS status,o1_0.user_id from t_order_1 o1_0
Order(orderId=1, userId=10, orderDate=2024-07-26 00:00:00.0, status=INSERT)

3. 总结

        通过Docker-Compose启动3对IP不同的主从数据库,通过JPA和默认的HikariDataSource数据源结合MySQL将ShardingSphere-JDBC整合到SpringBoot框架,实现了读写分离,分库分片,以及加密和加密对特定的字段,仅供学习交流,不具备严谨性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/875726.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

堆的基本实现

一、堆的概念 在提出堆的概念之前&#xff0c;首先要了解二叉树的基本概念 一颗二叉树是节点的有限集合&#xff0c;该集合&#xff1a; 1、或者为空&#xff1b; 2、或者由一个根节点加上两颗分别称为左子树和右子树的两颗子树构成&#xff1b; 堆就是一颗完全二叉树&…

【Python系列】isin用法

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

电脑屏幕录制软件哪个好?推荐3款,满足各种录制需求

大家好&#xff0c;今天和大家来聊一个既实用又有点神秘的话题——电脑屏幕录制软件哪个好&#xff1f;这是个让众多网友头疼的问题&#xff0c;毕竟谁不想拥有一款既好用又好玩的录制神器呢&#xff1f; 首先&#xff0c;我们得明确屏幕录制软件可不是简单地录屏而已&#xf…

VARIAN瓦里安真空Model 979 Leak Detector Instruction Manual使用说明

VARIAN瓦里安真空Model 979 Leak Detector Instruction Manual使用说明

杂项——电阻式角度传感器使用

三个引脚&#xff0c;分别接3.3V&#xff0c;GND&#xff0c;ADC引脚。12位ADC有4096份&#xff0c;将360分成4096份&#xff0c;再乘以单片机返回的模拟量的值&#xff0c;即可得到角度。 M0代码 #include "ti_msp_dl_config.h"volatile bool gCheckADC; volatile …

免费【2024】springboot 毕业生学历证明系统

博主介绍&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围&#xff1a;SpringBoot、Vue、SSM、HTML、Jsp、PHP、Nodejs、Python、爬虫、数据可视化…

【案例】使用React+redux实现一个Todomvc

About 大家好&#xff0c;我是且陶陶&#xff0c;今天跟大家分享一个redux的todoList案例&#xff0c;通过这个案例能够快速掌握redux的基本知识点&#x1f339; ❤️…❤️…❤️…❤️…❤️…❤️…❤️…❤️…❤️…❤️…❤️…❤️…❤️…❤️…❤️…❤️…❤️…❤️…

微信小程序之计算器

在日常生活中&#xff0c;计算器是人们广泛使用的工具&#xff0c;可以帮助我们快速且方便地计算金额、成本、利润等。下面将会讲解如何开发一个“计算器”微信小程序。 一、开发思路 1、界面和功能 “计算器”微信小程序的页面效果如图所示 在计算器中可以进行整数和小数的…

C++学习笔记——模板

学习视频 文章目录 模板的概念函数模板函数模板语法函数模板注意事项函数模板案例普通函数与函数模板的区别普通函数与函数模板的调用规则模板的局限性 类模板类模板与函数模板区别类模板中成员函数创建时机类模板对象做函数参数类模板与继承类模板成员函数类外实现类模板分文件…

box-shadow属性的复合写法及高级用法,超详细!

前言&#xff1a;最近又叕看到了一个好看的特效&#xff0c;随后整理了一下&#xff0c;发现实现起来主要靠一个css属性就实现了&#xff0c;有一次刷新了我对css强大的认知&#x1f60e;&#xff0c;这个属性就是box-shadow&#xff0c;平常我们用到的比较少&#xff0c;但是针…

oracle中存储过程的写法

存储过程常规语法&#xff1a; 实际业务例子&#xff1a; CREATE OR REPLACE TRIGGER "TRI_B00_02_ONLY_GUID" BEFORE/AFTER INSERT OR UPDATE OR DELETE ON B00_02 FOR EACH ROW declare t_guid varchar2(300) : ; --GUID t_cnt int : 0; BEGIN t_guid : :NEW…

【深度学习】大模型GLM-4-9B Chat ,微调与部署(1)

下载好东西&#xff1a; 启动容器环境: docker run -it --gpus all --net host --shm-size8g -v /ssd/xiedong/glm-4-9b-xd:/ssd/xiedong/glm-4-9b-xd kevinchina/deeplearning:pytorch2.3.0-cuda12.1-cudnn8-devel-yolov8train bashpip install typer tiktoken numpy1.2…

ROS2入门到精通—— 2-11 ROS2实战:实现基于voronoi_planner的全局规划(一)!!!保姆级教程

实现基于voronoi_planner的全局规划将分为两篇博文进行讲解 本文参考该大佬代码: https://github.com/nkuwenjian/voronoi_planner.githttps://github.com/nkuwenjian/voronoi_layer.git将上面的ROS1代码移植到ROS2,移植不易,中间遇到很多坑 0 前言 针对一些狭窄区域,可能…

【机器学习】梯度下降的基本概念和如何使用梯度下降自动化优化w和b

引言 梯度下降是一种用于寻找函数最小值的优化算法&#xff0c;它在机器学习中广泛用于训练模型&#xff0c;如线性回归、神经网络等 一、梯度下降的基本概念 1.1 目标函数 在机器学习中&#xff0c;这通常是损失函数&#xff08;如均方误差、交叉熵等&#xff09;&#xff0…

深度学习趋同性的量化探索:以多模态学习与联合嵌入为例

深度学习趋同性的量化探索&#xff1a;以多模态学习与联合嵌入为例 参考文献 据说是2024年最好的人工智能论文&#xff0c;是否有划时代的意义&#xff1f; [2405.07987] The Platonic Representation Hypothesis (arxiv.org) ​arxiv.org/abs/2405.07987 趋同性的量化表达 …

Pytorch使用教学7-张量的广播

PyTorch中的张量具有和NumPy相同的广播特性&#xff0c;允许不同形状的张量之间进行计算。 广播的实质特性&#xff0c;其实是低维向量映射到高维之后&#xff0c;相同位置再进行相加。我们重点要学会的就是低维向量如何向高维向量进行映射。 相同形状的张量计算 虽然我们觉…

JAW:一款针对客户端JavaScript的图形化安全分析框架

关于JAW JAW是一款针对客户端JavaScript的图形化安全分析框架&#xff0c;该工具基于esprima解析器和EsTree SpiderMonkey Spec实现其功能&#xff0c;广大研究人员可以使用该工具分析Web应用程序和基于JavaScript的客户端程序的安全性。 工具特性 1、动态可扩展的框架&#x…

模拟ADG主库归档文件丢失,备库出现gap(增量备份解决)

文章目录 一、说明二、环境信息2.1.主备库环境信息2.2.检查主备是否同步正常 三、模拟日志断档3.1.模拟主库归档文件丢失3.2 查看主库状态出现GAP 四、RMAN增量备份恢复备库同步4.1 RMAN增量恢复备库4.2 开启备库redo同步4.3 主备库验证同步 一、说明 模拟Oracle主库归档文件丢…

Git基本原理讲解、常见命令、Git版本回退、Git抛弃本地分支拉取仓库最新分支

借此机会写篇博客汇总一下自己去公司实习之后遇到的一些常见关于Git的操作。 Git基本认识 Git把数据看作是对小型文件系统的一组快照&#xff0c;每次提交更新&#xff0c;或在Git中保存项目状态时&#xff0c;Git主要对当时的全部文件制作一个快照并保存这个快照的索引。同时…

【C++】选择结构案例-三只小猪称体重

案例问题 假设有三只小猪A、B、C&#xff0c;在输入三者体重后希望能输出他们各自的体重并测出谁最重 思路 先让A与B相比较&#xff0c;如果A重&#xff0c;则让A和C相比较&#xff0c;如果A重则输出A最重&#xff0c;否则输出C最重 在最开始的条件&#xff08;AB相比较&am…