🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## 业务主从库 SQLManager使用数据源,如果只提供一个数据源,则认为读写均操作此数据源,如果提供多个,则默认第一个为写库,其他为读库。用户在开发代码的时候,无需关心操作的是哪个数据库,因为调用SQLMnager 的 select相关api的时候,总是去读取从库,add/update/delete 的时候,总是读取主库(如下是主从实现原理,大部分情况下无需关心如何实现) ```java sqlManager.insert(User.class,user) // 操作主库,如果只配置了一个数据源,则无所谓主从 sqlManager.unique(id,User.class) //读取从库 ``` 主从库的逻辑是由ConnectionSource来决定的,如下DefaultConnectionSource 的逻辑 ```java @Override public Connection getConn(ExecuteContext ctx,boolean isUpdate){ if(this.slaves==null||this.slaves.length==0) return this.getWriteConn(ctx); if(isUpdate) return this.getWriteConn(ctx); else return this.getReadConn(ctx); } ``` 如果你有一主多从数据源,可以通过ConnectionSourceHelper 构造一个支持主从的ConnectionSource(不同的框架,BeetlSQL提供了不通的构造方式,ConnectionSourceHelper可以作为一个示例使用) ```java //为了简单起见,主从库都走同一个数据库 DataSource master = SampleHelper.datasource(); DataSource slave1 = SampleHelper.datasource(); DataSource slave2 = SampleHelper.datasource(); //一主二从 ConnectionSource source = ConnectionSourceHelper.getMasterSlave(master,new DataSource[]{slave1,slave2}); SQLManagerBuilder builder = new SQLManagerBuilder(source); builder.setNc(new UnderlinedNameConversion()); builder.setInters(new Interceptor[]{new DebugInterceptor()}); builder.setDbStyle(new MySqlStyle()); SQLManager sqlManager = builder.build(); ``` 如果你是Spring或者SpringBoot框架,则可以简单指定多个数据源,以SpringBoot为例子 ```properties beetlsql = sqlManager1 beetlsql.sqlManager1.ds=ds1,salve1,salve2 beetlsql.sqlManager1.basePackage=org.beetl.sql.springboot.simple ``` 这里ds1和slave1,slave2 是数据源的名称。 如果是Spring,配置如下: ```xml <bean id="sqlManagerFactoryBean" class="org.beetl.sql.ext.spring.SqlManagerFactoryBean"> <property name="cs" > <bean class="org.beetl.sql.ext.spring.SpringConnectionSource"> <property name="masterSource" ref="dataSource-master"></property> <property name="slaveSource"> <list> <ref bean="dataSource-slave-1"></ref> <ref bean="dataSource-slave-2"></ref> </list> </property> </bean> </property> <!-- 其他配置 --> </bean> ``` 对于不同的ConnectionSource 完成逻辑不一样,对于spring,jfinal这样的框架,如果sqlManager在事务环境里,总是操作主数据库,无论是否是读写操作,考虑到主从复制的延迟,这样有利于保持数据一致性。如果是只读事务环境 则才会操作从数据库。如果没有事务环境,则根据sql是查询还是更新来决定。 如下是SpringConnectionSource 提供的主从逻辑 ```java @Override public Connection getConn(ExecuteContext ctx, boolean isUpdate){ if (this.slaves == null || this.slaves.length == 0) return this.getWriteConn(ctx); //如果是更新语句,也得走master if (isUpdate){ return this.getWriteConn(ctx); } //在事物里都用master,除了readonly事物 boolean inTrans = TransactionSynchronizationManager.isActualTransactionActive(); if (inTrans) { boolean isReadOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly(); if (!isReadOnly) { return this.getWriteConn(ctx); } } return this.getReadConn(ctx); } ``` 注意,对于使用者来说,无需关心上面说的细节,仅供要定制主从逻辑的架构师 > 1) 开发者可以自定义ConnectionSource来完成主从逻辑, > > 2)如果想强制某个操作从库,可以使用sqlManager.forceDataSource方法.