jfinal+sharding-jdbc实现数据分库,分表

工具及环境:idea 2016.2(非必须) 、jdk1.8、jfinal3.3 、sharding-jdbc 3.0.3

简介:JFinal 是基于 Java 语言的极速 WEB + ORM 框架,其核心设计目标是开发迅速、代码量少、学习简单、功能强大、轻量级、易扩展、Restful。在拥有Java语言所有优势的同时再拥有ruby、python、php等动态语言的开发效率!

        Sharding-JDBC 采用在 JDBC 协议层扩展分库分表,是一个以 jar 形式提供服务的轻量级组件,其核心思路是小而美地完成最核心的事情。

原理:通过自己构造jfinal的数据库plugin包装sharing-jdbc的datasource来,让sharding-jdbc来实现数据库的分表分库操作,从而简单实现欲达到的目的。

一、建立测试数据库环境。


1、建立数据库

create database sharding_0;  
create database sharding_1;

2、创建测试表

 

  SET FOREIGN_KEY_CHECKS=0;  
-- ----------------------------  
-- Table structure for t_user_0  
-- ----------------------------  
DROP TABLE IF EXISTS `t_user_0`;  
CREATE TABLE `t_user_0` (  
  `id` int(11) NOT NULL AUTO_INCREMENT,  
  `user_id` int(11) NOT NULL,  
  `name` varchar(255) NOT NULL,  
  `age` int(11) NOT NULL,  
  PRIMARY KEY (`id`)  
) ENGINE=InnoDB DEFAULT CHARSET=utf8;  
-- ----------------------------  
-- Table structure for t_user_1  
-- ----------------------------  
DROP TABLE IF EXISTS `t_user_1`;  
CREATE TABLE `t_user_1` (  
  `id` int(11) NOT NULL AUTO_INCREMENT,  
  `user_id` int(11) NOT NULL,  
  `name` varchar(255) NOT NULL,  
  `age` int(11) NOT NULL,  
  PRIMARY KEY (`id`)  
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;  
  
-- ----------------------------  
-- Table structure for t_user_02  
-- ----------------------------  
DROP TABLE IF EXISTS `t_user_2`;  
CREATE TABLE `t_user_2` (  
  `id` int(11) NOT NULL AUTO_INCREMENT,  
  `user_id` int(11) NOT NULL,  
  `name` varchar(255) NOT NULL,  
   `age` int(11) NOT NULL,  
  PRIMARY KEY (`id`)  
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

二、引入sharding-jdbc的jar包或者maven。本处使用maven

<dependency>
  <groupId>io.shardingjdbc</groupId>
  <artifactId>sharding-jdbc-core</artifactId>
  <version>2.0.3</version>
</dependency>


三、自定义ShardDrudPlugin类(基于drud数据库连接池的,其他数据库连接池类似)。

package cn.qcsy.framework.util;
import com.alibaba.druid.filter.Filter;
import com.alibaba.druid.pool.DruidDataSource;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.IPlugin;
import com.jfinal.plugin.activerecord.IDataSourceProvider;
import com.jfinal.plugin.druid.DruidPlugin;
import io.shardingjdbc.core.api.ShardingDataSourceFactory;
import io.shardingjdbc.core.api.config.ShardingRuleConfiguration;
import io.shardingjdbc.core.api.config.strategy.InlineShardingStrategyConfiguration;
 
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
 
/**
 * Description:自定义的sharding扩展类
 * Copyright: qcsy studio. All rights reserved.
 *
 * @author qcsy
 * @version 1.0
 * @timestamp 2018/4/3.
 */
public class ShardDrudPlugin implements IPlugin, IDataSourceProvider {
    //分表分库的rule
    ShardingRuleConfiguration shardingRuleConfiguration;
    //数据源map
    Map<String,DruidPlugin> druidPlugins;
    //原数据库连接源map
    Map<String,DataSource> dataSourceMap;
    //最终sharding-jdbc封装后的数据库连接源
    DataSource dataSource;
 
    public ShardDrudPlugin(ShardingRuleConfiguration shardingRuleConfiguration, Map<String, DruidPlugin> druidPlugins) {
        this.shardingRuleConfiguration = shardingRuleConfiguration;
        this.druidPlugins = druidPlugins;
        dataSourceMap=new HashMap<String, DataSource>();
    }
 
    public boolean start() {
        //遍历数据源 ,将数据源加入sharding jdbc
        for(Map.Entry<String,DruidPlugin> entry:druidPlugins.entrySet()){
            entry.getValue().start();
            dataSourceMap.put(entry.getKey(),entry.getValue().getDataSource());
        }
        try {
            //获得数据库连接类
            dataSource = ShardingDataSourceFactory.createDataSource(dataSourceMap,shardingRuleConfiguration, new ConcurrentHashMap(), new Properties());
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return true;
    }
 
    public boolean stop() {
        for(Map.Entry<String,DruidPlugin> entry:druidPlugins.entrySet()){
            entry.getValue().stop();
            dataSourceMap.put(entry.getKey(),entry.getValue().getDataSource());
        }
        return true;
    }
 
    public DataSource getDataSource() {
        return dataSource;
    }
}


四、配置jfinal的扩展信息

 /**
     * 配置Jfinal plugin扩展
     */
    public void configPlugin(Plugins me) {
        //-----------------配置测试库1--------------------------
 
        DruidPlugin source = new DruidPlugin(PropKit.use(CommonAttribute.DATA_BASE_CONFIG).get("jdbc.source.url"), PropKit.use(CommonAttribute.DATA_BASE_CONFIG).get("jdbc.source.user"), PropKit.use(CommonAttribute.DATA_BASE_CONFIG).get("jdbc.source.password").trim());
        String sourceDriverClass=PropKit.use(CommonAttribute.DATA_BASE_CONFIG).get("jdbc.source.driver","com.mysql.jdbc.Driver");
        source.setDriverClass(sourceDriverClass);
 
        //----------------- 配置目测试库2---------------
        DruidPlugin target = new DruidPlugin(PropKit.use(CommonAttribute.DATA_BASE_CONFIG).get("jdbc.target.url"), PropKit.use(CommonAttribute.DATA_BASE_CONFIG).get("jdbc.target.user"), PropKit.use(CommonAttribute.DATA_BASE_CONFIG).get("jdbc.target.password").trim());
        String targetDriverClass=PropKit.use(CommonAttribute.DATA_BASE_CONFIG).get("jdbc.target.driver","com.mysql.jdbc.Driver");
        target.setDriverClass(targetDriverClass);
 
 
        //------------------------测试分表分库------------------------------------
        Map<String,DruidPlugin> drudMap=new HashMap();
        drudMap.put("ds_0",source);
        drudMap.put("ds_1",source);
 
        // 配置Order表规则
        TableRuleConfiguration orderTableRuleConfig = new TableRuleConfiguration();
        // 关键逻辑表名,将与mappingkit中进行映射
        orderTableRuleConfig.setLogicTable("t_user");
        orderTableRuleConfig.setActualDataNodes("ds_${0..1}.t_user_${[0,1]}");
 
        // 配置分库策略
        orderTableRuleConfig.setDatabaseShardingStrategyConfig(new InlineShardingStrategyConfiguration("user_id", "ds_${user_id % 2}"));
 
        // 配置分表策略
        orderTableRuleConfig.setTableShardingStrategyConfig(new InlineShardingStrategyConfiguration("user_id", "t_user_${user_id % 2}"));
 
        // 配置规则
        ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
        shardingRuleConfig.getTableRuleConfigs().add(orderTableRuleConfig);
        //获得自定义的扩展
        ShardDrudPlugin drudPlugin=new ShardDrudPlugin(shardingRuleConfig,drudMap);
        me.add(drudPlugin);
        ActiveRecordPlugin targetARP = new ActiveRecordPlugin("target",drudPlugin);
        //配置数据库方言
        // targetARP.setDialect(DatabaseUtil.getDialectByDriverName(targetDriverClass));
        _MappingKit.mapping(targetARP);
        me.add(targetARP);
    }
    //mappingki中的映射,需映射逻辑表名
public class _MappingKit {
   
   public static void mapping(ActiveRecordPlugin arp) {
      arp.addMapping("t_user", "id", User01.class);
   }
}


五、测试

package cn.qcsy.framework.bizmodule.transport.controller;
 
import cn.qcsy.framework.bizmodule.transport.service.TransService;
import cn.qcsy.framework.model.User01;
import com.jfinal.core.Controller;
 
/**
 * Description:测试
 * Copyright: © 2017  CSTC. All rights reserved.
 *
 * @author qcsy
 * @version 1.0
 * @timestamp 2018/4/3.
 */
public class TestGetTrans extends Controller {
    //获取服务类
    private TransService transService=new TransService();
    public void getall(){
        User01 user01=new User01();
        user01.setId(2);
        user01.setUserId(2);
        user01.setName("4");
        user01.setAge(4);
        user01.save();
        renderJson("操作成功!");
    }
}


数据将会根据userid的模自动分库分表

 

--------------------------完----------------------------------

jfinal官网:http://www.jfinal.com/

sharding-jdbc:https://gitee.com/shardingjdbc/sharding-jdbc


评论区

lyh061619

2018-04-08 16:04

这个分享很不错,有实战考验了没?

JFinal

2018-04-08 16:55

有不少同学问过这个问题,正好有需要,感谢你的分享

秦城诗雨

2018-04-09 10:09

@lyh061619 暂时只是测试通过了,后期将在实际项目中应用,如果遇到问题,会同步更新本文

lyh061619

2018-04-09 10:10

@秦城诗雨 哈哈,不错不错,感谢分享的呢。

秦城诗雨

2018-04-09 10:15

@JFinal 嘿嘿,应该的,感谢你带来这么好的框架

wuxs

2018-04-10 16:53

CommonAttribute异常是缺少什么包吗 完全按照 你的环境配的

yjjdick1990

2018-04-12 18:14

点了赞再看,最近正在看这个

yjjdick1990

2018-04-12 18:15

@秦城诗雨 能加个好友吗交流一下QQ406123228

冰雨

2018-04-12 20:35

点赞收藏

秦城诗雨

2018-04-16 13:59

@wuxs 不好意思,最近都没逛论坛,现在才回复,CommonAttribute只是一个静态变量,你这个地方可以替换为一个字符串的,此处只是一个数据库use操作

秦城诗雨

2018-04-16 14:03

@yjjdick1990 我的邮箱qinchengshiyu@foxmail.com 看到邮件第一时间回复

秦城诗雨

2018-04-16 14:04

babbachuck

2018-04-17 14:10

@yjjdick1990 UZI也来敲代码了?哈哈

shmilyzero

2018-05-03 22:34

大神,我按照你的方式改了,但是貌似没有起到效果,没有从多个表里面查询。你的User01有什么特别的地方吗?

秦城诗雨

2018-05-06 14:28

@shmilyzero 我的User01没有什么特殊的地方,不过我的这个上面是保存,查询的话,可能要去看一下sharding-jdbc相关文档解决,因为这样封装以后,分表分库都交给sharding-jdbc管理了

maxwade

2018-05-27 09:30

查询的确可以从t_user_0和t_user_1两种不同的表查询出来,但为什么保存的时候默认保存到t_user_0表呢?

maxwade

2018-05-27 09:34

比如说,我现在需要根据name = 4来查询两张表的数据,应该如何处理呢?因为这时候表名不能写死了

localhost8080

2018-06-25 14:53

请问采用这种方案,实际项目中用了没?

秦城诗雨

2018-06-25 16:22

@maxwade 这个应该是跟sharding-jdbc分表策略有关,查询的时候直接查逻辑表名 而不是查两张表的实际表名

热门分享

扫码入社