springboot+mybatis+sharding-jdbc整合分库分表实战

接上一张分库分表分析。项目代码地址:https://gitee.com/wuhan1/sharding-jdbc.git
1.引入jar包

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.5.RELEASE</version>
		<relativePath />
	</parent>


		<!-- springboot -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<!-- 添加 MySQL -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>

		<!-- Mybatis -->
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>1.2.0</version>
		</dependency>

		<!-- druid -->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid</artifactId>
			<version>1.1.9</version>
		</dependency>

		<!-- sharding-jdbc -->
		<dependency>
			<groupId>io.shardingsphere</groupId>
			<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
			<version>3.1.0</version>
		</dependency>

2.新建表t_user_1和t_user_2,表结构完全一样



3.新建工程sharding-jdbc,结构

mapper接口

public interface TUserMapper {

	int insert(TUser user);
}

mapper接口对应的xml

<?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.xqc.dao.TUserMapper" >

    <insert id="insert" parameterType="TUser" >
        INSERT INTO
        t_user
        (user_name,age,remark)
        VALUES
        (#{userName}, #{age}, #{remark})
    </insert>

</mapper>

service接口

public interface TUserService {
	boolean  insert(TUser user);
}

service接口实现类

@Service
public class TUserServiceImpl implements TUserService{

	@Autowired
	private TUserMapper tUserMapper;
	
	@Override
	public boolean insert(TUser user) {
		return this.tUserMapper.insert(user) == 1;
	}

}

TUser实体类

public class TUser implements Serializable {

	private static final long serialVersionUID = 1L;

	private Integer id;
	private String userName;
	private Integer age;
	private String remark;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	public String getRemark() {
		return remark;
	}

	public void setRemark(String remark) {
		this.remark = remark;
	}

}

Controller类

@RestController
public class TUserController {

	@Autowired
	private TUserService tUserService;
	
	@GetMapping("/add")
	public String add(){
		TUser user = new TUser();
		user.setUserName("张三");
		user.setAge(20);
		user.setRemark("...");
		boolean result = this.tUserService.insert(user);
		if(result){
			return "success";
		}
		return "fail";
	}
}

application.properties配置,本文采用的是sharding-jdbc-spring-boot-starter的3.1.0版本的,所以配置文件需以sharding.jdbc.开头


水平分表不分库配置


#spring.main.allow-bean-definition-overriding=true
#配置数据源的详细信息,多个逗号分开
sharding.jdbc.datasource.names=m1
# 数据库连接池
sharding.jdbc.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource
#数据库驱动类名
sharding.jdbc.datasource.m1.driver-class-name=com.mysql.jdbc.Driver
# 数据库 URL 连接
sharding.jdbc.datasource.m1.url=jdbc:mysql://localhost:3306/sharding-jdbc?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC
# 数据库用户名
sharding.jdbc.datasource.m1.username=root
# 数据库密码
sharding.jdbc.datasource.m1.password=123456


# 指定t_user表的分布情况,配置在哪个数据库,表名称是什么  m1.t_user_1  m1.t_user_2
sharding.jdbc.config.sharding.tables.t_user.actual-data-nodes=m1.t_user_$->{1..2}
#指定t_user表中主键的生成策略  SNOWFLAKE:雪花算法,随机生成主键Id
sharding.jdbc.config.sharding.tables.t_user.key-generator-column-name=id
sharding.jdbc.config.sharding.tables.t_user.key-generator-type=SNOWFLAKE

# 指定分片的策略 约定id值 : 偶数--》t_user_1  奇数-->t_user_2
sharding.jdbc.config.sharding.tables.t_user.table-strategy.inline.sharding-column=id
sharding.jdbc.config.sharding.tables.t_user.table-strategy.inline.algorithm-expression=t_user_$->{id%2 +1}

#打开sql的输出日志

sharding.jdbc.config.sharding.props.sql.show=true

#实体类扫描配置,这样在mapper的xml中可以直接使用实体类名,不用写包路径
mybatis.type-aliases-package=com.xqc.mode
#驼峰转换
mybatis.configuration.mapUnderscoreToCamelCase=true
#处理日期
spring.jackson.date-format=yyyy-MM-dd HH:mm
spring.jackson.time-zone=GMT+8
#xml文件扫描
mybatis.mapperLocations=classpath:mapper/*.xml

启动类配置

@SpringBootApplication
@MapperScan("com.xqc.dao")//mapper接口扫描
public class App {
	
    public static void main( String[] args ){
      	SpringApplication.run(App.class, args);
    }
    
}

4.浏览器多次访问http://localhost:8080/add查看数据库数据
主键ID尾数奇数的存在t_user_2表中

主键ID尾数偶数的存在t_user_1表中

上面数据存储采用的是自带的inline算法,我们也可以根据自己的需求,自定义分片算法

# 自定义分表算法
sharding.jdbc.config.sharding.tables.t_user.table-strategy.standard.sharding-column=id
sharding.jdbc.config.sharding.tables.t_user.table-strategy.standard.precise-algorithm-class-name=com.xqc.algorithm.MyPreciseShardingAlgorithm

实现接口PreciseShardingAlgorithm

/**
* @dateTime 创建时间:2020年8月19日 上午10:19:06
* @version V1.0.0
* 类说明 自定义分表算法,尾数0-5存表t_user_1,6-9存表t_user_2
*/
public class MyPreciseShardingAlgorithm implements PreciseShardingAlgorithm<Long>{

	private static final List<String> PARAM_LIST = Arrays.asList("0","1","2","3","4","5");
	
	@Override
	public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Long> shardingValue) {
		//availableTargetNames拆分出来的物理表【t_user_1,t_user_2】,shardingValue分片字段的值
		for (String availableTargetName : availableTargetNames) {
			String value = "2" ;
			//尾数0-5存表t_user_1,6-9存表t_user_2
			 String colValue = shardingValue.getValue().toString();
			 String subLast = shardingValue.getValue().toString().substring(colValue.length()-1, colValue.length());
			 if(PARAM_LIST.contains(subLast)){
				 value = "1";
			 }
			if(availableTargetName.endsWith(value)){
				return availableTargetName;
			}
		}
		throw new IllegalArgumentException();
	}

}

