分库概念
分库是指将一个数据库的数据按照某种规则划分为多个独立的子库。每个子库都是一个独立的数据库,具有自己的表结构和数据存储。分库常用于处理大规模数据和高并发访问的场景,以提高系统的可扩展性和性能。
分库的主要目的是实现数据的分片存储和并行处理,从而提高数据库的处理能力和吞吐量。通过将数据分散存储在多个子库中,可以将负载均衡到不同的数据库节点上,减轻单一数据库的压力。同时,分库还可以支持水平扩展,使系统能够处理更大量级的数据和并发请求。
在进行分库时,常用的划分依据包括:
1.垂直分库:按照业务功能将不同的表分布到不同的数据库中,例如将用户相关表放在一个数据库,订单相关表放在另一个数据库。
2.水平分库:按照某个字段或规则将数据行分散到不同的数据库中,例如按照用户ID的哈希值进行分片,将不同用户的数据分布到不同的数据库中。
值得注意的是,分库操作需要考虑数据一致性、事务处理、跨库查询等问题,因此需要仔细设计和实施。同时,分库也增加了系统的复杂性和管理难度,需要综合考虑系统需求和资源成本。
下面我们进行分库实践
步骤基本和上一篇一样,只是配置不同
ShardingSphere实践(1)水平分表-CSDN博客
如果你看了这篇文章,也可以直接在基础上进行修改
一.加入依赖
<properties>
<mysql.version>5.1.37</mysql.version>
<mybatis.plus.boot.starter.version>3.4.2</mybatis.plus.boot.starter.version>
<lombok.version>1.18.24</lombok.version>
<druid.version>1.1.22</druid.version>
<shardingsphere.version>4.0.0-RC1</shardingsphere.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
<scope>provided</scope>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis.plus.boot.starter.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>${shardingsphere.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.version}</version>
</dependency>
</dependencies>
二.配置ShardingSphere
application.properties
# 单数据库分表,指定数据源名称
spring.shardingsphere.datasource.names=master0,master1
# 分表时一个实体类对应多张表,设置为true覆盖
spring.main.allow-bean-definition-overriding=true
# 配置第一个数据源,包括连接池、驱动类、数据库地址、用户名、密码
spring.shardingsphere.datasource.master0.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.master0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.master0.url=jdbc:mysql://localhost:3306/shardingsphere-demo?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.master0.username=root
spring.shardingsphere.datasource.master0.password=123456
# 配置第二个数据源,包括连接池、驱动类、数据库地址、用户名、密码
spring.shardingsphere.datasource.master1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.master1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.master1.url=jdbc:mysql://localhost:3306/shardingsphere-demo2?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.master1.username=root
spring.shardingsphere.datasource.master1.password=123456
# 指定数据库、数据表分布情况
spring.shardingsphere.sharding.tables.user.actual-data-nodes=master$->{0..1}.user
# 指定表的主键id,生成策略,SNOWFLAKE(雪花算法)
spring.shardingsphere.sharding.tables.user.key-generator.column=id
spring.shardingsphere.sharding.tables.user.key-generator.type=SNOWFLAKE
# 指定数据库分片策略,tenant_id取余后为0的分配到master0,为1的分配到master1
spring.shardingsphere.sharding.tables.user.database-strategy.inline.sharding-column=tenant_id
spring.shardingsphere.sharding.tables.user.database-strategy.inline.algorithm-expression=master$->{tenant_id % 2}
# 打开sql输出日志
spring.shardingsphere.props.sql.show=true
三.建库建表
建立上面配置的两个数据库,我这里分别是shardingsphere-demo和shardingsphere-demo2
分别在两个数据库下建立user表
CREATE TABLE `user` (
`id` bigint(20) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`tenant_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
四.编写业务代码
实体类
@Data
public class User {
@TableId
private Long id;
@TableField(value = "tenant_id")
private Integer tenantId;
private String name;
}
UserMapper
public interface UserMapper extends BaseMapper<User> {
}
UserService
public interface UserService extends IService<User> {
}
UserServiceImpl
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
五.测试
@SpringBootTest(classes = ShardingsphereDemoApplication.class)
public class UserServiceTest {
@Autowired
private UserService userService;
@Test
public void testUser() {
for (int i = 0; i < 10; i++) {
User user = new User();
user.setName("user_" + i);
Integer tenantId = 0;
if (i > 6) {
tenantId = 1;
}
user.setTenantId(tenantId);
userService.save(user);
}
}
}
shardingsphere-demo数据库下的user表
shardingsphere-demo2数据库下的user表
数据根据tenant_id分别分配到两个数据库的user表中了
再试一下查询,执行下面代码
List<User> list = userService.list();
可以看到,这里分别从两个数据库查询数据,完成分库效果
分库分表
分库实际上是粒度更大的数据分片,通过分库可以把数据库压力分配到多个数据库节点上,提高性能和可扩展性,但有时候对于单表数据过多的情况,跨多个库性能并不理想,或者我们并没有那么多数据库资源来增加数据库节点,那么,我们可以对每一个数据库再进行分表,尽可能达到最高的数据库利用率
下面进行分库、分表实践
在ShardingSphere中非常简单,只需增加几行配置
# 指定数据库分布情况,数据库里面表分布情况,如下user表,对应user_1,user_2两张表,数据库有master0、master1
spring.shardingsphere.sharding.tables.user.actual-data-nodes=master$->{0..1}.user_$->{1..2}
# 指定表分片策略,分片列为id字段,根据id字段的值进行分片,分片策略为id的值 % 2,余数为0的放入user_0表,为1的放入user_1表,为2的放入user_2表
spring.shardingsphere.sharding.tables.user.table-strategy.inline.sharding-column=id
spring.shardingsphere.sharding.tables.user.table-strategy.inline.algorithm-expression=user_$->{id % 2 + 1}
建表,分别在两个数据库建立user_1和user_2
CREATE TABLE `user_1` (
`id` bigint(20) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`tenant_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `user_2` (
`id` bigint(20) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`tenant_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
执行Test
@SpringBootTest(classes = ShardingsphereDemoApplication.class)
public class UserServiceTest {
@Autowired
private UserService userService;
@Test
public void testUser() {
for (int i = 0; i < 10; i++) {
User user = new User();
user.setName("user_" + i);
Integer tenantId = 0;
if (i > 6) {
tenantId = 1;
}
user.setTenantId(tenantId);
userService.save(user);
}
}
}
完成后,查看shardingsphere-demo数据库下两张表的数据
shardingsphere-demo2下的表数据
数据tenant_id为0的被分配到shardingsphere-demo数据库中,同时,根据id的余数再分配到两张表中,实现分库分表的效果
执行以下查询语句,测试结果是否正确
List<User> list = userService.list();
ShardingSphere分别从2个库4张表中查询数据
公共表(广播表)
公共表即每个数据库需要单独冗余一份完整数据的表,例如字典表
下面建一个dict字典表进行测试
建表语句
CREATE TABLE `dict` (
`id` bigint(20) NOT NULL,
`dict_name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
实体类
@Data
public class Dict {
@TableId
private Long id;
private String dictName;
}
其他的Service、Mapper请参照上面User表建立
增加配置
# 配置公共表
spring.shardingsphere.sharding.broadcast-tables=dict
spring.shardingsphere.sharding.tables.dict.key-generator.column=id
spring.shardingsphere.sharding.tables.dict.key-generator.type=SNOWFLAKE
测试
@SpringBootTest(classes = ShardingsphereDemoApplication.class)
public class UserServiceTest {
@Autowired
private DictService dictService;
@Test
public void testUser() {
Dict dict = new Dict();
dict.setDictName("字典值1");
dictService.save(dict);
}
}
查看数据库,可以看到两个库的dict表都插入了一条数据
水平分库的优缺点
优点
分库的优点有很多,例如提高系统性能和扩展性,使系统能够处理更大规模的数据和并发请求。数据库操作可以在多个节点上并行执行,从而加快数据处理速度。有助于提高系统的响应性和处理能力,特别是在大数据量和高并发的场景下。增强数据安全性、简化数据库管理、地理位置灵活性(可以根据实际需求将数据存储在不同的地理位置,以满足法律法规或业务需求)等
缺点
分库时需要考虑数据一致性、事务处理、跨库查询等问题,因此需要仔细设计和实施。同时,分库也增加了系统的复杂性和管理难度,需要综合考虑系统需求和资源成本,如果系统规模不大时,没必要进行分库,跨库操作具有包括网络开销在内的损耗,小数据量的情况下反而性能不如单库操作