1. 程式人生 > >springboot+jpa+sharding-jdbc分表

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;
    }
}