使用Sharding-JDBC對數(shù)據(jù)進(jìn)行分片處理詳解
前言
Sharding-JDBC是ShardingSphere的第一個產(chǎn)品,也是ShardingSphere的前身。
它定位為輕量級Java框架,在Java的JDBC層提供的額外服務(wù)。它使用客戶端直連數(shù)據(jù)庫,以jar包形式提供服務(wù),無需額外部署和依賴,可理解為增強(qiáng)版的JDBC驅(qū)動,完全兼容JDBC和各種ORM框架。
- 適用于任何基于Java的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。
- 基于任何第三方的數(shù)據(jù)庫連接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP等支持任意實現(xiàn)JDBC規(guī)范的數(shù)據(jù)庫。
- 目前支持MySQL,Oracle,SQLServer和PostgreSQL。
Sharding-JDBC的使用需要我們對項目進(jìn)行一些調(diào)整:結(jié)構(gòu)如下

這里使用的是springBoot項目改造
一、加入依賴
<!-- 這里使用了druid連接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.9</version>
</dependency>
<!-- sharding-jdbc 包 -->
<dependency>
<groupId>com.dangdang</groupId>
<artifactId>sharding-jdbc-core</artifactId>
<version>1.5.4</version>
</dependency>
<!-- 這里使用了雪花算法生成組建,這個算法的實現(xiàn)的自己寫的代碼,各位客關(guān)老爺可以修改為自己的id生成策略 -->
<dependency>
<groupId>org.kcsm.common</groupId>
<artifactId>kcsm-idgenerator</artifactId>
<version>3.0.1</version>
</dependency>
二、修改application.yml配置文件
#啟動接口
server:
port: 30009
spring:
jpa:
database: mysql
show-sql: true
hibernate:
# 修改不自動更新表
ddl-auto: none
#數(shù)據(jù)源0定義,這里只是用了一個數(shù)據(jù)源,各位客官可以根據(jù)自己的需求定義多個數(shù)據(jù)源
database0:
databaseName: database0
url: jdbc:mysql://kcsm-pre.mysql.rds.aliyuncs.com:3306/dstest?characterEncoding=utf8&useUnicode=true&useSSL=false&serverTimezone=Hongkong
username: root
password: kcsm@111
driverClassName: com.mysql.jdbc.Driver
三、數(shù)據(jù)源定義
package com.lzx.code.codedemo.config;
import com.alibaba.druid.pool.DruidDataSource;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
/**
* 描述:數(shù)據(jù)源0定義
*
* @Auther: lzx
* @Date: 2019/9/9 15:19
*/
@Data
@ConfigurationProperties(prefix = "database0")
@Component
public class Database0Config {
private String url;
private String username;
private String password;
private String driverClassName;
private String databaseName;
public DataSource createDataSource() {
DruidDataSource result = new DruidDataSource();
result.setDriverClassName(getDriverClassName());
result.setUrl(getUrl());
result.setUsername(getUsername());
result.setPassword(getPassword());
return result;
}
}
四、數(shù)據(jù)源分配算法實現(xiàn)
package com.lzx.code.codedemo.config;
import com.dangdang.ddframe.rdb.sharding.api.ShardingValue;
import com.dangdang.ddframe.rdb.sharding.api.strategy.database.SingleKeyDatabaseShardingAlgorithm;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* 描述:數(shù)據(jù)源分配算法
*
* 這里我們只用了一個數(shù)據(jù)源,所以所有的都只返回了數(shù)據(jù)源0
*
* @Auther: lzx
* @Date: 2019/9/9 15:27
*/
@Component
public class DatabaseShardingAlgorithm implements SingleKeyDatabaseShardingAlgorithm {
@Autowired
private Database0Config database0Config;
/**
* = 條件時候返回的數(shù)據(jù)源
* @param collection
* @param shardingValue
* @return
*/
@Override
public String doEqualSharding(Collection collection, ShardingValue shardingValue) {
return database0Config.getDatabaseName();
}
/**
* IN 條件返回的數(shù)據(jù)源
* @param collection
* @param shardingValue
* @return
*/
@Override
public Collection<String> doInSharding(Collection collection, ShardingValue shardingValue) {
List<String> result = new ArrayList<String>();
result.add(database0Config.getDatabaseName());
return result;
}
/**
* BETWEEN 條件放回的數(shù)據(jù)源
* @param collection
* @param shardingValue
* @return
*/
@Override
public Collection<String> doBetweenSharding(Collection collection, ShardingValue shardingValue) {
List<String> result = new ArrayList<String>();
result.add(database0Config.getDatabaseName());
return result;
}
}
五、數(shù)據(jù)表分配算法
package com.lzx.code.codedemo.config;
import com.dangdang.ddframe.rdb.sharding.api.ShardingValue;
import com.dangdang.ddframe.rdb.sharding.api.strategy.table.SingleKeyTableShardingAlgorithm;
import com.google.common.collect.Range;
import org.springframework.stereotype.Component;
import java.util.Collection;
import java.util.LinkedHashSet;
/**
* 描述: 數(shù)據(jù)表分配算法的實現(xiàn)
*
* @Auther: lzx
* @Date: 2019/9/9 16:19
*/
@Component
public class TableShardingAlgorithm implements SingleKeyTableShardingAlgorithm<Long> {
/**
* = 條件時候返回的數(shù)據(jù)源
* @param collection
* @param shardingValue
* @return
*/
@Override
public String doEqualSharding(Collection<String> collection, ShardingValue<Long> shardingValue) {
for (String eaach:collection) {
Long value = shardingValue.getValue();
value = value >> 22;
if(eaach.endsWith(value%10+"")){
return eaach;
}
}
throw new IllegalArgumentException();
}
/**
* IN 條件返回的數(shù)據(jù)源
* @param tableNames
* @param shardingValue
* @return
*/
@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) {
value = value >> 22;
if (tableName.endsWith(value % 10 + "")) {
result.add(tableName);
}
}
}
return result;
}
/**
* BETWEEN 條件放回的數(shù)據(jù)源
* @param tableNames
* @param shardingValue
* @return
*/
@Override
public Collection<String> doBetweenSharding(Collection<String> tableNames, ShardingValue<Long> shardingValue) {
Collection<String> result = new LinkedHashSet<>(tableNames.size());
Range<Long> range = shardingValue.getValueRange();
for (Long i = range.lowerEndpoint(); i <= range.upperEndpoint(); i++) {
for (String each : tableNames) {
Long value = i >> 22;
if (each.endsWith(i % 10 + "")) {
result.add(each);
}
}
}
return result;
}
}
六、數(shù)據(jù)源配置
package com.lzx.code.codedemo.config;
import com.dangdang.ddframe.rdb.sharding.api.ShardingDataSourceFactory;
import com.dangdang.ddframe.rdb.sharding.api.rule.DataSourceRule;
import com.dangdang.ddframe.rdb.sharding.api.rule.ShardingRule;
import com.dangdang.ddframe.rdb.sharding.api.rule.TableRule;
import com.dangdang.ddframe.rdb.sharding.api.strategy.database.DatabaseShardingStrategy;
import com.dangdang.ddframe.rdb.sharding.api.strategy.table.TableShardingStrategy;
import com.dangdang.ddframe.rdb.sharding.keygen.DefaultKeyGenerator;
import com.dangdang.ddframe.rdb.sharding.keygen.KeyGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* 描述:數(shù)據(jù)源配置
*
* @Auther: lzx
* @Date: 2019/9/9 15:21
*/
@Configuration
public class DataSourceConfig {
@Autowired
private Database0Config database0Config;
@Autowired
private DatabaseShardingAlgorithm databaseShardingAlgorithm;
@Autowired
private TableShardingAlgorithm tableShardingAlgorithm;
@Bean
public DataSource getDataSource() throws SQLException {
return buildDataSource();
}
private DataSource buildDataSource() throws SQLException {
//分庫設(shè)置
Map<String, DataSource> dataSourceMap = new HashMap<>(2);
//添加兩個數(shù)據(jù)庫database0和database1
dataSourceMap.put(database0Config.getDatabaseName(), database0Config.createDataSource());
//設(shè)置默認(rèn)數(shù)據(jù)庫
DataSourceRule dataSourceRule = new DataSourceRule(dataSourceMap, database0Config.getDatabaseName());
//分表設(shè)置,大致思想就是將查詢虛擬表Goods根據(jù)一定規(guī)則映射到真實表中去
TableRule orderTableRule = TableRule.builder("user")
.actualTables(Arrays.asList("user_0", "user_1", "user_2", "user_3", "user_4", "user_5", "user_6", "user_7", "user_8", "user_9"))
.dataSourceRule(dataSourceRule)
.build();
//分庫分表策略
ShardingRule shardingRule = ShardingRule.builder()
.dataSourceRule(dataSourceRule)
.tableRules(Arrays.asList(orderTableRule))
.databaseShardingStrategy(new DatabaseShardingStrategy("ID", databaseShardingAlgorithm))
.tableShardingStrategy(new TableShardingStrategy("ID", tableShardingAlgorithm)).build();
DataSource dataSource = ShardingDataSourceFactory.createDataSource(shardingRule);
return dataSource;
}
@Bean
public KeyGenerator keyGenerator() {
return new DefaultKeyGenerator();
}
}
七、開始測試
定義一個實體
package com.lzx.code.codedemo.entity;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.*;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
/**
* 描述: 用戶
*
* @Auther: lzx
* @Date: 2019/7/11 15:39
*/
@Entity(name = "USER")
@Getter
@Setter
@ToString
@JsonIgnoreProperties(ignoreUnknown = true)
@AllArgsConstructor
@NoArgsConstructor
public class User {
/**
* 主鍵
*/
@Id
@GeneratedValue(generator = "idUserConfig")
@GenericGenerator(name ="idUserConfig" ,strategy="org.kcsm.common.ids.SerialIdGeneratorSnowflakeId")
@Column(name = "ID", unique = true,nullable=false)
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
/**
* 用戶名
*/
@Column(name = "USER_NAME",length = 100)
private String userName;
/**
* 密碼
*/
@Column(name = "PASSWORD",length = 100)
private String password;
}
定義實體DAO
package com.lzx.code.codedemo.dao;
import com.lzx.code.codedemo.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
/**
* 描述: 用戶dao接口
*
* @Auther: lzx
* @Date: 2019/7/11 15:52
*/
@RepositoryRestResource(path = "user")
public interface UserDao extends JpaRepository<User,Long>,JpaSpecificationExecutor<User> {
}
測試類,插入1000條user數(shù)據(jù)
package com.lzx.code.codedemo;
import com.lzx.code.codedemo.dao.RolesDao;
import com.lzx.code.codedemo.dao.UserDao;
import com.lzx.code.codedemo.entity.Roles;
import com.lzx.code.codedemo.entity.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class CodeDemoApplicationTests {
@Autowired
private UserDao userDao;
@Autowired
private RolesDao rolesDao;
@Test
public void contextLoads() {
User user = null;
Roles roles = null;
for(int i=0;i<1000;i++){
user = new User(
null,
"lzx"+i,
"123456"
);
roles = new Roles(
null,
"角色"+i
);
rolesDao.save(roles);
userDao.save(user);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
效果:數(shù)據(jù)被分片存儲到0~9的數(shù)據(jù)表中

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Jpa中Specification的求和sum不生效原理分析
這篇文章主要為大家介紹了Jpa中Specification的求和sum不生效原理示例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08
淺談SpringCache與redis集成實現(xiàn)緩存解決方案
本篇文章主要介紹了淺談SpringCache與redis集成實現(xiàn)緩存解決方案,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-12-12
springboot?vue測試列表遞歸查詢子節(jié)點(diǎn)下的接口功能實現(xiàn)
這篇文章主要為大家介紹了springboot?vue測試列表遞歸查詢子節(jié)點(diǎn)下的接口功能實現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05
SpringBoot整合RabbitMQ實現(xiàn)延遲隊列的示例詳解
這篇文章主要為大家詳細(xì)介紹了SpringBoot如何整合RabbitMQ實現(xiàn)延遲隊列,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價值,感興趣的可以了解一下2023-04-04
IDEA 連接數(shù)據(jù)庫的實現(xiàn)方法
這篇文章主要介紹了IDEA 連接數(shù)據(jù)庫的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10
mybatis中association和collection的使用與區(qū)別
在 MyBatis 中,<association>?和?<collection>?是用于配置結(jié)果映射中關(guān)聯(lián)關(guān)系的兩個元素,本文主要介紹了mybatis中<association>和<collection>的使用與區(qū)別,具有一定的參考價值,感興趣的可以了解一下2024-01-01
Java Lambda表達(dá)式原理及多線程實現(xiàn)
這篇文章主要介紹了Java Lambda表達(dá)式原理及多線程實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-07-07
Java訪問WebService返回XML數(shù)據(jù)的方法
這篇文章主要介紹了Java訪問WebService返回XML數(shù)據(jù)的方法,涉及java操作WebService的相關(guān)技巧,需要的朋友可以參考下2015-06-06

