jboot的动态配置数据源

阅读更多
Jboot通过ShardingJDBC实现分库分表,但是分库分表函数主要是通过字段值进行计算,但如果分库方式与数据无关,并且分库需要在运行时动态新增配置就无法满足要求。
下面是通过改造基本Model类,并动态配置数据源的方法:

1、新增数据源缓存类
   注意,configName要使用线程本地类,JBoot非线程安全。
public class DataConfigName {
    private static DataConfigName me;
    @JSONField(serialize = false)
    transient private ThreadLocal configName = new ThreadLocal<>();

    private DataConfigName(){}

    public static DataConfigName getInstance(){
        if(me == null){
            me = new DataConfigName();
        }
        return me;
    }

    public void setConfigName(String name){
        configName.set(name);
    }

    public String getConfigName(){
        String name = configName.get();
        if(null == name){
            name = DbKit.MAIN_CONFIG_NAME;
        }
        return name;
    }
}


2、修改Model基础类
   JBoot操作数据库主要通过Model来实现,框架提供了基础类JBootModel,需要对这个类进行扩展,覆盖所有方法,如下所示,方法中都增加了use子句,实现数据源的切换,否则会使用默认数据源:
public class GlueModel> extends JbootModel {
    public GlueModel(){};
    ……
    

    public M use(String configName) {
        return super.use(configName);
    }

    M superUse(String configName) {
        return super.use(configName);
    }

    public boolean saveOrUpdate() {
        this.use(DataConfigName.getInstance().getConfigName());
        return super.saveOrUpdate();
    }

    public boolean save() {
        this.use(DataConfigName.getInstance().getConfigName());
        return super.save();
    }
    ……
}


3、替换所有Db类的操作,增加use子句,如:
public class TransactionModel extends GlueModel {

    ……

    public static TransactionModel getByTno(String tno){
        ……
        Record record = Db.use(DataConfigName.getInstance().getConfigName()).findFirst(sql);
        ……
    }
    ……
}


4、创建一个数据源动态管理类。
Jboot虽然在2.1.2版本的DataSourceConfigManager类中开放了addConfig方法,但由于Db类是属于JFinal框架的,无法影响到,因此需要调用JFinal的DbKit的addConfig方法完成数据源的新增。
下面的代码只提供了从默认数据库获取数据源配置参数的实现方式,如果需要通过本地配置文件、网络文件等方式,可参考自行添加
public class DynamicDataSourceManager {
    /**
     * 从数据库获取数据源配置参数
     * @param tableName
     * @param corpId
     * @return
     */
    public static Config loadConfigFromDB(String tableName, String corpId){
        Config config = DbKit.getConfig(corpId);
        if(null == config) {
            SqlPara sql = new SqlPara();
            sql.setSql("select * from " + tableName + " where corpid=?").addPara(corpId);
            List records = Db.find(sql);
            if (null != records && records.size()>0) {
                Record record = records.get(0);
                DataSourceConfig dataSourceConfig = new DataSourceConfig();
                dataSourceConfig.setName(record.getStr("corpid"));
                dataSourceConfig.setType(DataSourceConfig.TYPE_MYSQL);
                dataSourceConfig.setDriverClassName("com.mysql.cj.jdbc.Driver");
                dataSourceConfig.setUrl("jdbc:mysql://"
                        + record.getStr("write_host")
                        + ":" + record.getStr("write_port")
                        + "/"
                        + record.getStr("write_database")
                        + "?useUnicode=true&characterEncoding="
                        + record.getStr("charset")
                        + "&useSSL=false");
                dataSourceConfig.setUser(record.getStr("write_username"));
                dataSourceConfig.setPassword(record.getStr("write_password"));
                dataSourceConfig.setPoolName(record.getStr("write_database"));

                DataSource dataSource = new DataSourceBuilder(dataSourceConfig).build();

                config = new Config(
                        record.getStr("corpid"),
                        dataSource,
                        new MysqlDialect(),
                        false,
                        false,
                        DbKit.DEFAULT_TRANSACTION_LEVEL,
                        IContainerFactory.defaultContainerFactory,
                        new EhCache()
                );
                DbKit.addConfig(config);
            }
        }
        return config;
    }
}


5、在切片方法或入口方法中实现数据源的配置
    ……
    if(null != corpId){
        Config config = DynamicDataSourceManager.loadConfigFromDB("corp_database", corpId);
        if(null != config) {
            DataConfigName.getInstance().setConfigName(corpId);
        }
     }
    ……


通过上述修改即可完成动态分库处理,实际的Model中无需再做任何特殊处理。

你可能感兴趣的:(java)