背景
最近学习后端有一个需求,在设计聊天系统的数据库时需要将聊天记录以某种方式进行分表存储以提高性能。 通过学习康师傅的后台教学视频,掌握了单实体对应单表的Dao写法,案例如下
pojo实体类
@Entity
@Table(name = "table")
public class TestEntity {
@Id
@Column(name = "id")
private String id;
@Column(name = "attr")
private String attr;
// 其他属性以及getters和setters
}
如此,我们的Dao也许是下面这个样子的
Dao
public interface TestDao extends JpaRepository<TestEntity, String>, JpaSpecificationExecutor<TestEntity> {
@Query(nativeQuery = true, value = "select * from table where id = ?")
List<TestEntity> findAllById(String id);
@Query(nativeQuery = true, value = "select * from table where attr = ?")
TestEntity findOneByAttr(String attr);
}
单实体单表实现了那多表当然可以像下面的方式实现,假设我要分10表 那就是需要10个Entity,这样的话我的Dao也要一一对应,经过~~熟练的~~复制粘贴操作,区区10张表完全不在话下
但是看看(~~算了懒得贴图了,想象一下就好了~~)这些类里面的惨状,所有的代码一模一样,因为所有的表结构一模一样,接口也一模一样,实现也一模一样…… 然后分析前面的需求,这时候你需要按照用户id计算哈希取模分表存放这些聊天记录,然后你的代码将会是这样的
@Autowired
private MessageDao0 dao0;
@Autowired
private MessageDao1 dao1;
@Autowired
private MessageDao2 dao2;
@Autowired
private MessageDao3 dao3;
@Autowired
private MessageDao4 dao4;
@Autowired
private MessageDao5 dao5;
@Autowired
private MessageDao6 dao6;
@Autowired
private MessageDao7 dao7;
@Autowired
private MessageDao8 dao8;
@Autowired
private MessageDao9 dao9;
@Override
public ResponseResult saveOfflineMessage(String userID, Message message) {
int hashCode = userID.hashCode();
switch (hashCode % 10) {
case 0:
return dao0.saveOfflineMessage(userID, message);
case 1:
return dao1.saveOfflineMessage(userID, message);
case 2:
return dao2.saveOfflineMessage(userID, message);
case 3:
return dao3.saveOfflineMessage(userID, message);
case 4:
return dao4.saveOfflineMessage(userID, message);
case 5:
return dao5.saveOfflineMessage(userID, message);
case 6:
return dao6.saveOfflineMessage(userID, message);
case 7:
return dao7.saveOfflineMessage(userID, message);
case 8:
return dao8.saveOfflineMessage(userID, message);
case 9:
return dao9.saveOfflineMessage(userID, message);
default:
return ResponseResult.Failed();
}
}
~~硬生生将写代码这样神圣的智力劳动变成了体力劳动~~
复制粘贴这样的活再多也难不倒我们~~社畜~~
但是仅仅调用了一个接口就写了70行代码,也就是说如果我要调用其他接口也要一个个判断过去,虽然整齐划一的代码看着害挺舒服但是它影响了我的拔刀速度
并且,如果有更特殊的需求,要分20、30张表,或者,需要自动生成表来存放不同日期的,那这样的解决方案必须被pass掉了
解决方案
我们可以使用 @SecondaryTable
注解实体类来指定其他结构完全相同的表
修改后的pojo实体类
@Entity
@Table(name = "table0")
@SecondaryTables({
@SecondaryTable(name = "table1"),
@SecondaryTable(name = "table2"),
@SecondaryTable(name = "table3"),
@SecondaryTable(name = "table4"),
@SecondaryTable(name = "table5"),
@SecondaryTable(name = "table6"),
@SecondaryTable(name = "table7"),
@SecondaryTable(name = "table8"),
@SecondaryTable(name = "table9")
})
public class TestEntity {
@Id
@Column(name = "id")
private String id;
@Column(name = "attr")
private String attr;
// 其他属性以及getters和setters
}
这时候的Dao也只需要一个类即可
修改后的Dao
public interface TestDao extends JpaRepository<TestEntity, String>, JpaSpecificationExecutor<TestEntity> {
@Query(value = "select * from table?1 where id= ?2", nativeQuery = true)
TestEntity getOneById(int tableNum, String id);
@Query(value = "select * from table?1 where attr = ?2", nativeQuery = true)
List<TestEntity> getAllByAttr(int tableNum, String attr);
}
以上的 ?1
和 ?2
代表的是接口参数的占位符,后面的数字是几代表就是第几个参数,例如当传入的 tableNum
为0时即代表将在 table0
中进行查询操作,tableNum
为9时代表将在 table9
中进行查询操作
然后再来看我们的接口调用
@Autowired
private MessageDao messageDao;
@Override
public ResponseResult saveOfflineMessage(String userID, Message message) {
return messageDao.saveOfflineMessage(userID.hashCode() % 10, message);
}
~~从此告别复制粘贴的传统艺能,一劳永逸!~~
后端小白,如有错误,恳请各路大佬斧正