mango的中文名是“芒果”,它是一个轻量级极速数据层访问框架。并不是mongodb数据库。不同于mycat的庞大,mango能轻松轻量级的实现业务需求上的分表分表策略
github项目地址:https://github.com/jfaster/mango
项目开发文档:http://mango.jfaster.org/quickstart.html
下面是mango的一些特性:
我们使用由甲骨文JVM性能团队提供的工具 JMH 对mybatis,spring-jdbc,mango和直接使用jdbc进行了性能测试。您可以checkout性能测试源码 mango-benchmark 查看测试细节并自行运行获得测试结果。
表分片通常也被称为分表,散表。 当某张表的数据量很大时,sql执行效率都会变低,这时通常会把大表拆分成多个小表,以提高sql执行效率。 我们将这种大表拆分成多个小表的策略称之为表分片。
先来看一段mango框架中表分片的代码:
@DB(table = "t_order")
@Sharding(tableShardingStrategy = TableShardingOrderDao.OrderTableShardingStrategy.class)
public interface TableShardingOrderDao {
@SQL("insert into #table(id, uid, price, status) values(:id, :uid, :price, :status)")
public void addOrder(@TableShardingBy("uid") Order order);
@SQL("select id, uid, price, status from #table where uid = :1")
public ListgetOrdersByUid(@TableShardingBy int uid);
class OrderTableShardingStrategy implements TableShardingStrategy{
@Override
public String getTargetTable(String table, Integer shardingParameter) {
return table + "_" + (shardingParameter % 2);
}
}
}
上面的代码实现了所有的表分片逻辑,以上面的代码为例,总结一下mango框架实现表分片的3个步骤:
上面的3个步骤步中,最核心的是第2步中的表分片策略。mango框架使用@Sharding注解中的tableShardingStrategy参数来指定表分片策略,tableShardingStrategy参数接受任何实现了 TableShardingStrategy 接口的类。
我们来看一下TableShardingStrategy接口的定义:
public interface TableShardingStrategy{
public String getTargetTable(String table, T shardingParameter);
}
TableShardingStrategy接口非常简单,只有一个getTargetTable方法,其中:
以上面的OrderTableShardingStrategy表分片策略为例:
数据库分片通常也被称为分库,散库等。 当我们在某个库中,把某张大表拆分成多个小表后还不能满足性能要求,这时我们需要把一部分拆分的表挪到另外一个库中,以提高sql执行效率。
先来看一段mango框架中数据库分片的代码:
@DB()
@Sharding(databaseShardingStrategy = DatabaseShardingOrderDao.OrderDatabaseShardingStrategy.class)
public interface DatabaseShardingOrderDao {
@SQL("insert into t_order(id, uid, price, status) values(:id, :uid, :price, :status)")
public void addOrder(@DatabaseShardingBy("uid") Order order);
@SQL("select id, uid, price, status from t_order where uid = :1")
public ListgetOrdersByUid(@DatabaseShardingBy int uid);
class OrderDatabaseShardingStrategy implements DatabaseShardingStrategy{
@Override
public String getDatabase(Integer shardingParameter) {
return shardingParameter < 1000 ? "db1" : "db2";
}
}
}
上面的代码实现了所有的数据库分片逻辑,以上面的代码为例,总结一下mango框架实现数据库分片的2个步骤:
上面的2个步骤步中,最核心的是第1步中的数据库分片策略。mango框架使用@Sharding注解中的databaseShardingStrategy参数来指定数据库分片策略,databaseShardingStrategy参数接受任何实现了 DatabaseShardingStrategy 接口的类。
我们来看一下DatabaseShardingStrategy接口的定义:
public interface DatabaseShardingStrategy{
public String getDatabase(T shardingParameter);
}
DatabaseShardingStrategy接口非常简单,只有一个getDatabase方法,其中:
以上面的OrderDatabaseShardingStrategy数据库分片策略为例:
我们将上面的数据库分片策略与表分片策略一起使用,形成同时使用数据库分片与表分片的代码:
@DB(table = "t_order")
@Sharding(
databaseShardingStrategy = ShardingOrderDao.OrderDatabaseShardingStrategy.class,
tableShardingStrategy = ShardingOrderDao.OrderTableShardingStrategy.class
)
public interface ShardingOrderDao {
@SQL("insert into #table(id, uid, price, status) values(:id, :uid, :price, :status)")
public void addOrder(@DatabaseShardingBy("uid") @TableShardingBy("uid") Order order);
@SQL("select id, uid, price, status from #table where uid = :1")
public ListgetOrdersByUid(@DatabaseShardingBy @TableShardingBy int uid);
class OrderDatabaseShardingStrategy implements DatabaseShardingStrategy{
@Override
public String getDatabase(Integer uid) {
return uid < 1000 ? "db1" : "db2";
}
}
class OrderTableShardingStrategy implements TableShardingStrategy{
@Override
public String getTargetTable(String table, Integer uid) {
return table + "_" + (uid % 2);
}
}
}
上面的代码中,数据库分片策略使用了OrderDatabaseShardingStrategy,即uid小于1000时使用的database为db1,uid大于等于1000时使用的database为db2。 表分片策略则使用了OrderTableShardingStrategy,即uid为偶数时使用t_order_0表,uid为奇数时使用t_order_1表。
组合数据库分片策略与表分片策略得到如下规则:
下面的代码同样实现了同时使用数据库分片与表分片,不过更加简洁。
@DB(table = "t_order")
@Sharding(shardingStrategy = ShardingOrder2Dao.OrderShardingStrategy.class)
public interface ShardingOrder2Dao {
@SQL("insert into #table(id, uid, price, status) values(:id, :uid, :price, :status)")
public void addOrder(@ShardingBy("uid") Order order);
@SQL("select id, uid, price, status from #table where uid = :1")
public ListgetOrdersByUid(@ShardingBy int uid);
class OrderShardingStrategy implements ShardingStrategy {
@Override
public String getDatabase(Integer uid) {
return uid < 1000 ? "db1" : "db2";
}
@Override
public String getTargetTable(String table, Integer uid) {
return table + "_" + (uid % 2);
}
}
}
上面的代码中,引入了@ShardingBy注解,@ShardBy=@DataSourceShardBy+@TableShardBy。
上面的所有的代码我们都使用uid作为分片策略的计算参数,我们称之为一维分片策略。
考虑下面一个问题,当我们把数据库分片信息与表分片信息保存到order表中id字段的头部时,我们不但能把uid作为分片策略的计算参数,也能把id作为分片策略的计算参数。但@Sharding注解放在类上时,我们只能要么选择uid作为分片策略的计算参数,要们选择id作为分片策略的计算参数。这时我们需要将@Sharding注解下移到方法上,不同的方法指定不同的分片策略,实现多维度分片策略。
请看下面的代码:
@DB(table = "t_order")
public interface ShardingOrder3Dao {
@SQL("insert into #table(id, uid, price, status) values(:id, :uid, :price, :status)")
@Sharding(shardingStrategy = ShardingOrder3Dao.OrderUidShardingStrategy.class)
public void addOrder(@ShardingBy("uid") Order order);
@SQL("select id, uid, price, status from #table where uid = :1")
@Sharding(shardingStrategy = ShardingOrder3Dao.OrderUidShardingStrategy.class)
public ListgetOrdersByUid(@ShardingBy int uid);
@SQL("select id, uid, price, status from #table where id = :1")
@Sharding(shardingStrategy = OrderIdShardingStrategy.class)
public Order getOrderById(@ShardingBy String id);
class OrderUidShardingStrategy implements ShardingStrategy {
@Override
public String getDatabase(Integer uid) {
return uid < 1000 ? "db1" : "db2";
}
@Override
public String getTargetTable(String table, Integer uid) {
return table + "_" + (uid % 2);
}
}
class OrderIdShardingStrategy implements ShardingStrategy {
@Override
public String getDatabase(String orderId) {
return "db" + orderId.substring(0, 1);
}
@Override
public String getTargetTable(String table, String orderId) {
return table + "_" + orderId.substring(1, 2);
}
}
}
上面的代码中,addOrder(@ShardingBy("uid") Order order) 方法与 getOrdersByUid(@ShardingBy int uid) 方法使用了以uid作为参数的分片策略OrderUidShardingStrategy,而 getOrderById(@ShardingBy String id) 方法则使用了以id作为参数的分片策略OrderIdShardingStrategy。