java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringBoot集成Sharding-JDBC分库分表

SpringBoot集成Sharding-JDBC实现分库分表方式

作者:DanceDonkey

这篇文章主要介绍了SpringBoot集成Sharding-JDBC实现分库分表方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

一、环境搭建

1.创建一个springboot项目,引入以下依赖。

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid-spring-boot-starter</artifactId>
			<version>1.1.20</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>
		<dependency>
			<groupId>org.apache.shardingsphere</groupId>
			<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
			<version>4.0.0-RC1</version>
		</dependency>
		<dependency>
			<groupId>com.baomidou</groupId>
			<artifactId>mybatis-plus-boot-starter</artifactId>
			<version>3.0.5</version>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
		</dependency>
	</dependencies>

2.创建一个数据库user和两张表user_1,user_2

CREATE DATABASE `user`;

CREATE TABLE `user_1` (
  `id` bigint(30) NOT NULL,
  `username` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  `gender` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8


CREATE TABLE `user_2` (
  `id` bigint(30) NOT NULL,
  `username` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  `gender` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

3.分别创建user表对应的实体类和mapper

实体类代码

@Data
public class User {

    private Long id;

    private String username;

    private String password;
    
    private String gender;

}

mapper代码

public interface UserMapper extends BaseMapper<User>{

}

结构图:

二、实现水平分表

需求:现在有两个user表,一个是user_1,一个是user_2,当id为偶数的时候向user_1表中插入数据,当id为奇数的时候向user_2表中插入数据,实现水平分表。

1.配置application.properties

#指定当前应用的所有数据源标识(由于后期可能会涉及到多个数据源,或读写分离等,这里要为每个数据源
# 起一个标识名,然后为每个数据源具体配置)
spring.shardingsphere.datasource.names=d1
#配置d1这个数据源,由于这里是水平分表,所以只需要一个数据源即可 其中d1代表该数据源的一个标识
spring.shardingsphere.datasource.d1.type=com.alibaba.druid.pool.DruidDataSource
#指定链接驱动
spring.shardingsphere.datasource.d1.driver-class-name=com.mysql.cj.jdbc.Driver
#指定链接url
spring.shardingsphere.datasource.d1.url=jdbc:mysql://localhost:3308/user?useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
#指定链接用户名
spring.shardingsphere.datasource.d1.username=root
#指定链接密码
spring.shardingsphere.datasource.d1.password=root

#由于是水平分表,所以会涉及到多张相同的表,这里指定这些表的分布情况:在哪个数据源上,以及一共有几张表
#指定在d1数据源,且有user_1和user_2两张表
#$->{1..2}该表达式是与前面的user_相拼接的,不能乱写,例如我们现在的两张表名是user_1和user_2,那这里就是user_$->{1..2}
#如果我们分布了3张表 user_5,user_6,user_7,那这里就是user_$->{5..6..7}
spring.shardingsphere.sharding.tables.user.actual-data-nodes=d1.user_$->{1..2}

# 指定 user 表里面主键id 以及id的生成策略 SNOWFLAKE:表示用雪花算法生成该id
spring.shardingsphere.sharding.tables.user.key-generator.column=id
spring.shardingsphere.sharding.tables.user.key-generator.type=SNOWFLAKE

# 指定分片策略 约定 id 值偶数添加到 user_1 表,如果 id 是奇数添加到 user_2表
#指定要根据哪个字段进行分表,这里根据id进行分表
spring.shardingsphere.sharding.tables.user.table-strategy.inline.sharding-column=id
#执行分表的规则:注意这里是$->{id% 2 + 1},由于偶数%2的结果为0,但是我们并没有user_0这样表
#所以我们要在取模的结果上+1 这样就实现了如果是偶数那么取模的结果就是user_1,如果是奇数就是user_2
spring.shardingsphere.sharding.tables.user.table-strategy.inline.algorithm-expression=user_$->{id% 2 + 1}

#开启sql 输出日志
spring.shardingsphere.props.sql.show=true
# 由于一个实体类对应两张表,所以会产生覆盖操作,加上这个配置解决覆盖问题
spring.main.allow-bean-definition-overriding=true

2.编写测试代码

	@Test
	void testAddUser()   {
		for (int i = 0;i < 6;i++){
			User user = new User();
			user.setGender("0");
			user.setPassword(UUID.randomUUID().toString().substring(0,5));
			user.setUsername("-->" + i);
			userMapper.insert(user);
		}
	}

3.日志查看:

可以看到当user_id的值为偶数的时候,是向user_1表中插入的。

再看当user_id的值为奇数的时候,该条数据插入了user_2这个表。

三、实现水平分库

需求:现在有两个user库,一个是user_db1,一个是user_db2,每个user库中都有两张相同的表,user_1,user_2,当user对象的gender属性值为1的时候向user_db1库中插入,当user对象的gender属性值为0的时候向user_db2库中插入,这是分库的规则,分表的规则是,当id为偶数的时候向user_1表中插入数据,当id为奇数的时候向user_2表中插入数据。(建表语句和上面是相同的)

结构如下:

2.配置application.properties

#指定当前应用的所有数据源标识(由于后期可能会涉及到多个数据源,或读写分离等,这里要为每个数据源
# 起一个标识名,然后为每个数据源具体配置)
spring.shardingsphere.datasource.names=d1,d2
#配置d1这个数据源,由于这里是水平分表,所以只需要一个数据源即可 其中d1代表该数据源的一个标识
spring.shardingsphere.datasource.d1.type=com.alibaba.druid.pool.DruidDataSource
#指定链接驱动
spring.shardingsphere.datasource.d1.driver-class-name=com.mysql.cj.jdbc.Driver
#指定链接url
spring.shardingsphere.datasource.d1.url=jdbc:mysql://localhost:3308/user_db1?useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
#指定链接用户名
spring.shardingsphere.datasource.d1.username=root
#指定链接密码
spring.shardingsphere.datasource.d1.password=root

#由于是两个数据库,所以要配置两个数据源
#配置d2数据源
spring.shardingsphere.datasource.d2.type=com.alibaba.druid.pool.DruidDataSource
#指定链接驱动
spring.shardingsphere.datasource.d2.driver-class-name=com.mysql.cj.jdbc.Driver
#指定链接url
spring.shardingsphere.datasource.d2.url=jdbc:mysql://localhost:3308/user_db2?useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
#指定链接用户名
spring.shardingsphere.datasource.d2.username=root
#指定链接密码
spring.shardingsphere.datasource.d2.password=root


#指定数据库和表的分布情况
#指定数据库分布情况,数据库里面表分布情况
#d$->{1..2}.user_$->{1..2} 表示在d1,d2数据源上都有user_1和user_2两张表
spring.shardingsphere.sharding.tables.user.actual-data-nodes=d$->{1..2}.user_$->{1..2}

# 指定 user 表里面主键id 以及id的生成策略 SNOWFLAKE:表示用雪花算法生成该id
spring.shardingsphere.sharding.tables.user.key-generator.column=id
spring.shardingsphere.sharding.tables.user.key-generator.type=SNOWFLAKE

# 指定分片策略 约定 id 值偶数添加到 user_1 表,如果 id 是奇数添加到 user_2表
#指定要根据哪个字段进行分表,这里根据id进行分表
spring.shardingsphere.sharding.tables.user.table-strategy.inline.sharding-column=id
#执行分表的规则:注意这里是$->{id% 2 + 1},由于偶数%2的结果为0,但是我们并没有user_0这样表
#所以我们要在取模的结果上+1 这样就实现了如果是偶数那么取模的结果就是user_1,如果是奇数就是user_2
spring.shardingsphere.sharding.tables.user.table-strategy.inline.algorithm-expression=user_$->{id% 2 + 1}

#============================================================================================
#以上指定了分表策略,下面指定分库策略,也就是gender为0则向user_db1中插入,为1则向user_db2中插入
spring.shardingsphere.sharding.tables.user.database-strategy.inline..sharding-column=gender
#如果gender为0 则表达式{gender=='0'?1:2}的结果就是1,则d$->{gender=='0'?1:2} = d1,就会向d1数据源也就是user_db1库中添加
#如果gender为1 则表达式{gender=='0'?1:2}的结果就是2,则d$->{gender=='0'?1:2} = d2,就会向d1数据源也就是user_db2库中添加
spring.shardingsphere.sharding.tables.user.database-strategy.inline.algorithm-expression=d$->{gender=='0'?1:2}




#开启sql 输出日志
spring.shardingsphere.props.sql.show=true
# 由于一个实体类对应两张表,所以会产生覆盖操作,加上这个配置解决覆盖问题
spring.main.allow-bean-definition-overriding=true

2.编写测试代码

	@Test
	void testAddUser()   {
		for (int i = 0;i < 10;i++){
			User user = new User();
			user.setPassword(UUID.randomUUID().toString().substring(0,5));
			user.setUsername("-->" + i);
			if (i % 2 == 0) user.setGender("0");
			else user.setGender("1");
			userMapper.insert(user);
		}
	}

3.数据库查看

可以看到:gender为0,且id为偶数插入到了user_db1库中的,user_1表。

可以看到:gender为0,且id为奇数插入到了user_db1库中的,user_2表。

可以看到:gender为1,且id为偶数插入到了user_db2库中的,user_1表。

可以看到:gender为1,且id为奇数插入到了user_db2库中的,user_2表。

四、公共表的配置

有些表的数据量不大,需要在每个数据库中都有,这时需要配置公共表。

向user_db1,和user_db2两个数据库都创建一个t_dict表

CREATE table t_dicit(
	id BIGINT(30) PRIMARY key,
	`dstatus` VARCHAR(255) not null,
	`description` VARCHAR(255) not null
)

status和desc是mysql的两个关键字,表的字段名尽量避开这些关键字,否则会发生运行时异常。

1.配置application.properties

#指定当前应用的所有数据源标识(由于后期可能会涉及到多个数据源,或读写分离等,这里要为每个数据源
# 起一个标识名,然后为每个数据源具体配置)
spring.shardingsphere.datasource.names=d1,d2
#配置d1这个数据源,由于这里是水平分表,所以只需要一个数据源即可 其中d1代表该数据源的一个标识
spring.shardingsphere.datasource.d1.type=com.alibaba.druid.pool.DruidDataSource
#指定链接驱动
spring.shardingsphere.datasource.d1.driver-class-name=com.mysql.cj.jdbc.Driver
#指定链接url
spring.shardingsphere.datasource.d1.url=jdbc:mysql://localhost:3308/user_db1?useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
#指定链接用户名
spring.shardingsphere.datasource.d1.username=root
#指定链接密码
spring.shardingsphere.datasource.d1.password=root

#由于是两个数据库,所以要配置两个数据源
#配置d2数据源
spring.shardingsphere.datasource.d2.type=com.alibaba.druid.pool.DruidDataSource
#指定链接驱动
spring.shardingsphere.datasource.d2.driver-class-name=com.mysql.cj.jdbc.Driver
#指定链接url
spring.shardingsphere.datasource.d2.url=jdbc:mysql://localhost:3308/user_db2?useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
#指定链接用户名
spring.shardingsphere.datasource.d2.username=root
#指定链接密码
spring.shardingsphere.datasource.d2.password=root


#指定数据库和表的分布情况
#指定数据库分布情况,数据库里面表分布情况
#d$->{1..2}.user_$->{1..2} 表示在d1,d2数据源上都有user_1和user_2两张表
spring.shardingsphere.sharding.tables.user.actual-data-nodes=d$->{1..2}.user_$->{1..2}

# 指定 user 表里面主键id 以及id的生成策略 SNOWFLAKE:表示用雪花算法生成该id
spring.shardingsphere.sharding.tables.user.key-generator.column=id
spring.shardingsphere.sharding.tables.user.key-generator.type=SNOWFLAKE

# 指定分片策略 约定 id 值偶数添加到 user_1 表,如果 id 是奇数添加到 user_2表
#指定要根据哪个字段进行分表,这里根据id进行分表
spring.shardingsphere.sharding.tables.user.table-strategy.inline.sharding-column=id
#执行分表的规则:注意这里是$->{id% 2 + 1},由于偶数%2的结果为0,但是我们并没有user_0这样表
#所以我们要在取模的结果上+1 这样就实现了如果是偶数那么取模的结果就是user_1,如果是奇数就是user_2
spring.shardingsphere.sharding.tables.user.table-strategy.inline.algorithm-expression=user_$->{id% 2 + 1}

#============================================================================================
#以上指定了分表策略,下面指定分库策略,也就是gender为0则向user_db1中插入,为1则向user_db2中插入
spring.shardingsphere.sharding.tables.user.database-strategy.inline..sharding-column=gender
#如果gender为0 则表达式{gender=='0'?1:2}的结果就是1,则d$->{gender=='0'?1:2} = d1,就会向d1数据源也就是user_db1库中添加
#如果gender为1 则表达式{gender=='0'?1:2}的结果就是2,则d$->{gender=='0'?1:2} = d2,就会向d1数据源也就是user_db2库中添加
spring.shardingsphere.sharding.tables.user.database-strategy.inline.algorithm-expression=d$->{gender=='0'?1:2}


#============================================================================================
#配置公共表 在向t_dicit表插入数据时 这些默认的数据源(d1,d2)的t_dicit表都会插入该数据
spring.shardingsphere.sharding.broadcast-tables=t_dicit
spring.shardingsphere.sharding.tables.t_dicit.key-generator.column=id
spring.shardingsphere.sharding.tables.t_dicit.key-generator.type=SNOWFLAKE

#开启sql 输出日志
spring.shardingsphere.props.sql.show=true
# 由于一个实体类对应两张表,所以会产生覆盖操作,加上这个配置解决覆盖问题
spring.main.allow-bean-definition-overriding=true

2.编写实体类和mapper

@TableName("t_dicit")
@Data
public class Dict {

    @TableId
    private Long id;

    private String dstatus;

    private String description;

}
public interface DictMapper extends BaseMapper<Dict> {

}

3.编写测试程序

	@Test
	public void testDict(){
		Dict dict = new Dict();
		dict.setDescription("启用状态");
		dict.setDstatus("A");
		dictMapper.insert(dict);
	}

4.查看日志发现分别向两个数据源发送了sql

5.查看表

两个库的t_dicit表都有了该数据。

同样如果是删除公共表的数据也是同时将两个数据库中的记录删除。

	@Test
	public void testDictDel(){
		dictMapper.deleteById(1270356973266165762L);
	}

运行日志:

两个库中的数据都被删除。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文