再看数据库数据

分片算法介绍
通过分片算法将数据分片,支持通过=、BETWEEN和IN分片。分片算法需要应用方开发者自行实现,可实现的灵活度非常高。

精确分片算法
对应PreciseShardingAlgorithm,用于处理使用单一键作为分片键的=与IN进行分片的场景。需要配合StandardShardingStrategy使用。
范围分片算法
对应RangeShardingAlgorithm,用于处理使用单一键作为分片键的BETWEEN AND进行分片的场景。需要配合StandardShardingStrategy使用。
复合分片算法
对应ComplexKeysShardingAlgorithm,用于处理使用多键作为分片键进行分片的场景,包含多个分片键的逻辑较复杂,需要应用开发者自行处理其中的复杂度。需要配合ComplexShardingStrategy使用。
Hint分片算法
对应HintShardingAlgorithm,用于处理使用Hint行分片的场景。需要配合HintShardingStrategy使用。

水平分库分表配置:不同的数据库,相同的表结构,每个库都有多份

#分库不分表的情况

#spring.main.allow-bean-definition-overriding=true
#配置数据源的详细信息,多个逗号分开
sharding.jdbc.datasource.names=m1,m2

#数据库1
# 数据库连接池
sharding.jdbc.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource
#数据库驱动类名
sharding.jdbc.datasource.m1.driver-class-name=com.mysql.jdbc.Driver
# 数据库 URL 连接
sharding.jdbc.datasource.m1.url=jdbc:mysql://localhost:3306/sharding-jdbc?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC
# 数据库用户名
sharding.jdbc.datasource.m1.username=root
# 数据库密码
sharding.jdbc.datasource.m1.password=123456

#数据库2
# 数据库连接池
sharding.jdbc.datasource.m2.type=com.alibaba.druid.pool.DruidDataSource
#数据库驱动类名
sharding.jdbc.datasource.m2.driver-class-name=com.mysql.jdbc.Driver
# 数据库 URL 连接
sharding.jdbc.datasource.m2.url=jdbc:mysql://localhost:3306/sharding-jdbc_02?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC
# 数据库用户名
sharding.jdbc.datasource.m2.username=root
# 数据库密码
sharding.jdbc.datasource.m2.password=123456

# 指定分库的策略 约定id值 : 偶数--》m1  奇数-->m2
sharding.jdbc.config.sharding.tables.t_user.database-strategy.inline.sharding-column=id
sharding.jdbc.config.sharding.tables.t_user.database-strategy.inline.algorithm-expression=m$->{id%2 +1}

