分表与分库¶
分表¶
分表通常也被称为散表。 当某张表的数据量很大时,sql执行效率都会变低,这时通常会把大表拆分成多个小表,以提高sql执行效率。
快速分表¶
先来看一段分表的代码:
@DB(table = "user", tablePartition = IntegerModTenTablePartition.class)
public interface UserDao {
@SQL("insert into #table(uid, name) values(:1, :2)")
public void addUser(@TableShardBy int uid, String name);
@SQL("select uid, name from #table where uid = :1")
public User getUser(@TableShardBy int uid);
}
上面的代码实现了所有的分表逻辑,以上面的代码为例,总结一下实现分表的三个步骤:
- 填写@DB注解中的table参数,这个参数将启用 全局表名,上面代码的全局表名是user
- 填写@DB注解中的tablePartition参数,这个参数的作用是定义分表策略,上面代码使用了mango内部提供的IntegerModTenTablePartition,表明对输入参数进行模十分表
- 使用 @TableShardBy 注解指定对分表策略传入的参数,上面的代码会将uid作为参数传递给第2步中的分表策略。需要注意的是IntegerModTenTablePartition分表策略只支持Integer或int类型的参数。
以调用 userDao.getUser(88) 为例,最后被执行的sql为 select uid, name from user_8 where uid = 88 。
下面是mango框架内部提供的8种分表策略:
- 整数模十分表,支持Integer或int参数类型,实现类为 IntegerModTenTablePartition
- 长整模十分表,支持Long或long参数类型,实现类为 LongModTenTablePartition
- 字符串模十分表,支持String参数类型,实现类为 StringModTenTablePartition
- 模十分表,支持Integer或int或Long或long或String参数类型,实现类为 ModTenTablePartition
- 整数模百分表,支持Integer或int参数类型,实现类为 IntegerModHundredTablePartition
- 长整模百分表,支持Long或long参数类型,实现类为 LongModHundredTablePartition
- 字符串模百分表,支持String参数类型,实现类为 StringModHundredTablePartition
- 模百分表,支持Integer或int或Long或long或String参数类型,实现类为 ModHundredTablePartition
自定义分表¶
mango框架内部提供的8种分表策略,但这并不能满足所有要求,当我们需要其他的分表策略时,我们就需要自定义分表策略类。
分表策略类通过@DB注解中的tablePartition参数传入,tablePartition参数接受任何实现了 TablePartition 接口的类,所以我们可以通过自己实现TablePartition接口,来完成任何自定义分表策略。
我们先来看一下TablePartition接口的定义:
public interface TablePartition<T> {
public String getPartitionedTable(String table, T shardParam, int type);
}
TablePartition接口非常简单,只有一个getPartitionedTable方法,其中:
- 输入参数table,对应的是全局表名
- 输入参数shardParam,接收被@TableShardBy注解修饰的参数,shardParam的类型是泛型,将由实现类确定具体类型
- 输入参数type,接收@TableShardBy注解中的type参数,该参数用于复杂的分表策略
- 输出则为真正的表名
我们来实现一个简单的模五分表策略:
public class ModFiveTablePartition implements TablePartition<Integer> {
@Override
public String getPartitionedTable(String table, Integer shardParam, int type) {
return table + "_" + (shardParam % 5);
}
}
如果我们用这个自定义的分表策略ModFiveTablePartition替换之前的ModTenTablePartition,再次调用 userDao.getUser(88),最后被执行的sql将变为 select uid, name from user_3 where uid = 88 。
分库¶
分库通常也被称为散库,数据源路由等。 当我们在某个库中,把某张大表拆分成多个小表后还不能满足性能要求,这时我们需要把一部分拆分的表挪到另外一个库中,以提高sql执行效率。
先来看一段分库的代码:
@DB(table = "user", dataSourceRouter = MyDataSourceRouter.class)
public interface DataSourceRouterUserDao {
@SQL("insert into #table(uid, name) values(:1, :2)")
public void addUser(@DataSourceShardBy int uid, String name);
@SQL("select uid, name from #table where uid = :1")
public User getUser(@DataSourceShardBy int uid);
}
上面的代码实现了所有的分库逻辑,以上面的代码为例,总结一下实现分表的三个步骤:
- 填写@DB注解中的table参数,这个参数将启用 全局表名,上面代码的全局表名是user
- 填写@DB注解中的dataSourceRouter参数,这个参数的作用是定义分库策略,上面代码使用了自定义分库策略MyDataSourceRouter
- 使用 @DataSourceShardBy 注解指定对分库策略传入的参数,上面的代码会将uid作为参数传递给第2步中的分库策略。
@DB注解中的dataSourceRouter参数接受任何实现了 DataSourceRouter 接口的类。 我们来看一下DataSourceRouter接口的定义:
public interface DataSourceRouter<T> {
public String getDataSourceName(T shardParam, int type);
}
DataSourceRouter接口也非常简单,只有一个getDataSourceName方法,其中:
- 输入参数shardParam,接收被@DataSourceShardBy注解修饰的参数,shardParam的类型是泛型,将由实现类确定具体类型
- 输出则为要访问的数据源名称,这里需要用到 多数据源 的相关知识
最后来看MyDataSourceRouter分库策略:
public class MyDataSourceRouter implements DataSourceRouter<Integer> {
@Override
public String getDataSourceName(Integer shardParam, int type) {
return shardParam % 10 < 5 ? "datasource1" : "datasource2";
}
}
上面的代码中,如果uid尾号为0-4的用户将使用datasource1数据源,uid尾号为5-9的用户将使用datasource2数据源。
混合使用分库分表¶
我们将上面的分库与分表策略一起使用,形成混合使用分库分表的代码:
@DB(
table = "user",
dataSourceRouter = MyDataSourceRouter.class,
tablePartition = IntegerModTenTablePartition.class
)
public interface UserDao {
@SQL("insert into #table(uid, name) values(:1, :2)")
public void addUser(@DataSourceShardBy @TableShardBy int uid, String name);
@SQL("select uid, name from #table where uid = :1")
public User getUser(@DataSourceShardBy @TableShardBy int uid);
}
上面的代码中,分库策略使用了自定义的MyDataSourceRouter,分表策略则使用了IntegerModTenTablePartition模十分表。
组合分库加分表策略得到如下规则:
uid尾号为0,1,2,3,4的用户将使用datasource1数据源中对应的user_0,user_1,user_2,user_3,user_4表,uid尾号为5,6,7,8,9的用户将使用datasource2数据源中对应的user_5,user_6,user_7,user_8,user_9表。
@ShardBy注解¶
一般情况下,分库分表都使用一个参数,如上面的UserDao,使用uid进行分库与分表。在uid上使用@DataSourceShardBy,@TableShardBy两个注解显得不够简洁,所以mango框架引入了@ShardBy注解。
@ShardBy=@DataSourceShardBy+@TableShardBy,所以上面的UserDao可以简化为如下代码:
@DB(
table = "user",
dataSourceRouter = MyDataSourceRouter.class,
tablePartition = IntegerModTenTablePartition.class
)
public interface User2Dao {
@SQL("insert into #table(uid, name) values(:1, :2)")
public void addUser(@ShardBy int uid, String name);
@SQL("select uid, name from #table where uid = :1")
public User getUser(@ShardBy int uid);
}
查看完整示例代码¶
和 分表与分库 相关的所有代码均可以在 mango-example 中找到。