springboot+jpa+sharding-jdbc分表
1. 引入依賴:
<dependency>
<groupId>com.dangdang</groupId>
<artifactId>sharding-jdbc-core</artifactId>
<version>1.5.4</version>
</dependency>
2. 建立資料表:tabe_0,table_1,table_2...
3. 實現分表演算法
import java.util.Collection;
import java.util.LinkedHashSet;
import com.dangdang.ddframe.rdb.sharding.api.ShardingValue;
import com.dangdang.ddframe.rdb.sharding.api.strategy.table.SingleKeyTableShardingAlgorithm;
import com.google.common.collect.Range;
public final class JdbcSharingConfig implements SingleKeyTableShardingAlgorithm<Long> {
/**
* doEqualSharding =
* @param tableNames 實際物理表名
* @param shardingValue [logicTableName="t_order", columnName="order_id", value=20]
*
* select * from t_order from t_order where order_id = 11
* └── SELECT * FROM t_order_1 WHERE order_id = 11
* select * from t_order from t_order where order_id = 44
* └── SELECT * FROM t_order_0 WHERE order_id = 44
*
* select * from t_order from t_order where order_id = 11
* └── SELECT * FROM t_order_1 WHERE order_id = 11
* select * from t_order from t_order where order_id = 44
* └── SELECT * FROM t_order_0 WHERE order_id = 44
*/
public String doEqualSharding(final Collection<String> tableNames, final ShardingValue<Long> shardingValue) {
int index = (int)(shardingValue.getValue() % 450);
String indexStr = "";
if(index >= 300)
indexStr = "2";
else if(index >= 150)
indexStr = "1";
else
indexStr = "0";
for (String each : tableNames) {
if (each.endsWith(indexStr)) {
return each;
}
}
throw new IllegalArgumentException();
}
/**
* select * from t_order from t_order where order_id in (11,44)
* ├── SELECT * FROM t_order_0 WHERE order_id IN (11,44)
* └── SELECT * FROM t_order_1 WHERE order_id IN (11,44)
* select * from t_order from t_order where order_id in (11,13,15)
* └── SELECT * FROM t_order_1 WHERE order_id IN (11,13,15)
* select * from t_order from t_order where order_id in (22,24,26)
* └──SELECT * FROM t_order_0 WHERE order_id IN (22,24,26)
*/
@Override
public Collection<String> doInSharding(final Collection<String> tableNames, final ShardingValue<Long> shardingValue) {
Collection<String> result = new LinkedHashSet<>(tableNames.size());
for (Long value : shardingValue.getValues()) {
int index = (int)(value % 450);
String indexStr = "";
if(index >= 450)
indexStr = "2";
else if(index >= 300)
indexStr = "1";
else
indexStr = "0";
for (String tableName : tableNames) {
if (tableName.endsWith(indexStr)) {
result.add(tableName);
}
}
}
return result;
}
/**
* select * from t_order from t_order where order_id between 10 and 20
* ├── SELECT * FROM t_order_0 WHERE order_id BETWEEN 10 AND 20
* └── SELECT * FROM t_order_1 WHERE order_id BETWEEN 10 AND 20
*/
@Override
public Collection<String> doBetweenSharding(final Collection<String> tableNames, final ShardingValue<Long> shardingValue) {
Collection<String> result = new LinkedHashSet<>(tableNames.size());
Range<Long> range = shardingValue.getValueRange();
for (Long i = range.lowerEndpoint(); i <= range.upperEndpoint(); i++) {
int index = (int)(i % 450);
String indexStr = "";
if(index >= 450)
indexStr = "2";
else if(index >= 300)
indexStr = "1";
else
indexStr = "0";
for (String each : tableNames) {
if (each.endsWith(indexStr)) {
result.add(each);
}
}
}
return result;
}
4. 配置類:
import com.alibaba.druid.pool.DruidDataSource;
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.mysql.jdbc.Driver;
import org.springframework.beans.factory.annotation.Value;
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;
@Configuration
public class DataSourceConfiguration {
@Value("${database.name}")
private String databaseName;
@Value("${database.user}")
private String username;
@Value("${database.psw}")
private String psw;
@Bean
public DataSource getDataSource() throws SQLException {
return buildDataSource();
}
private DataSource buildDataSource() throws SQLException {
// 設定分庫對映
Map<String, DataSource> dataSourceMap = new HashMap<>(2);
// 新增兩個資料庫db0,db1到map裡
dataSourceMap.put("db0", createDataSource(databaseName, username, psw));
// dataSourceMap.put("db1", createDataSource("db1"));
// 設定預設db為db0,也就是為那些沒有配置分庫分表策略的指定的預設庫
// 如果只有一個庫,也就是不需要分庫的話,map裡只放一個對映就行了,只有一個庫時不需要指定預設庫,但2個及以上時必須指定預設庫,否則那些沒有配置策略的表將無法操作資料
DataSourceRule dataSourceRule = new DataSourceRule(dataSourceMap, "db0");
// 設定分表對映,將table_0和table_1兩個實際的表對映到table邏輯表
// 0和1兩個表是真實的表,table是個虛擬不存在的表,只是供使用。如查詢所有資料就是select * from table就能查完0和1表的
TableRule orderTableRule = TableRule.builder("table")
.actualTables(Arrays.asList("table_0", "table_1", "table_2"))
.dataSourceRule(dataSourceRule)
.build();
// 具體分庫分表策略,按什麼規則來分
ShardingRule shardingRule = ShardingRule.builder()
.dataSourceRule(dataSourceRule)
.tableRules(Arrays.asList(orderTableRule))
// .databaseShardingStrategy(new DatabaseShardingStrategy("id_table", new JdbcSharingConfig()))
.tableShardingStrategy(new TableShardingStrategy("id_table", new JdbcSharingConfig())).build();
DataSource dataSource = ShardingDataSourceFactory.createDataSource(shardingRule);
return dataSource;
}
private static DataSource createDataSource(final String dataSourceName, final String username, final String psw) {
// 使用druid連線資料庫
DruidDataSource result = new DruidDataSource();
result.setDriverClassName(Driver.class.getName());
result.setUrl(dataSourceName);
result.setUsername(username);
result.setPassword(psw);
return result;
}
}