# 指定t_user表的分布情况,配置在哪个数据库,表名称是什么  m1.t_user_1  m1.t_user_2
sharding.jdbc.config.sharding.tables.t_user.actual-data-nodes=m$->{1..2}.t_user_$->{1..2}
#指定t_user表中主键的生成策略  SNOWFLAKE:雪花算法,随机生成主键Id
sharding.jdbc.config.sharding.tables.t_user.key-generator-column-name=id
sharding.jdbc.config.sharding.tables.t_user.key-generator-type=SNOWFLAKE

#指定表的分表算法
sharding.jdbc.config.sharding.tables.t_user.table-strategy.inline.sharding-column=pid
sharding.jdbc.config.sharding.tables.t_user.table-strategy.inline.algorithm-expression=t_user_$->{pid%2 +1}

#打开sql的输出日志
sharding.jdbc.config.sharding.props.sql.show=true

#实体类扫描配置,这样在mapper的xml中可以直接使用实体类名,不用写包路径
mybatis.type-aliases-package=com.xqc.mode
#驼峰转换
mybatis.configuration.mapUnderscoreToCamelCase=true
#处理日期
spring.jackson.date-format=yyyy-MM-dd HH:mm
spring.jackson.time-zone=GMT+8
#xml文件扫描
mybatis.mapperLocations=classpath:mapper/*.xml

水平分库不分表配置:相同的表结构,放在多个数据库中,根据分库算法存放数据,访问地址http://localhost:8080/role/add

#分库不分表的情况

#spring.main.allow-bean-definition-overriding=true
#配置数据源的详细信息,多个逗号分开
sharding.jdbc.datasource.names=m1,m2

#数据库1
# 数据库连接池
sharding.jdbc.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource
#数据库驱动类名
sharding.jdbc.datasource.m1.driver-class-name=com.mysql.jdbc.Driver
# 数据库 URL 连接
sharding.jdbc.datasource.m1.url=jdbc:mysql://localhost:3306/sharding-jdbc?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC
# 数据库用户名
sharding.jdbc.datasource.m1.username=root
# 数据库密码
sharding.jdbc.datasource.m1.password=123456

#数据库2
# 数据库连接池
sharding.jdbc.datasource.m2.type=com.alibaba.druid.pool.DruidDataSource
#数据库驱动类名
sharding.jdbc.datasource.m2.driver-class-name=com.mysql.jdbc.Driver
# 数据库 URL 连接
sharding.jdbc.datasource.m2.url=jdbc:mysql://localhost:3306/sharding-jdbc_02?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC
# 数据库用户名
sharding.jdbc.datasource.m2.username=root
# 数据库密码
sharding.jdbc.datasource.m2.password=123456


# 指定t_user表的分布情况,配置在哪个数据库,表名称是什么  m1.t_user_1  m1.t_user_2
#sharding.jdbc.config.sharding.tables.t_role.actual-data-nodes=m1.t_user_$->{1..2}
#指定t_user表中主键的生成策略  SNOWFLAKE:雪花算法,随机生成主键Id
sharding.jdbc.config.sharding.tables.t_role.key-generator-column-name=id
sharding.jdbc.config.sharding.tables.t_role.key-generator-type=SNOWFLAKE

# 指定分片的策略 约定id值 : 偶数--》m1  奇数-->m2

# 自定义分库算法
sharding.jdbc.config.sharding.tables.t_role.database-strategy.inline.sharding-column=id
sharding.jdbc.config.sharding.tables.t_role.database-strategy.inline.algorithm-expression=m$->{id%2 +1}

#打开sql的输出日志

sharding.jdbc.config.sharding.props.sql.show=true

#实体类扫描配置,这样在mapper的xml中可以直接使用实体类名,不用写包路径
mybatis.type-aliases-package=com.xqc.mode
#驼峰转换
mybatis.configuration.mapUnderscoreToCamelCase=true
#处理日期
spring.jackson.date-format=yyyy-MM-dd HH:mm
spring.jackson.time-zone=GMT+8
#xml文件扫描
mybatis.mapperLocations=classpath:mapper/*.xml



sharding-jdbc执行流程

SQL路由:根据解析上下文匹配用户配置的分片策略,并生成最终的路由路径
SQL改写:将SQL改写为在真实数据库中可以正确执行的语句。

猜你喜欢

转载自blog.csdn.net/dhj199181/article/details/108073182