最近逛论坛发现了一个轻量级极速数据层访问框架--mango。能够实现分表分库,功能还算比较强大。据官网介绍,
mango的中文名是“芒果”,它是一个轻量级极速数据层访问框架。目前已有十多个大型线上项目在使用mango,在某一支付系统中,更是利用mango,承载了每秒12万的支付下单请求。
下面是mango的一些特性:
- 超高性能,响应速度接近直接使用JDBC
- 采用接口与注解的形式定义DAO,完美结合db与cache操作
- 支持动态sql,可以构造任意复杂的sql语句
- 支持多数据源,分表,分库,事务
- 内嵌“函数式调用”功能,能将任意复杂的对象,映射到数据库的表中
- 高效详细的log统计,方便开发者随时了解自己的系统
- 独立jar包,不依赖其它jar包
- 提供便捷的spring插件,与spring无缝集成
性能相关
据官方称,测试下来效率和mybatis,spring-jdbc等不相上下。
代码实践
- 1.新建表fruit,user_0,user_1,user_2,user_3
SET NAMES utf8;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for `fruit`
-- ----------------------------
DROP TABLE IF EXISTS `fruit`;
CREATE TABLE `fruit` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL,
`num` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
SET FOREIGN_KEY_CHECKS = 1;
/*==========分割线============*/
CREATE TABLE `user_0` (
`uid` int(11) NOT NULL,
`name` varchar(20) NOT NULL,
PRIMARY KEY (`uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `user_1` (
`uid` int(11) NOT NULL,
`name` varchar(20) NOT NULL,
PRIMARY KEY (`uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `user_2` (
`uid` int(11) NOT NULL,
`name` varchar(20) NOT NULL,
PRIMARY KEY (`uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `user_3` (
`uid` int(11) NOT NULL,
`name` varchar(20) NOT NULL,
PRIMARY KEY (`uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; - 2.新建maven工程,并引入依赖。
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jfaster</groupId>
<artifactId>mango</artifactId>
<version>1.3.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.18</version>
</dependency> - 3.新建操作表对应等Dao类和分表相关类。
分表通常也被称为散表。 当某张表的数据量很大时,sql执行效率都会变低,这时通常会把大表拆分成多个小表,以提高sql执行效率。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
我们这次使用自定义分表,根据uid取模,可以分为4个分表。
分表策略类通过@DB注解中的tablePartition参数传入,tablePartition参数接受任何实现了 TablePartition 接口的类,所以我们可以通过自己实现TablePartition接口,来完成任何自定义分表策略。
下面是我们的自定义分表:
package com.wdzj.mongo.util;
import org.jfaster.mango.partition.TablePartition;
/**
* 整数模4分表
* @author lichaoqiang
* @date 2016-06-22
* */
public class ModFourTablePartition implements TablePartition<Integer> {
public String getPartitionedTable(String table, Integer shardParam, int type) {
// TODO Auto-generated method stub
return table + "_" + (shardParam % 4);
}
}
下面是操作数据库的DAO类,均采用注解。
package com.wdzj.mongo.dao;
import org.jfaster.mango.annotation.DB;
import org.jfaster.mango.annotation.SQL;
/**
* 表fruit的操作DAO,均使用注解方式来实现
*
* */
public interface FruitDao {
// 插入数据
public void add(String name, int num);
// 根据name取num的总和
public int getTotalNum(String name);
// 删除数据
public int deleteFruit(int id);
}
//==================================
package com.wdzj.mongo.dao;
import org.jfaster.mango.annotation.DB;
import org.jfaster.mango.annotation.SQL;
import org.jfaster.mango.annotation.TableShardBy;
import com.wdzj.mongo.model.User;
import com.wdzj.mongo.util.ModFourTablePartition;
public interface UserDao {
public void addUser(int uid, String name) ;
public User getUser(int uid) ;
}
- 4.测试
package com.wdzj.mongo.example;
查看相关分表中测试的数据发现插入表是根据取模策略离散的,这个对于大量数据的表业务做分表有很大的参考意义。
import org.jfaster.mango.operator.Mango;
import com.wdzj.mongo.dao.FruitDao;
import com.wdzj.mongo.util.MangoDBUtils;
public class TestFruit {
public static void main(String[] args) {
// TODO Auto-generated method stub
//数据库连接方式一
// String driverClassName = "com.mysql.jdbc.Driver";
// String url = "jdbc:mysql://192.168.29.1:3306/mongo_demo";
// String username = "root"; // 这里请使用您自己的用户名
// String password = "root"; // 这里请使用您自己的密码
// DataSource ds = new DriverManagerDataSource(driverClassName, url, username, password);
// Mango mango = Mango.newInstance(ds); // 使用数据源初始化mango
//数据库连接方式二,自己封装好
Mango mango =MangoDBUtils.getMango();
FruitDao dao = mango.create(FruitDao.class);
String name = "pear";
int num = 3;
dao.add(name, num);
System.out.println(dao.getTotalNum(name));
}
}
//=======================分表测试
package com.wdzj.mongo.example;
import org.jfaster.mango.operator.Mango;
import com.wdzj.mongo.dao.UserDao;
import com.wdzj.mongo.util.MangoDBUtils;
/**
* 测试分表
* */
public class TestUserSplitTable {
public static void main(String[] args) {
// TODO Auto-generated method stub
testAddUser();
System.out.println("add user ended................");
testGetUser();
}
public static void testAddUser(){
Mango mango =MangoDBUtils.getMango();
UserDao dao = mango.create(UserDao.class);
for(int i=0;i<10;i++){
dao.addUser(i, "张三"+i);
}
}
public static void testGetUser(){
Mango mango =MangoDBUtils.getMango();
UserDao dao = mango.create(UserDao.class);
for(int i=0;i<10;i++){
System.out.println(dao.getUser(i));
}
}
}
具体的demo代码可以在github源码上看到。
还有很多有意思的功能等着去探索,后面更多实践后,再写点东西吧。