創建數據庫
DROP TABLE IF EXISTS `t_order_1`; CREATE TABLE `t_order_1`( `order_id` bigint(20) NOT NULL COMMENT'訂單id', `price` decimal(10,2) NOT NULL COMMENT'訂單價格', `user_id` bigint(20) NOT NULL COMMENT'下單用戶id', `status`varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '訂單狀態', PRIMARY KEY (`order_id`) USING BTREE )ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; DROP TABLE IF EXISTS `t_order_2`; CREATE TABLE `t_order_2`( `order_id` bigint(20) NOT NULL COMMENT '訂單id', `price` decimal(10,2) NOT NULL COMMENT '訂單價格', `user_id` bigint(20) NOT NULL COMMENT '下單用戶id', `status`varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '訂單狀態', PRIMARY KEY (`order_id`) USING BTREE )ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
引入maven依賴
<dependencies> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.1</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.16</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-jdbc-spring-boot-starter</artifactId> <version>4.0.0-RC1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
分片規則配置
分片規則配置是sharding-jdbc進行對分庫分表操作的重要依據,配置內容包括:數據源、主鍵生成策略、分片策
略等。
在application.properties中配置
server.port=56081
spring.application.name = sharding-jdbc-simple-demo
server.servlet.context-path = /sharding-jdbc-simple-demo
spring.http.encoding.enabled = true
spring.http.encoding.charset = UTF-8
spring.http.encoding.force = true
spring.main.allow-bean-definition-overriding = true
mybatis.configuration.map-underscore-to-camel-case = true
#sharding-jdbc分片規則配置
#數據源
spring.shardingsphere.datasource.names = m1
spring.shardingsphere.datasource.m1.type = com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m1.driver-class-name = com.mysql.jdbc.Driver
spring.shardingsphere.datasource.m1.url = jdbc:mysql://localhost:3306/order_db?useUnicode=true
spring.shardingsphere.datasource.m1.username = root
spring.shardingsphere.datasource.m1.password = mysql
# 指定t_order表的數據分布情況,配置數據節點 m1.t_order_1,m1.t_order_2
spring.shardingsphere.sharding.tables.t_order.actual-data-nodes = m1.t_order_$->{1..2}
# 指定t_order表的主鍵生成策略為SNOWFLAKE
spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id
spring.shardingsphere.sharding.tables.t_order.key-generator.type=SNOWFLAKE
# 指定t_order表的分片策略,分片策略包括分片鍵和分片算法
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column = order_id
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression = t_order_$->{order_id % 2 + 1}
# 打開sql輸出日志
spring.shardingsphere.props.sql.show = true
swagger.enable = true
logging.level.root = info
logging.level.org.springframework.web = info
logging.level.com.itheima.dbsharding = debug
logging.level.druid.sql = debug
1.首先定義數據源m1,並對m1進行實際的參數配置。
2.指定t_order表的數據分布情況,他分布在m1.t_order_1,m1.t_order_2
3.指定t_order表的主鍵生成策略為SNOWFLAKE,SNOWFLAKE是一種分布式自增算法,保證id全局唯一
4.定義t_order分片策略,order_id為偶數的數據落在t_order_1,為奇數的落在t_order_2,分表策略的表達式為t_order_$->{order_id % 2 + 1}
數據庫操作
package com.topcheer.dbsharding.simple.dao; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import org.springframework.stereotype.Component; import java.math.BigDecimal; import java.util.List; import java.util.Map; /** * Created by Administrator. */ @Mapper @Component public interface OrderDao { /** * 插入訂單 * @param price * @param userId * @param status * @return */ @Insert("insert into t_order(price,user_id,status)values(#{price},#{userId},#{status})") int insertOrder(@Param("price") BigDecimal price, @Param("userId") Long userId, @Param("status") String status); /** * 根據id列表查詢訂單 * @param orderIds * @return */ @Select("<script>" + "select" + " * " + " from t_order t " + " where t.order_id in " + " <foreach collection='orderIds' open='(' separator=',' close=')' item='id'>" + " #{id} " + " </foreach>" + "</script>") List<Map> selectOrderbyIds(@Param("orderIds") List<Long> orderIds); }
測試類
@RunWith(SpringRunner.class) @SpringBootTest(classes = {ShardingJdbcSimpleBootstrap.class}) public class ShardingJdbcDemoApplicationTests { @Autowired(required = false) OrderDao orderDao; @Test public void testInsertOrder(){ for(int i=1;i<20;i++){ orderDao.insertOrder(new BigDecimal(i),1L,"SUCCESS"); } } @Test public void testSelectOrderbyIds(){ List<Long> ids = new ArrayList<>(); ids.add(435435795839451136L); ids.add(435435794501468161L); List<Map> maps = orderDao.selectOrderbyIds(ids); System.out.println(maps); } }
當執行插入的方法的時候, 會把原來的sql進行解析,然后根據分片的規則,進行插入不同的表
但執行查詢的時候
通過日志可以發現,根據傳入order_id的奇偶不同,sharding-jdbc分別去不同的表檢索數據,達到預期目標
流程分析
通過日志分析,Sharding-JDBC在拿到用戶要執行的sql之后干了哪些事兒:
(1)解析sql,獲取片鍵值,在本例中是order_id
(2)Sharding-JDBC通過規則配置 t_order_$->{order_id % 2 + 1},知道了當order_id為偶數時,應該往
t_order_1表插數據,為奇數時,往t_order_2插數據。
(3)於是Sharding-JDBC根據order_id的值改寫sql語句,改寫后的SQL語句是真實所要執行的SQL語句。
(4)執行改寫后的真實sql語句
(5)將所有真正執行sql的結果進行匯總合並,返回。
注意假如是配置類的形式進行配置的話,要排除
@Configuration public class ShardingJdbcConfig { //配置分片規則 // 定義數據源 Map<String, DataSource> createDataSourceMap() { DruidDataSource dataSource1 = new DruidDataSource(); dataSource1.setDriverClassName("com.mysql.jdbc.Driver"); dataSource1.setUrl("jdbc:mysql://rm-bp1y5jh79h6b3eh9clo.mysql.rds.aliyuncs.com:3306/order_db?useUnicode=true"); dataSource1.setUsername("root"); dataSource1.setPassword("1qaz@WSX"); Map<String, DataSource> result = new HashMap<>(); result.put("m1", dataSource1); return result; } // 定義主鍵生成策略 private static KeyGeneratorConfiguration getKeyGeneratorConfiguration() { KeyGeneratorConfiguration result = new KeyGeneratorConfiguration("SNOWFLAKE","order_id"); return result; } // 定義t_order表的分片策略 TableRuleConfiguration getOrderTableRuleConfiguration() { TableRuleConfiguration result = new TableRuleConfiguration("t_order","m1.t_order_$->{1..2}"); result.setTableShardingStrategyConfig(new InlineShardingStrategyConfiguration("order_id", "t_order_$->{order_id % 2 + 1}")); result.setKeyGeneratorConfig(getKeyGeneratorConfiguration()); return result; } // 定義sharding-Jdbc數據源 @Bean DataSource getShardingDataSource() throws SQLException { ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration(); shardingRuleConfig.getTableRuleConfigs().add(getOrderTableRuleConfiguration()); //spring.shardingsphere.props.sql.show = true Properties properties = new Properties(); properties.put("sql.show","true"); return ShardingDataSourceFactory.createDataSource(createDataSourceMap(), shardingRuleConfig,properties); } }