下面是springboot按月分表的实现方式完整攻略:
第一步:创建表和初始化数据
首先,我们需要创建一张原始的订单表,结构如下:
CREATE TABLE `order` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`order_no` varchar(64) DEFAULT NULL COMMENT '订单号',
`order_amount` decimal(10,2) DEFAULT NULL COMMENT '订单金额',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';
接下来,初始化一些数据,可以通过以下SQL语句插入数据:
INSERT INTO `order`(order_no, order_amount, create_time) VALUES
('202201010001', 100, '2022-01-01 10:10:10'),
('202201020001', 300, '2022-01-02 10:10:10'),
('202202010001', 200, '2022-02-01 10:10:10');
第二步:实现按月分表的方式
定义分表规则
首先,我们需要定义分表规则,这里我们选择按照订单创建时间来进行分表,即每个月一张表。
创建分表的SQL语句
接下来,我们可以通过以下SQL语句来创建按月分表的订单表:
CREATE TABLE IF NOT EXISTS `order_{0}` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`order_no` varchar(64) DEFAULT NULL COMMENT '订单号',
`order_amount` decimal(10,2) DEFAULT NULL COMMENT '订单金额',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';
上面的语句中,{0}
表示动态的表名后缀,例如表名为order_202201
。
实现分表的代码逻辑
最后,我们可以通过实现springboot的拦截器和多数据源来实现按月分表的逻辑。
首先,我们要实现拦截器,来根据订单创建的时间来判断应该使用哪个数据源,代码示例:
@Component
public class OrderTableInterceptor implements HandlerInterceptor {
private static final String TABLE_PREFIX = "order_";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String orderNo = request.getParameter("orderNo");
if (StringUtils.isEmpty(orderNo)) {
throw new BusinessException("orderNo不能为空");
}
Date createTime = getOrderCreateTime(orderNo);
if (createTime == null) {
throw new BusinessException("获取订单创建时间失败");
}
String dataSourceKey = TABLE_PREFIX + DateUtil.format(createTime, "yyyyMM");
DataSourceContextHolder.setDataSourceKey(dataSourceKey);
return true;
}
/**
* 根据订单号获取订单创建时间
*/
private Date getOrderCreateTime(String orderNo) {
// 查询订单,返回订单创建时间
// 这里假设根据订单号从数据库中查询出来的订单创建时间为:2022-01-01 10:10:10
return DateUtil.parse("2022-01-01 10:10:10");
}
}
在上面的代码中,我们首先根据订单号获取订单创建时间,然后将订单创建时间格式化成表名的后缀,例如订单创建时间为2022-01-01 10:10:10
,则表名后缀为202201
。最后,使用DataSourceContextHolder
来动态切换数据源。
接下来,我们还需要实现多数据源的配置和切换,这里我们采用springboot官方推荐的AbstractRoutingDataSource
来实现,代码示例:
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDataSourceKey();
}
}
其中,DataSourceContextHolder
就是用来保存当前线程要使用的数据源的key。
最后,我们需要在springboot的配置文件中加入以下配置,来指定使用DynamicDataSource
作为数据源:
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/order?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: root
password: root
initial-size: 3
min-idle: 3
max-active: 500
max-wait: 60000
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
validation-query: SELECT 1 FROM DUAL
test-while-idle: true
test-on-borrow: false
test-on-return: false
datasource:
# 按月分表的数据源配置
order_202201:
url: jdbc:mysql://localhost:3306/order_202201?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
order_202202:
url: jdbc:mysql://localhost:3306/order_202202?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
在上面的配置中,我们针对每个月的订单表都配置了一个单独的数据源。
第三步:测试
最后,我们可以通过以下代码来测试按月分表的实现方式:
@RestController
public class OrderController {
@Autowired
OrderMapper orderMapper;
@GetMapping("/order")
public List<Order> getOrderList(@RequestParam String orderNo) {
return orderMapper.getOrderList(orderNo);
}
@PostMapping("/order")
public Order addOrder(@RequestBody Order order) {
orderMapper.addOrder(order);
return order;
}
}
其中,OrderMapper
是用来操作数据库的Mapper,在里面会使用我们刚刚实现的动态数据源的逻辑。在测试时,可以通过Postman等工具来发送请求,例如:
- GET http://localhost:8080/order?orderNo=202201010001
- POST http://localhost:8080/order
测试成功后,就可以使用按月分表的方式来快速的拆分大量的订单数据了。
示例
下面是两个示例:
示例1
假设当前时间为2022年1月,我们要添加一个订单,订单创建时间为2022年1月3日,订单号为202201030001。发送POST请求如下:
POST http://localhost:8080/order
Content-Type: application/json
{
"orderNo": "202201030001",
"orderAmount": 200,
"createTime": "2022-01-03 00:00:00"
}
返回结果如下:
{
"id": 4,
"orderNo": "202201030001",
"orderAmount": 200.00,
"createTime": "2022-01-03T00:00:00.000+00:00"
}
在数据库中,会自动创建一张名为order_202201
的订单表,并且将该订单插入到该表中。
示例2
假设现在要查询订单号为202201010001
的订单,发送GET请求如下:
GET http://localhost:8080/order?orderNo=202201010001
返回结果如下:
[
{
"id": 1,
"orderNo": "202201010001",
"orderAmount": 100.00,
"createTime": "2022-01-01T10:10:10.000+00:00"
}
]
在查询时,程序会根据订单创建时间来确定使用哪张表,例如该订单创建时间为2022年1月1日,所以会查询order_202201
表,并返回查询结果。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:springboot 按月分表的实现方式 - Python技术站