10、Sharding-JDBC 实战:如何解决根据ID更新时扫描全部分表

一、问题描述

我们在使用 ShardingJDBC 作为分片工具的时候,会在配置中指定分片键,例如根据 create_time 创建时间来按月分片是比较常用的操作。当分片表中需要根据主键 ID 来进行更新的时候,由于不确定数据的 create_time 具体是多少,ShardingJDBC 就会在选择使用分片表的时候,就会默认选择全部。如果涉及到事务就有可能会产生 锁表事务等待 等问题,从而导致数据库操作时间延长

二、问题解决

首先从逻辑上讲,在没有确定分片键值的情况下,确实没有办法只根据ID确定数据所在分表的位置。

但是俗话说,没有绝对的问题,只有相对的场景。我们要从场景入手,才能找到解决问题的办法。

所以,我们要先确认根据ID更新的使用场景:

1.场景一:同一事务中,新增并更新

例如:将数据插入到数据库中后,还需要使用数据库中生成的ID,来更新同一条数据的其他字段的话,就会涉及到根据主键更新扫描全部分表的问题。

1.1 解决方案:

由于是先新增后更新,那么我们程序中已经拿到了 set 好的 createTime 字段,所以我们在更新的时候,只需要在 where 中再添加一下 create_time 的筛选条件就好了:

update t_user set user_no = id where id = ? and create_time = ?;

如果是数组的话,可以这样:

update t_user set user_no = id where id in (?, ?) and create_time in (?, ?);

这样就可以大大缩小操作分表的范围。


2.场景二:不同事务中,新增后更新场景

例如:在列表中编辑某一条数据的时候,就会涉及到根据主键更新扫描全部分表的问题。

2.1 解决方案:

  • 实现1: 在列表查询的时候就查询出创建时间,然后编辑的时候将创建时间和主键一起通过入参传回来。
  • 实现2: 在更新之前,先根据主键查询出数据的创建时间查询出来,由于查询不会进行锁表,也不需要事务等待,所以先查询,然后再根据查询出的创建时间和主键一起作为条件进行更新操作。

整理完毕,完结撒花~ 🌻