项目需要同事访问多个库,如何配置多数据源,并支持多数据源的读写分离
有两个办法: 加个src/main/resources/ioc/dao2.js 或者 写个MyBeans
package io.nutz.demo.simple;
import javax.sql.DataSource;
import org.nutz.dao.Dao;
import org.nutz.dao.impl.NutDao;
import org.nutz.ioc.impl.PropertiesProxy;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import com.alibaba.druid.pool.DruidDataSource;
@IocBean
public class MyBeans {
@Inject
protected PropertiesProxy conf;
@IocBean
public Dao dao2(@Inject DataSource dataSource2) {
return new NutDao(dataSource2);
}
@IocBean
public DataSource dataSource2(@Inject DataSource dataSource2) {
return conf.make(DruidDataSource.class, "jdbc2.");
}
}
把 dataSource2方法里的@Inject DataSource dataSource2参数去掉就可以了
@wendal 今天在继续使用这个方法引入其它数据源,发现貌似没有识别主从
我跟了DataSourceStarter类的getSlaveDataSource方法,发现传进来的prefix始终为:jdbc.slave,所以匹配不上slave
我自己定义如下:
@IocBean
public class MyBeans {
@Inject
protected PropertiesProxy conf;
@IocBean
public Dao daoPlay(@Inject DataSource dataSourcePlay) {
return new NutDao(dataSourcePlay);
}
@IocBean
public DataSource dataSourcePlay() {
return conf.make(DruidDataSource.class, "jdbc.play.");
}
}
配置文件为:
jdbc.play.type=druid
jdbc.play.url=jdbc:mysql://192.168.0.11:13306/
jdbc.play.username=play
jdbc.play.password=oj%w9DB$cu&$5yv^
jdbc.play.validationQuery=select 1;
jdbc.play.slave.A.url=jdbc:mysql://192.168.0.12:13306/
jdbc.play.slave.A.username=play
jdbc.play.slave.A.password=oj%w9DB$cu&$5yv^
jdbc.slave.A.validationQuery=select 1;
看了下nutzboot的NutDaoStarter源码,其中自动注入了jdbc.slave的从库
// 看看是不是需要注入从数据库
if (Lang.loadClassQuite("org.nutz.boot.starter.jdbc.DataSourceStarter") != null) {
DataSource slaveDataSource = DataSourceStarter.getSlaveDataSource(ioc, conf, "jdbc.slave.");
if (slaveDataSource != null) {
NutDaoRunner runner = new NutDaoRunner();
runner.setSlaveDataSource(slaveDataSource);
dao.setRunner(runner);
}
}
感觉这个地方是不需要改,也不能改,因为无法拿到另外注入的dao对象和prefix,所以感觉要从nutz的dao对象入手改造,我在想是不是可以给dao对象重载一个方法来进行从库的加载
NutDaoRunner runner = new NutDaoRunner();
runner.setSlaveDataSource(slaveDataSource);
dao.setRunner(runner);
不需要重载吧, 这段代码不就是设置从数据库了?
是的,我刚刚又再深入看了下 DataSourceStarter.getSlaveDataSource 方法实现了多从库的灵活调度,所以看来还是得在nb上想办法扩展,但暂时想不到怎么扩展,还是基础不够扎实,尴尬
我现在能想到的是把NutDaoStarter另外封装一个类出来,然后构造函数留一个prefix参数,类继承自NutDao,然后这样注入:
@Inject
public NutDao daoPlay() {
return new NutDaoCustom("jdbc.play.");
}
@Inject
public NutDao daoNews() {
return new NutDaoCustom("jdbc.news.");
}
如果是这样,我觉得可以形成一个配置规范;
比如:jdbc.{dbname}.url 主库
jdbc.{dbname}.slave.A.url 从库
jdbc.{dbname}.slave.B.url 从库
然后NutDaoStarter在加载时,自动扫描conf内所有{dbname},然后根据{dbname}注入所有db,且注入名直接就是{dbname}Dao
假设{dbname}有:play、news等, 那么使用时就直接:
@Inject
public Dao playDao;
@Inject
public Dao newsDao;
不知道是否可行
顺带可以把我的 https://nutz.cn/yvr/t/u8boo9deokhnkqig232cmkfk7i 写个新的RedisStarter,再结合 DynaDataSourceSeletor 实现一个选择器,就可以完成多组redis主从配置了
@wendal 请教下,下面这个拦截器我可以统一设置到每一个不通库的dao上吗?会不会有冲突
NutDao dao = new NutDao(dataSource, sqlManager);
List<Object> interceptors = new ArrayList<>();
// 是否启用了DaoCache呢?
if (conf.getBoolean(PROP_INTERCEPTOR_CACHE_ENABLE, false)) {
interceptors.add(ioc.get(DaoCacheInterceptor.class));
}
// 日志拦截器
if (conf.getBoolean(PROP_INTERCEPTOR_LOG_ENABLE, true)) {
interceptors.add("log");
}
// sql耗时拦截器
if (conf.getBoolean(PROP_INTERCEPTOR_TIME_ENABLE, true)) {
interceptors.add("time");
}
@wendal 我先简单实现了一版,已经PR了,你帮忙看看,给点建议