先貼代碼, 回頭講解。未完待續java
實現分庫分表、讀寫分離。
準備兩張表:svc_order, svc_order_item mysql
結構以下,能夠想象成是未實施分庫分表以前的數據庫結構:算法
CREATE DATABASE IF NOT EXISTS DATABASE; USE DATABASE; CREATE TABLE IF NOT EXISTS `svc_order` ( `order_id` bigint(64) NOT NULL AUTO_INCREMENT, `user_id` bigint(64) DEFAULT NULL, `order_name` varchar(255) DEFAULT NULL, PRIMARY KEY (`order_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `svc_order_item` ( `order_item_id` bigint(64) NOT NULL AUTO_INCREMENT, `order_id` bigint(64) DEFAULT NULL, `order_item_name` varchar(255) DEFAULT NULL, PRIMARY KEY (`order_item_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
必定要對原有結構作到心中有數,重複表述一下:
咱們原有一個數據庫叫 database
, 裏面有兩張表,分別是 svc_order
訂單表和 svc_order_item
訂單明細表,每一個表都有一個主鍵ID 、用戶ID(user_id) 和 名稱。spring
計劃:
svc_order 表按照 user_id 分庫,按照主鍵 order_id 分片
svc_order_item 表按照 user_id 分庫,按照主鍵 order_item_id 分片sql
原有庫分紅兩個庫,使用 user_id 對 2 取模,例如 user_id = 2 的存入 0 庫,user_id = 3 的存入 1 庫。
原有表分紅兩個表,svc_order
訂單表使用 order_id 對 2 取模,svc_order_item
表使用 order_item_id 對 2 取模,例如 order_id = 2 的存入 0 表,order_id = 3 的存入 1 表。數據庫
讀寫分離設置爲 1 個寫庫,2 個讀庫。api
爲了便於理解,咱們定義經常使用名詞:ide
邏輯表:指的就是未實施分表以前的表名。例如 svc_order
就是邏輯表名。工具
虛擬表、物理表:指的是分表後真實存在的表名。上面咱們說到存到 0 表、 1 表就是虛擬表,爲了便於理解,咱們把邏輯表名加在前面,好比 svc_order
的兩個虛表咱們能夠命名爲 svc_order_0
、svc_order_1
測試
順便說明一下數據庫名,咱們原有 database
, 因爲要分紅兩個庫,咱們能夠命名爲 database_0
、database_1
,因爲,須要讀寫分離(1帶2),至關於又多了四個數據庫,至此,咱們的數據庫應該有 write_database_0
,read_0_database_0
,read_1_database_0
,write_database_1
,read_0_database_1
,read_1_database_1
init.sql
DROP DATABASE IF EXISTS write_database_0; DROP DATABASE IF EXISTS read_0_database_0; DROP DATABASE IF EXISTS read_1_database_0; DROP DATABASE IF EXISTS write_database_1; DROP DATABASE IF EXISTS read_0_database_1; DROP DATABASE IF EXISTS read_1_database_1; CREATE DATABASE IF NOT EXISTS write_database_0; USE write_database_0; CREATE TABLE IF NOT EXISTS `svc_order_0` ( `order_id` bigint(64) NOT NULL AUTO_INCREMENT, `user_id` bigint(64) DEFAULT NULL, `order_name` varchar(255) DEFAULT NULL, PRIMARY KEY (`order_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `svc_order_1` ( `order_id` bigint(64) NOT NULL AUTO_INCREMENT, `user_id` bigint(64) DEFAULT NULL, `order_name` varchar(255) DEFAULT NULL, PRIMARY KEY (`order_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `svc_order_item_0` ( `order_item_id` bigint(64) NOT NULL AUTO_INCREMENT, `order_id` bigint(64) DEFAULT NULL, `order_item_name` varchar(255) DEFAULT NULL, PRIMARY KEY (`order_item_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `svc_order_item_1` ( `order_item_id` bigint(64) NOT NULL AUTO_INCREMENT, `order_id` bigint(64) DEFAULT NULL, `order_item_name` varchar(255) DEFAULT NULL, PRIMARY KEY (`order_item_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE DATABASE IF NOT EXISTS read_1_database_0; USE read_1_database_0; CREATE TABLE IF NOT EXISTS `svc_order_0` ( `order_id` bigint(64) NOT NULL AUTO_INCREMENT, `user_id` bigint(64) DEFAULT NULL, `order_name` varchar(255) DEFAULT NULL, PRIMARY KEY (`order_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `svc_order_1` ( `order_id` bigint(64) NOT NULL AUTO_INCREMENT, `user_id` bigint(64) DEFAULT NULL, `order_name` varchar(255) DEFAULT NULL, PRIMARY KEY (`order_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `svc_order_item_0` ( `order_item_id` bigint(64) NOT NULL AUTO_INCREMENT, `order_id` bigint(64) DEFAULT NULL, `order_item_name` varchar(255) DEFAULT NULL, PRIMARY KEY (`order_item_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `svc_order_item_1` ( `order_item_id` bigint(64) NOT NULL AUTO_INCREMENT, `order_id` bigint(64) DEFAULT NULL, `order_item_name` varchar(255) DEFAULT NULL, PRIMARY KEY (`order_item_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE DATABASE IF NOT EXISTS read_0_database_0; USE read_0_database_0; CREATE TABLE IF NOT EXISTS `svc_order_0` ( `order_id` bigint(64) NOT NULL AUTO_INCREMENT, `user_id` bigint(64) DEFAULT NULL, `order_name` varchar(255) DEFAULT NULL, PRIMARY KEY (`order_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `svc_order_1` ( `order_id` bigint(64) NOT NULL AUTO_INCREMENT, `user_id` bigint(64) DEFAULT NULL, `order_name` varchar(255) DEFAULT NULL, PRIMARY KEY (`order_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `svc_order_item_0` ( `order_item_id` bigint(64) NOT NULL AUTO_INCREMENT, `order_id` bigint(64) DEFAULT NULL, `order_item_name` varchar(255) DEFAULT NULL, PRIMARY KEY (`order_item_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `svc_order_item_1` ( `order_item_id` bigint(64) NOT NULL AUTO_INCREMENT, `order_id` bigint(64) DEFAULT NULL, `order_item_name` varchar(255) DEFAULT NULL, PRIMARY KEY (`order_item_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE DATABASE IF NOT EXISTS write_database_1; USE write_database_1; CREATE TABLE IF NOT EXISTS `svc_order_0` ( `order_id` bigint(64) NOT NULL AUTO_INCREMENT, `user_id` bigint(64) DEFAULT NULL, `order_name` varchar(255) DEFAULT NULL, PRIMARY KEY (`order_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `svc_order_1` ( `order_id` bigint(64) NOT NULL AUTO_INCREMENT, `user_id` bigint(64) DEFAULT NULL, `order_name` varchar(255) DEFAULT NULL, PRIMARY KEY (`order_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `svc_order_item_0` ( `order_item_id` bigint(64) NOT NULL AUTO_INCREMENT, `order_id` bigint(64) DEFAULT NULL, `order_item_name` varchar(255) DEFAULT NULL, PRIMARY KEY (`order_item_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `svc_order_item_1` ( `order_item_id` bigint(64) NOT NULL AUTO_INCREMENT, `order_id` bigint(64) DEFAULT NULL, `order_item_name` varchar(255) DEFAULT NULL, PRIMARY KEY (`order_item_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE DATABASE IF NOT EXISTS read_0_database_1; USE read_0_database_1; CREATE TABLE IF NOT EXISTS `svc_order_0` ( `order_id` bigint(64) NOT NULL AUTO_INCREMENT, `user_id` bigint(64) DEFAULT NULL, `order_name` varchar(255) DEFAULT NULL, PRIMARY KEY (`order_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `svc_order_1` ( `order_id` bigint(64) NOT NULL AUTO_INCREMENT, `user_id` bigint(64) DEFAULT NULL, `order_name` varchar(255) DEFAULT NULL, PRIMARY KEY (`order_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `svc_order_item_0` ( `order_item_id` bigint(64) NOT NULL AUTO_INCREMENT, `order_id` bigint(64) DEFAULT NULL, `order_item_name` varchar(255) DEFAULT NULL, PRIMARY KEY (`order_item_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `svc_order_item_1` ( `order_item_id` bigint(64) NOT NULL AUTO_INCREMENT, `order_id` bigint(64) DEFAULT NULL, `order_item_name` varchar(255) DEFAULT NULL, PRIMARY KEY (`order_item_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE DATABASE IF NOT EXISTS read_1_database_1; USE read_1_database_1; CREATE TABLE IF NOT EXISTS `svc_order_0` ( `order_id` bigint(64) NOT NULL AUTO_INCREMENT, `user_id` bigint(64) DEFAULT NULL, `order_name` varchar(255) DEFAULT NULL, PRIMARY KEY (`order_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `svc_order_1` ( `order_id` bigint(64) NOT NULL AUTO_INCREMENT, `user_id` bigint(64) DEFAULT NULL, `order_name` varchar(255) DEFAULT NULL, PRIMARY KEY (`order_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `svc_order_item_0` ( `order_item_id` bigint(64) NOT NULL AUTO_INCREMENT, `order_id` bigint(64) DEFAULT NULL, `order_item_name` varchar(255) DEFAULT NULL, PRIMARY KEY (`order_item_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `svc_order_item_1` ( `order_item_id` bigint(64) NOT NULL AUTO_INCREMENT, `order_id` bigint(64) DEFAULT NULL, `order_item_name` varchar(255) DEFAULT NULL, PRIMARY KEY (`order_item_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
pom.xml
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.5</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>6.0.6</version> </dependency> <dependency> <groupId>com.dangdang</groupId> <artifactId>sharding-jdbc-core</artifactId> <version>1.5.4.1</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.18</version> <scope>provided</scope> </dependency>
ShardingJdbcConfig.java
package com.junbaor.sharding.config; import com.alibaba.druid.pool.DruidDataSource; import com.dangdang.ddframe.rdb.sharding.api.MasterSlaveDataSourceFactory; import com.dangdang.ddframe.rdb.sharding.api.ShardingDataSourceFactory; import com.dangdang.ddframe.rdb.sharding.api.rule.BindingTableRule; 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.slave.MasterSlaveLoadBalanceStrategyType; import com.dangdang.ddframe.rdb.sharding.api.strategy.table.TableShardingStrategy; import com.dangdang.ddframe.rdb.sharding.config.ShardingPropertiesConstant; 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; import java.util.Properties; @Configuration public class ShardingJdbcConfig { @Bean public DataSource buildDataSource() throws SQLException { /*讀寫分離 start */ DataSource writeDatabase0 = createDataSource("write_database_0"); Map<String, DataSource> slave0DataBase = new HashMap<>(2); slave0DataBase.put("read0_database_0", createDataSource("read0_database_0")); slave0DataBase.put("read1_database_0", createDataSource("read1_database_0")); DataSource database0 = MasterSlaveDataSourceFactory.createDataSource("write_database_0", "write_database_0", writeDatabase0, slave0DataBase, MasterSlaveLoadBalanceStrategyType.ROUND_ROBIN); DataSource writeDatabase1 = createDataSource("write_database_1"); Map<String, DataSource> slave1DataBase = new HashMap<>(2); slave1DataBase.put("read0_database_1", createDataSource("read0_database_1")); slave1DataBase.put("read1_database_1", createDataSource("read1_database_1")); DataSource database1 = MasterSlaveDataSourceFactory.createDataSource("write_database_1", "write_database_1", writeDatabase1, slave1DataBase, MasterSlaveLoadBalanceStrategyType.ROUND_ROBIN); /*讀寫分離 end */ Map<String, DataSource> dataSourceMap = new HashMap<>(2); dataSourceMap.put("database_0", database0); dataSourceMap.put("database_1", database1); /*分庫分表 start*/ DataSourceRule dataSourceRule = new DataSourceRule(dataSourceMap, "database_0"); TableRule orderTableRule = TableRule.builder("svc_order") .actualTables(Arrays.asList("svc_order_0", "svc_order_1")) .generateKeyColumn("order_id", KeyGenerate.class) .dataSourceRule(dataSourceRule) .build(); TableRule orderItemTableRule = TableRule.builder("svc_order_item") .actualTables(Arrays.asList("svc_order_item_0", "svc_order_item_1")) .generateKeyColumn("order_item_id",KeyGenerate.class) .dataSourceRule(dataSourceRule) .build(); BindingTableRule bindOrderAndOrderItem = new BindingTableRule(Arrays.asList(orderTableRule, orderItemTableRule)); ShardingRule shardingRule = ShardingRule.builder() .dataSourceRule(dataSourceRule) .tableRules(Arrays.asList(orderTableRule, orderItemTableRule)) .databaseShardingStrategy(new DatabaseShardingStrategy(Arrays.asList("user_id"), new DbSharding())) .tableShardingStrategy(new TableShardingStrategy(Arrays.asList("order_id"), new TableSharding())) .bindingTableRules(Arrays.asList(bindOrderAndOrderItem)) .build(); /*分庫分表 end*/ Properties properties = new Properties(); properties.setProperty(ShardingPropertiesConstant.SQL_SHOW.getKey(), "true"); DataSource dataSource = ShardingDataSourceFactory.createDataSource(shardingRule, properties); return dataSource; } private static DataSource createDataSource(final String dataSourceName) { DruidDataSource result = new DruidDataSource(); result.setUrl(String.format("jdbc:mysql://127.0.0.1:3306/%s?useUnicode=true&characterEncoding=utf-8&useSSL=false", dataSourceName)); result.setUsername("root"); result.setPassword("root"); return result; } }
AppUtils.java
package com.junbaor.sharding.util; import com.dangdang.ddframe.rdb.sharding.api.ShardingValue; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; public class AppUtils { public static Collection<String> sharding(Collection<String> availableTargetNames, Collection<ShardingValue<?>> shardingValues) { long shardingvalue = 0; Iterator<ShardingValue<?>> iterator = shardingValues.iterator(); if (iterator.hasNext()) { shardingvalue = ((Long) iterator.next().getValue()).intValue(); } for (String tableName : availableTargetNames) { if (tableName.endsWith((shardingvalue % 2) + "")) { return Arrays.asList(tableName); } } return null; } }
DbSharding.java
package com.junbaor.sharding.config; import com.dangdang.ddframe.rdb.sharding.api.ShardingValue; import com.dangdang.ddframe.rdb.sharding.api.strategy.database.MultipleKeysDatabaseShardingAlgorithm; import com.junbaor.sharding.util.AppUtils; import java.util.Collection; /** * 利用多分片鍵接口實現單鍵分片算法 */ public class DbSharding implements MultipleKeysDatabaseShardingAlgorithm { @Override public Collection<String> doSharding(Collection<String> availableTargetNames, Collection<ShardingValue<?>> shardingValues) { Collection<String> sharding = AppUtils.sharding(availableTargetNames, shardingValues); if (sharding != null) { return sharding; } return null; } }
TableSharding.java
package com.junbaor.sharding.config; import com.dangdang.ddframe.rdb.sharding.api.ShardingValue; import com.dangdang.ddframe.rdb.sharding.api.strategy.table.MultipleKeysTableShardingAlgorithm; import com.junbaor.sharding.util.AppUtils; import java.util.Collection; /** * 利用多分片鍵接口實現單鍵分片算法 */ public class TableSharding implements MultipleKeysTableShardingAlgorithm { @Override public Collection<String> doSharding(Collection<String> availableTargetNames, Collection<ShardingValue<?>> shardingValues) { Collection<String> sharding = AppUtils.sharding(availableTargetNames, shardingValues); if (sharding != null) { return sharding; } return null; } }
KeyGenerate.java 僅供單機測試
package com.junbaor.sharding.config; import com.dangdang.ddframe.rdb.sharding.keygen.KeyGenerator; import lombok.extern.slf4j.Slf4j; import java.util.concurrent.atomic.AtomicLong; @Slf4j public class KeyGenerate implements KeyGenerator { private static AtomicLong atomicInteger = new AtomicLong(1); @Override public Number generateKey() { long nextId = atomicInteger.addAndGet(1); log.info("nextId:{}", nextId); return nextId; } }