赞
踩
这里的水平分库分表是指 水平分库 + 水平分表 ,怎么解释呢,一般是这个订单表特别的大,然后就进行水平分表,一个库多个一样的表,随着数据继续大,发现库的数据也太大,然后就把库也变成多个,里面的表结构和原来是一样的。先看下大致架构走势,如下图:
数据流向图如下:
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.6.0</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.alian</groupId> <artifactId>sharding-jdbc</artifactId> <version>0.0.1-SNAPSHOT</version> <name>sharding-jdbc</name> <description>sharding-jdbc</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-jdbc-spring-boot-starter</artifactId> <version>4.1.1</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.15</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.26</version> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.20</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
有些小伙伴的 druid 可能用的是 druid-spring-boot-starter
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.6</version>
</dependency>
然后出现可能使用不了的各种问题,这个时候你只需要在主类上添加 @SpringBootApplication(exclude = {DruidDataSourceAutoConfigure.class}) 即可
package com.alian.shardingjdbc;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication(exclude = {DruidDataSourceAutoConfigure.class})
@SpringBootApplication
public class ShardingJdbcApplication {
public static void main(String[] args) {
SpringApplication.run(ShardingJdbcApplication.class, args);
}
}
sharding_0
CREATE DATABASE `sharding_1` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
CREATE DATABASE `sharding_2` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
在数据库sharding_1和sharding_1下面分别创建两张表:tb_order_1和tb_order_2,也就是每个库都有两张表,表的结构都是一样的。
tb_order_1
CREATE TABLE `tb_order_1` (
`order_id` bigint(20) NOT NULL COMMENT '主键',
`user_id` int unsigned NOT NULL DEFAULT '0' COMMENT '用户id',
`price` int unsigned NOT NULL DEFAULT '0' COMMENT '价格(单位:分)',
`order_status` tinyint unsigned NOT NULL DEFAULT '1' COMMENT '订单状态(1:待付款,2:已付款,3:已取消)',
`order_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`title` varchar(100) NOT NULL DEFAULT '' COMMENT '订单标题',
PRIMARY KEY (`order_id`),
KEY `idx_user_id` (`user_id`),
KEY `idx_order_time` (`order_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';
tb_order_2
CREATE TABLE `tb_order_2` (
`order_id` bigint(20) NOT NULL COMMENT '主键',
`user_id` int unsigned NOT NULL DEFAULT '0' COMMENT '用户id',
`price` int unsigned NOT NULL DEFAULT '0' COMMENT '价格(单位:分)',
`order_status` tinyint unsigned NOT NULL DEFAULT '1' COMMENT '订单状态(1:待付款,2:已付款,3:已取消)',
`order_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`title` varchar(100) NOT NULL DEFAULT '' COMMENT '订单标题',
PRIMARY KEY (`order_id`),
KEY `idx_user_id` (`user_id`),
KEY `idx_order_time` (`order_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';
application.properties
server.port=8899 server.servlet.context-path=/sharding-jdbc # 允许定义相同的bean对象去覆盖原有的 spring.main.allow-bean-definition-overriding=true # 数据源名称,多数据源以逗号分隔 spring.shardingsphere.datasource.names=ds1,ds2 # sharding_1数据库连接池类名称 spring.shardingsphere.datasource.ds1.type=com.alibaba.druid.pool.DruidDataSource # sharding_1数据库驱动类名 spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.cj.jdbc.Driver # sharding_1数据库url连接 spring.shardingsphere.datasource.ds1.url=jdbc:mysql://192.168.19.129:3306/sharding_1?serverTimezone=GMT%2B8&characterEncoding=utf8&useUnicode=true&useSSL=false&zeroDateTimeBehavior=CONVERT_TO_NULL&autoReconnect=true&allowMultiQueries=true&failOverReadOnly=false&connectTimeout=6000&maxReconnects=5 # sharding_1数据库用户名 spring.shardingsphere.datasource.ds1.username=alian # sharding_1数据库密码 spring.shardingsphere.datasource.ds1.password=123456 # sharding_2数据库连接池类名称 spring.shardingsphere.datasource.ds2.type=com.alibaba.druid.pool.DruidDataSource # sharding_2数据库驱动类名 spring.shardingsphere.datasource.ds2.driver-class-name=com.mysql.cj.jdbc.Driver # sharding_2数据库url连接 spring.shardingsphere.datasource.ds2.url=jdbc:mysql://192.168.19.130:3306/sharding_2?serverTimezone=GMT%2B8&characterEncoding=utf8&useUnicode=true&useSSL=false&zeroDateTimeBehavior=CONVERT_TO_NULL&autoReconnect=true&allowMultiQueries=true&failOverReadOnly=false&connectTimeout=6000&maxReconnects=5 # sharding_2数据库用户名 spring.shardingsphere.datasource.ds2.username=alian # sharding_2数据库密码 spring.shardingsphere.datasource.ds2.password=123456 # 指定tb_order表的数据分布情况,配置数据节点,使用Groovy的表达式,逻辑表tb_order对应的节点是:ds1.tb_order_1, ds1.tb_order_2,ds2.tb_order_1, ds2.tb_order_2 spring.shardingsphere.sharding.tables.tb_order.actual-data-nodes=ds$->{1..2}.tb_order_$->{1..2} # 指定库分片策略,根据user_id的奇偶性来添加到不同的库中 spring.shardingsphere.sharding.tables.tb_order.database-strategy.inline.sharding-column=user_id spring.shardingsphere.sharding.tables.tb_order.database-strategy.inline.algorithm-expression=ds$->{user_id%2==0?2:1} # 采用行表达式分片策略:InlineShardingStrategy # 指定tb_order表的分片策略中的分片键 spring.shardingsphere.sharding.tables.tb_order.table-strategy.inline.sharding-column=order_id # 指定tb_order表的分片策略中的分片算法表达式,使用Groovy的表达式 spring.shardingsphere.sharding.tables.tb_order.table-strategy.inline.algorithm-expression=tb_order_$->{order_id%2==0?2:1} # 指定tb_order表的主键为order_id spring.shardingsphere.sharding.tables.tb_order.key-generator.column=order_id # 指定tb_order表的主键生成策略为SNOWFLAKE spring.shardingsphere.sharding.tables.tb_order.key-generator.type=SNOWFLAKE # 指定雪花算法的worker.id spring.shardingsphere.sharding.tables.tb_order.key-generator.props.worker.id=100 # 指定雪花算法的max.tolerate.time.difference.milliseconds spring.shardingsphere.sharding.tables.tb_order.key-generator.props.max.tolerate.time.difference.milliseconds=20 # 打开sql输出日志 spring.shardingsphere.props.sql.show=true
application.yml
server: port: 8899 servlet: context-path: /sharding-jdbc spring: main: # 允许定义相同的bean对象去覆盖原有的 allow-bean-definition-overriding: true shardingsphere: props: sql: # 打开sql输出日志 show: true datasource: # 数据源名称,多数据源以逗号分隔 names: ds1,ds2 ds1: # 数据库连接池类名称 type: com.alibaba.druid.pool.DruidDataSource # 数据库驱动类名 driver-class-name: com.mysql.cj.jdbc.Driver # 数据库url连接 url: jdbc:mysql://192.168.19.129:3306/sharding_1?serverTimezone=GMT%2B8&characterEncoding=utf8&useUnicode=true&useSSL=false&zeroDateTimeBehavior=CONVERT_TO_NULL&autoReconnect=true&allowMultiQueries=true&failOverReadOnly=false&connectTimeout=6000&maxReconnects=5 # 数据库用户名 username: alian # 数据库密码 password: 123456 ds2: # 数据库连接池类名称 type: com.alibaba.druid.pool.DruidDataSource # 数据库驱动类名 driver-class-name: com.mysql.cj.jdbc.Driver # 数据库url连接 url: jdbc:mysql://192.168.19.130:3306/sharding_2?serverTimezone=GMT%2B8&characterEncoding=utf8&useUnicode=true&useSSL=false&zeroDateTimeBehavior=CONVERT_TO_NULL&autoReconnect=true&allowMultiQueries=true&failOverReadOnly=false&connectTimeout=6000&maxReconnects=5 # 数据库用户名 username: alian # 数据库密码 password: 123456 sharding: # 未配置分片规则的表将通过默认数据源定位 default-data-source-name: ds1 tables: tb_order: # 由数据源名 + 表名组成,以小数点分隔。多个表以逗号分隔,支持inline表达式 actual-data-nodes: ds$->{1..2}.tb_order_$->{1..2} # 分库策略 database-strategy: # 行表达式分片策略 inline: # 分片键 sharding-column: user_id # 算法表达式 algorithm-expression: ds$->{user_id%2==0?2:1} # 分表策略 table-strategy: # 行表达式分片策略 inline: # 分片键 sharding-column: order_id # 算法表达式 algorithm-expression: tb_order_$->{order_id%2==0?2:1} # key生成器 key-generator: # 自增列名称,缺省表示不使用自增主键生成器 column: order_id # 自增列值生成器类型,缺省表示使用默认自增列值生成器(SNOWFLAKE/UUID) type: SNOWFLAKE # SnowflakeShardingKeyGenerator props: # SNOWFLAKE算法的worker.id worker: id: 100 # SNOWFLAKE算法的max.tolerate.time.difference.milliseconds max: tolerate: time: difference: milliseconds: 20
Order.java
@Data @Entity @Table(name = "tb_order") public class Order implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "order_id") private Long orderId; @Column(name = "user_id") private Integer userId; @Column(name = "price") private Integer price; @Column(name = "order_status") private Integer orderStatus; @Column(name = "title") private String title; @Column(name = "order_time") private LocalDateTime orderTime; }
OrderRepository.java
package com.alian.shardingjdbc.repository;
import com.alian.shardingjdbc.domain.Order;
import org.springframework.data.repository.PagingAndSortingRepository;
public interface OrderRepository extends PagingAndSortingRepository<Order, Long> {
/**
* 根据订单id查询订单
* @param orderId
* @return
*/
Order findOrderByOrderId(Long orderId);
}
OrderService.java
package com.alian.shardingjdbc.service; import com.alian.shardingjdbc.domain.Order; import com.alian.shardingjdbc.repository.OrderRepository; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Optional; @Slf4j @Service public class OrderService { @Autowired private OrderRepository orderRepository; public void saveOrder(Order order) { orderRepository.save(order); } public Order queryOrder(Long orderId) { return orderRepository.findOrderByOrderId(orderId); } }
OrderTests.java
package com.alian.shardingjdbc; import com.alian.shardingjdbc.domain.Order; import com.alian.shardingjdbc.service.OrderService; import lombok.extern.slf4j.Slf4j; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import java.time.LocalDateTime; @Slf4j @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest public class OrderTests { @Autowired private OrderService orderService; @Test public void saveOrder() { for (int i = 0; i < 20; i++) { Order order = new Order(); // 随机生成1000到1006的用户id int userId = (int) Math.round(Math.random() * (1006 - 1000) + 1000); order.setUserId(userId); // 随机生成50到100的金额 int price = (int) Math.round(Math.random() * (10000 - 5000) + 5000); order.setPrice(price); order.setOrderStatus(2); order.setOrderTime(LocalDateTime.now()); order.setTitle(""); orderService.saveOrder(order); } } @Test public void queryOrder() { Long orderId = 845384036364206080L; Order order = orderService.queryOrder(orderId); log.info("查询的结果:{}", order); } }
效果图:
从上面的结果我们可以看到order_id为 845384036364206080 的记录在 sharding_2 库的 tb_order_2 表,实际查询是去两个数据源的 tb_order_2 表中查询,然后汇总得到结果,请看下面的 Actual SQL
19:49:34 145 INFO [main]:Logic SQL: select order0_.order_id as order_id1_0_, order0_.order_status as order_st2_0_, order0_.order_time as order_ti3_0_, order0_.price as price4_0_, order0_.title as title5_0_, order0_.user_id as user_id6_0_ from tb_order order0_ where order0_.order_id=?
19:49:34 145 INFO [main]:Actual SQL: ds1 ::: select order0_.order_id as order_id1_0_, order0_.order_status as order_st2_0_, order0_.order_time as order_ti3_0_, order0_.price as price4_0_, order0_.title as title5_0_, order0_.user_id as user_id6_0_ from tb_order_2 order0_ where order0_.order_id=? ::: [845384036364206080]
19:49:34 146 INFO [main]:Actual SQL: ds2 ::: select order0_.order_id as order_id1_0_, order0_.order_status as order_st2_0_, order0_.order_time as order_ti3_0_, order0_.price as price4_0_, order0_.title as title5_0_, order0_.user_id as user_id6_0_ from tb_order_2 order0_ where order0_.order_id=? ::: [845384036364206080]
19:49:34 212 INFO [main]:查询的结果:Order(orderId=845384036364206080, userId=1004, price=6984, orderStatus=2, title=, orderTime=2023-03-22T19:34:21)
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。