目錄
介紹
springboot整合sharding-jdbc分庫分表
pom依賴
application.properties配置檔案
分庫分表配置
分庫分表配置
分庫規則
分表規則
controller
entity
mapper
mapper.xml
庫表結構
代碼測試
demo網盤連結:https://pan.baidu.com/s/1GRDY2WV35B2tDINNFsYZlw
提取碼:6rbl
介紹
sharding-jdbc是基于JDBC實作代理的可叫做用戶端分庫分表,MyCat是基于資料庫DB代理的可叫做服務端分庫分表。
springboot整合sharding-jdbc分庫分表
pom依賴
<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>
<groupId>com.sharding</groupId>
<artifactId>sharding</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<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>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--sharding-jdbc -->
<dependency>
<groupId>com.dangdang</groupId>
<artifactId>sharding-jdbc-core</artifactId>
<version>1.5.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.properties配置檔案
mybatis.config-locations=classpath:mybatis/mybatis-config.xml
#datasource
spring.devtools.remote.restart.enabled=false
#data source1
spring.datasource.test1.driverClassName=com.mysql.jdbc.Driver
spring.datasource.test1.jdbcUrl=jdbc:mysql://127.0.0.1:3306/test_0?serverTimezone=UTC
spring.datasource.test1.username=root
spring.datasource.test1.password=root
#data source2
spring.datasource.test2.driverClassName=com.mysql.jdbc.Driver
spring.datasource.test2.jdbcUrl=jdbc:mysql://127.0.0.1:3306/test_1?serverTimezone=UTC
spring.datasource.test2.username=root
spring.datasource.test2.password=root
分庫分表配置
配置多資料源、根據那個字段進行分庫、分表政策
/**
* 分庫分表配置 - 需要關聯查詢的表不建議進行分庫,但是可以同庫分表!
*
* @Description: 資料源配置和Mybatis配置和分庫分表規則
*/
@Configuration
@MapperScan(basePackages = "com.mapper", sqlSessionTemplateRef = "test1SqlSessionTemplate")
public class DataSourceConfig {
// >>>>>>> 配置多資料源 <<<<<<<<
/**
* 指定配置檔案中的配置資料源0,資料源的名稱最好要有一定的規則,友善配置分庫的計算規則
*/
@Bean(name="test_0")
@ConfigurationProperties(prefix = "spring.datasource.test1")
public DataSource test_0(){
return DataSourceBuilder.create().build();
}
/**
* 指定配置檔案中的配置資料源1,資料源的名稱最好要有一定的規則,友善配置分庫的計算規則
*/
@Bean(name="test_1")
@ConfigurationProperties(prefix = "spring.datasource.test2")
public DataSource test_1(){
return DataSourceBuilder.create().build();
}
/**
* 配置資料源規則,即将多個資料源交給sharding-jdbc管理,并且可以設定預設的資料源,
* 當表沒有配置分庫規則時會使用預設的資料源
*
* @param test_0 執行個體化資料庫名
* @param test_1 執行個體化資料庫名
* @return
*/
@Bean
public DataSourceRule dataSourceRule(@Qualifier("test_0") DataSource test_0,
@Qualifier("test_1") DataSource test_1){
Map<String, DataSource> dataSourceMap = new HashMap<>(); //設定分庫映射
dataSourceMap.put("test_0", test_0);
dataSourceMap.put("test_1", test_1);
return new DataSourceRule(dataSourceMap, "test_0"); //設定預設庫,兩個庫以上時必須設定預設庫。預設庫的資料源名稱必須是dataSourceMap的key之一
}
// >>>>>>> 配置分表政策 <<<<<<<<
/**
* 配置資料源政策和表政策,具體政策需要自己實作
* @param dataSourceRule
* @return
*/
@Bean
public ShardingRule shardingRule(DataSourceRule dataSourceRule){
//具體分庫分表政策,多個不同表可裝入List中
TableRule orderTableRule = TableRule.builder("user")// 去掉字尾的表名
.actualTables(Arrays.asList("user_0", "user_1"))// 水準拆分後相同屬性的所有表名
.tableShardingStrategy(new TableShardingStrategy("order_id", new ModuloTableShardingAlgorithm()))// 指定表分片政策根據那個字段(或者傳入的數值)進行取模算法
.dataSourceRule(dataSourceRule)
.build();
//綁定表政策,在查詢時會使用主表政策計算路由的資料源,是以需要約定綁定表政策的表的規則需要一緻,可以一定程度提高效率
List<BindingTableRule> bindingTableRules = new ArrayList<BindingTableRule>();
bindingTableRules.add(new BindingTableRule(Arrays.asList(orderTableRule)));
return ShardingRule.builder()
.dataSourceRule(dataSourceRule)
.tableRules(Arrays.asList(orderTableRule))
.bindingTableRules(bindingTableRules)
// 分庫-通過user_id(字段名稱可随意修改,和資料庫對應上即可)字段來進行取模算法
.databaseShardingStrategy(new DatabaseShardingStrategy("user_id", new ModuloDatabaseShardingAlgorithm()))
// 分表-通過order_id(字段名稱可随意修改,和資料庫對應上即可)字段來進行取模算法 (先分庫再分表)
.tableShardingStrategy(new TableShardingStrategy("order_id", new ModuloTableShardingAlgorithm()))
.build();
}
/**
* 建立sharding-jdbc的資料源DataSource,MybatisAutoConfiguration會使用此資料源
* @param shardingRule
* @return
* @throws SQLException
*/
@Bean(name="dataSource")
public DataSource shardingDataSource(ShardingRule shardingRule) throws SQLException {
return ShardingDataSourceFactory.createDataSource(shardingRule);
}
/**
* 需要手動配置事務管理器
* @param dataSource
* @return
*/
@Bean
public DataSourceTransactionManager transactitonManager(@Qualifier("dataSource") DataSource dataSource){
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = "test1SqlSessionFactory")
@Primary
public SqlSessionFactory testSqlSessionFactory(@Qualifier("dataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mybatis/*.xml"));
return bean.getObject();
}
@Bean(name = "test1SqlSessionTemplate")
@Primary
public SqlSessionTemplate testSqlSessionTemplate(@Qualifier("test1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
分庫規則
/**
* @Auther: Tinko
* @Date: 2018/12/19 16:31
* @Description: 分庫規則
*/
public class ModuloDatabaseShardingAlgorithm implements SingleKeyDatabaseShardingAlgorithm<Long> {
@Override
public String doEqualSharding(Collection<String> databaseNames, ShardingValue<Long> shardingValue) {
for (String each : databaseNames) {
if (each.endsWith(Long.parseLong(shardingValue.getValue().toString()) % 2 + "")) {
return each;
}
}
throw new IllegalArgumentException();
}
@Override
public Collection<String> doInSharding(Collection<String> databaseNames, ShardingValue<Long> shardingValue) {
Collection<String> result = new LinkedHashSet<>(databaseNames.size());
for (Long value : shardingValue.getValues()) {
for (String tableName : databaseNames) {
if (tableName.endsWith(value % 2 + "")) {
result.add(tableName);
}
}
}
return result;
}
@Override
public Collection<String> doBetweenSharding(Collection<String> databaseNames, ShardingValue<Long> shardingValue) {
Collection<String> result = new LinkedHashSet<>(databaseNames.size());
Range<Long> range = (Range<Long>) shardingValue.getValueRange();
for (Long i = range.lowerEndpoint(); i <= range.upperEndpoint(); i++) {
for (String each : databaseNames) {
if (each.endsWith(i % 2 + "")) {
result.add(each);
}
}
}
return result;
}
}
分表規則
/**
* @Auther: Tinko
* @Date: 2018/12/19 16:30
* @Description: 分表規則
*/
public class ModuloTableShardingAlgorithm implements SingleKeyTableShardingAlgorithm<Long> {
@Override
public String doEqualSharding(Collection<String> tableNames, ShardingValue<Long> shardingValue) {
for (String each : tableNames) {
if (each.endsWith(shardingValue.getValue() % 2 + "")) {
return each;
}
}
throw new IllegalArgumentException();
}
@Override
public Collection<String> doInSharding(Collection<String> tableNames, ShardingValue<Long> shardingValue) {
Collection<String> result = new LinkedHashSet<>(tableNames.size());
for (Long value : shardingValue.getValues()) {
for (String tableName : tableNames) {
if (tableName.endsWith(value % 2 + "")) {
result.add(tableName);
}
}
}
return result;
}
@Override
public Collection<String> doBetweenSharding(Collection<String> tableNames, ShardingValue<Long> shardingValue) {
Collection<String> result = new LinkedHashSet<>(tableNames.size());
Range<Long> range = (Range<Long>) shardingValue.getValueRange();
for (Long i = range.lowerEndpoint(); i <= range.upperEndpoint(); i++) {
for (String each : tableNames) {
if (each.endsWith(i % 2 + "")) {
result.add(each);
}
}
}
return result;
}
}
controller
@RestController
public class UserController {
@Autowired
private UserMapper userMapper;
/**
* 新增使用者資訊
* @param user
*/
@RequestMapping("/add")
public Object add(User user) throws SQLException{
System.out.println(user.toString());
return userMapper.insert(user);
}
/**
* 根據使用者id查詢使用者資訊
* @param id 使用者id
*/
@RequestMapping("/select")
public Object select(Integer id) throws SQLException{
return userMapper.select(id);
}
}
entity
@Data
public class User {
private Long id;
private Long order_id;
private Long user_id;
private String name;
private String address;
}
mapper
public interface UserMapper {
Long insert(User user);
List<Map<String, Object>> select(@Param("id")Integer id);
}
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.mapper.UserMapper" >
<insert id="insert" parameterType="com.entity.User" >
-- 表名不要寫字尾,字尾由sharding-jdbc根據政策生成
INSERT INTO user
(order_id,user_id,name,address)
VALUES
(#{order_id},#{user_id},#{name}, #{address})
</insert>
<select id="select" parameterType="map" resultType="map">
-- 表名不要寫字尾,字尾由sharding-jdbc根據政策生成
select * from user where id = #{id}
</select>
</mapper>
庫表結構
建立test_0、test_1庫,兩個庫分别導入以下user_0、user_1表結構
DROP TABLE IF EXISTS `user_0`;
CREATE TABLE `user_0` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`order_id` varchar(100) DEFAULT NULL COMMENT '用來分表政策',
`user_id` varchar(100) DEFAULT NULL COMMENT '用來分庫政策',
`name` varchar(100) DEFAULT NULL,
`address` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for user_1
-- ----------------------------
DROP TABLE IF EXISTS `user_1`;
CREATE TABLE `user_1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`order_id` varchar(100) DEFAULT NULL COMMENT '用來分表政策',
`user_id` varchar(100) DEFAULT NULL COMMENT '用來分庫政策',
`name` varchar(100) DEFAULT NULL,
`address` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8;
單庫多表測試
倆庫四個表:
1. 在多次調用/insert解決存儲資料庫,檢視資料庫會發現:test_0庫中的user_0、user_1表中的資料是均攤存放的
2. 調用/select接口傳入id,擷取到資料
多庫多表測試
以下查到的資料是存在test_1庫的user_1表中
分析庫表資料,不難發現所配置的存儲/查詢規律
test_0庫
test_1庫
結論:
根據上圖分析不難發現sharding-jdbc分庫分表規則,
首先根據指定字段進行分庫,落實庫索引後,第二步才是分表,
分庫規則:指定分庫字段 % 2 = 餘數 >>> 拿到餘數後,拼接庫名,如:餘數為0的話拼接test庫名就得到test_0。
分表規則:指定分表字段 % 2 = 餘數 >>> 拿到餘數後,拼接表名,如:餘數為1的話拼接user表名就得到user_1。
注:指定分庫、分表的字段和取模數值可在以上的(分庫分表規則)标題中配置。
limit 分頁操作
官網:歸并引擎 :: ShardingSphere