最近逛论坛发现了一个轻量级极速数据层访问框架--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,均使用注解方式来实现
*
* */
@DB
public interface FruitDao {
// 插入数据
@SQL("insert into fruit(name, num) values(:1, :2)")
public void add(String name, int num);

// 根据name取num的总和
@SQL("select sum(num) from fruit where name=:1")
public int getTotalNum(String name);

// 删除数据
@SQL("delete from fruit where name=:1")
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;

@DB(table = "user", tablePartition = ModFourTablePartition.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);
}

  • 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源码上看到。
    还有很多有意思的功能等着去探索,后面更多实践后,再写点东西吧。