1. 程式人生 > >dangdang的擴充套件 sharding-jdbc實現動態資料來源分庫分表分頁查詢

dangdang的擴充套件 sharding-jdbc實現動態資料來源分庫分表分頁查詢

dangdang的擴充套件 sharding-jdbc實現動態資料來源分庫分表分頁查詢


原文地址

dangdang的分庫分表擴充套件 sharding-jdbc

這段時間應公司需求需要分庫查詢資料,還好不是分表
研究了一下sharding-jdbc
我這裡需求有點複雜,說是資料來源不固定,隨時新增一個數據源我就想到不能配置到專案檔案中,就在業務庫中新建一個表用來儲存資料來源的資訊
表資訊


用最原始的jdbc連線資料庫的方式實現分庫查詢

封裝的DBUtil

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.jdbc.core.datasource.ShardingDataSource; import com.maven.znly.entity.NewDataSource; import org.apache.commons.dbcp.BasicDataSource; import javax.sql.DataSource; import java.
sql.*; import java.util.*; /** * @ClassName DBUtil * @Description 為了方便建立資料庫連結 只為查詢封裝 * @Author asus * @Date Created by asus on 2018/11/1917:22 * @Version 1.0 **/ public class DBUtil { public static Page getPage(List<NewDataSource> dataSourceList, String sql,PageRequest pageRequest){ ResultSet rs=null; Connection conn=null; List<Map<String, Object>> list = new ArrayList<>(); Integer pageNo=pageRequest.getPageNumber();//第幾頁 Integer pageSize=pageRequest.getPageSize();//一頁幾條 Integer count=0; try { Map<String, DataSource> dataSourceMap = createDataSourceMap(dataSourceList); DataSourceRule dataSourceRule = new DataSourceRule(dataSourceMap); TableRule[] tableRules=new TableRule[dataSourceList.size()]; for (int i = 0; i <dataSourceList.size() ; i++) { TableRule tableRule = TableRule.builder("device_log").actualTables(Arrays.asList("device_log")).dataSourceRule(dataSourceRule).build(); tableRules[i]=tableRule; } List<TableRule> newTableRule=Arrays.asList(tableRules); //TableRule orderTableRule = TableRule.builder("device_log").actualTables(Arrays.asList("device_log")).dataSourceRule(dataSourceRule).build(); ShardingRule shardingRule = ShardingRule.builder().dataSourceRule(dataSourceRule).tableRules(newTableRule) .databaseShardingStrategy(new DatabaseShardingStrategy("create_time", new ModuloDatabaseShardingAlgorithm())) .tableShardingStrategy(new TableShardingStrategy("create_time", new ModuloTableShardingAlgorithm())).build(); DataSource dataSource = new ShardingDataSource(shardingRule); //2.獲得資料庫的連線 conn=dataSource.getConnection(); //構造一個statement物件來執行sql語句:主要有Statement,PreparedStatement,CallableStatement三種例項來實現 // stmt=conn.createStatement(); //獲得總個數 String countSql = "select count(*) totalCount from (" + sql + " ) cout"; PreparedStatement pstmt = conn.prepareStatement(countSql); rs=pstmt.executeQuery(); count=rs.getInt("totalCount"); StringBuilder sb = new StringBuilder("SELECT * FROM "); sb.append("( "); sb.append(sql); sb.append(") A limit " + ( pageNo* pageSize) + "," + pageSize + ""); PreparedStatement pstmts = conn.prepareStatement(sb.toString()); rs=pstmts.executeQuery(); //PreparedStatement pstmt = conn.prepareStatement(sql); //執行sql並返還結束 ; ResultSetMetaData md = rs.getMetaData(); //獲得結果集結構資訊,元資料 int columnCount = md.getColumnCount(); //獲得列數 while (rs.next()) { Map<String,Object> rowData = new HashMap<>(); for (int i = 1; i <= columnCount; i++) { rowData.put(md.getColumnName(i), rs.getObject(i)); } list.add(rowData); } if(rs !=null){//11.關閉記錄集 try{ rs.close(); } catch (SQLException e){ e.printStackTrace(); } } if(conn !=null){//13.關閉連線 (記住一定要先關閉前面的11.12.然後在關閉連線,就像關門一樣,先關裡面的,最後關最外面的) try{ conn.close(); }catch(SQLException e){ e.printStackTrace(); } } }catch (Exception e){ e.printStackTrace(); } return new MyPage(pageRequest, list, count); } //將獲得的資料庫與java的連結返回(返回的型別為Connection) public static List<Map<String,Object>> getConnection(List<NewDataSource> dataSourceList, String sql){ ResultSet rs=null; Connection conn=null; List<Map<String, Object>> list = new ArrayList<>(); Integer count=0; try { Map<String, DataSource> dataSourceMap = createDataSourceMap(dataSourceList); DataSourceRule dataSourceRule = new DataSourceRule(dataSourceMap); TableRule[] tableRules=new TableRule[dataSourceList.size()]; for (int i = 0; i <dataSourceList.size() ; i++) { TableRule tableRule = TableRule.builder("device_log").actualTables(Arrays.asList("device_log")).dataSourceRule(dataSourceRule).build(); tableRules[i]=tableRule; } List<TableRule> newTableRule=Arrays.asList(tableRules); //TableRule orderTableRule = TableRule.builder("device_log").actualTables(Arrays.asList("device_log")).dataSourceRule(dataSourceRule).build(); ShardingRule shardingRule = ShardingRule.builder().dataSourceRule(dataSourceRule).tableRules(newTableRule) .databaseShardingStrategy(new DatabaseShardingStrategy("create_time", new ModuloDatabaseShardingAlgorithm())) .tableShardingStrategy(new TableShardingStrategy("create_time", new ModuloTableShardingAlgorithm())).build(); DataSource dataSource = new ShardingDataSource(shardingRule); //2.獲得資料庫的連線 conn=dataSource.getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql); rs=pstmt.executeQuery(); ResultSetMetaData md = rs.getMetaData(); //獲得結果集結構資訊,元資料 int columnCount = md.getColumnCount(); //獲得列數 while (rs.next()) { Map<String,Object> rowData = new HashMap<>(); for (int i = 1; i <= columnCount; i++) { rowData.put(md.getColumnName(i), rs.getObject(i)); } list.add(rowData); } if(rs !=null){//11.關閉記錄集 try{ rs.close(); } catch (SQLException e){ e.printStackTrace(); } } if(conn !=null){//13.關閉連線 (記住一定要先關閉前面的11.12.然後在關閉連線,就像關門一樣,先關裡面的,最後關最外面的) try{ conn.close(); }catch(SQLException e){ e.printStackTrace(); } } }catch (Exception e){ e.printStackTrace(); } return list; } private static DataSource createDataSource(NewDataSource dataSource) { BasicDataSource result = new BasicDataSource(); result.setDriverClassName("com.mysql.jdbc.Driver"); String URL="jdbc:mysql://"+dataSource.getDataIp()+":"+dataSource.getDataCode()+"/"+dataSource.getDataDbName()+"?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&autoReconnect=true&useSSL=false&serverTimezone=GMT%2B8"; result.setUrl(URL); result.setUsername(dataSource.getDataUserName()); result.setPassword(dataSource.getDataUserPassword()); return result; } private static Map<String, DataSource> createDataSourceMap(List<NewDataSource> dataSourceList) { Map<String, DataSource> mapList = new HashMap<>(); for (int i = 0; i < dataSourceList.size(); i++) { NewDataSource dataSource=dataSourceList.get(i); DataSource dataSource1=createDataSource(dataSource); mapList.put(dataSource.getDataDbName(),dataSource1); } return mapList; } static class MyPage implements Page { private PageRequest pageRequest; private List<Map<String, Object>> objectList; private int total; public MyPage(PageRequest pageRequest, List<Map<String,Object>> objectList, int total) { this.pageRequest = pageRequest; this.objectList = objectList; this.total = total; } @Override public int getNumber() { return pageRequest.getPageNumber(); } @Override public int getSize() { return pageRequest.getPageSize(); } @Override public int getTotalPages() { if (total % pageRequest.getPageSize() == 0) { return total/pageRequest.getPageSize(); } else { return total/pageRequest.getPageSize()+1; } } @Override public int getNumberOfElements() { return 0; } @Override public long getTotalElements() { return this.total; } @Override public Page map(Converter converter) { return null; } @Override public Iterator<Map<String,Object>> iterator() { return objectList.iterator(); } @Override public List<Map<String,Object>> getContent() { return objectList; } @Override public boolean hasContent() { return objectList!=null&&objectList.size()>0; } @Override public Sort getSort() { return null; } @Override public boolean isFirst() { return pageRequest.getPageNumber() == 0; } @Override public boolean isLast() { return pageRequest.getPageNumber()==getTotalPages()-1; } @Override public boolean hasNext() { return pageRequest.getPageNumber()<getTotalPages()-1; } @Override public boolean hasPrevious() { return pageRequest.getPageNumber() >0; } @Override public Pageable nextPageable() { return null; } @Override public Pageable previousPageable() { return null; } } }

因為我需要分頁所以這裡就再次封裝一個

ModuloDatabaseShardingAlgorithm

import com.dangdang.ddframe.rdb.sharding.api.ShardingValue;
import com.dangdang.ddframe.rdb.sharding.api.strategy.database.SingleKeyDatabaseShardingAlgorithm;
import com.google.common.collect.Range;

import java.util.Collection;
import java.util.LinkedHashSet;

/**
 * @ClassName ModuloDatabaseShardingAlgorithm
 * @Description TODO
 * @Author asus
 * @Date Created by asus on 2018/12/1012:10
 * @Version 1.0
 **/
public class ModuloDatabaseShardingAlgorithm implements SingleKeyDatabaseShardingAlgorithm<Integer>{
    @Override
    public String doEqualSharding(Collection<String> collection, ShardingValue<Integer> shardingValue) {
        for (String each : collection) {
            if (each.endsWith(shardingValue.getValue() % 2 + "")) {
                return each;
            }
        }
        throw new IllegalArgumentException();
    }

    @Override
    public Collection<String> doInSharding(Collection<String> collection, ShardingValue<Integer> shardingValue) {
        Collection<String> result = new LinkedHashSet<>(collection.size(