不少人误以为 d2js 只能通过 database.js 指定一个数据库,是一个单数据库方案。实际上 d2js 也可以使用多个数据库。
在 WEB-INF/jslib/d2js/base.js 的末尾,是 dj2s 创建 DataSource 为 d2js 的 SqlExecutor 的主要代码:
D2JS.init = function(){ var datasource = application.datasource || (application.datasource = (function(){ var properties = new java.util.Properties(); for(var k in datasourceConfig){ properties.setProperty(k, datasourceConfig[k] + ''); } return Java.type('org.apache.commons.dbcp2.BasicDataSourceFactory').createDataSource(properties); }())); var sqlExecutor = new org.siphon.jssql.SqlExecutor(datasource, engine, JSON); sqlExecutor.defaultJsonDbType = datasourceConfig.defaultJsonDbType || 'JSONB'; sqlExecutor.columnNameCase = datasourceConfig.columnNameCase || 0; // LOWER sqlExecutor.useColumnLabelAsName = datasourceConfig.useColumnLabelAsName || false; ; d2js = handler = new D2JS(sqlExecutor); engine.put('handler', handler); engine.put('d2js', d2js); }
这个 D2JS.init 函数在 application.d2js.js 和 application.jssp.js 中调用。
通过自定义 D2JS.init 函数,可以自定义数据库连接。
如对于spring,可编写 spring-datasource.js :
D2JS.init = function(){ var sqlExecutor = D2JS.createExecutorForDataSource("dataSource"); d2js = handler = new D2JS(sqlExecutor); engine.put('handler', handler); engine.put('d2js', d2js); } D2JS.createExecutorForDataSource = function(beanName){ var WebApplicationContextUtils = Java.type('org.springframework.web.context.support.WebApplicationContextUtils'); var wac = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext); var datasource = wac.getBean(beanName); var sqlExecutor = new org.siphon.jssql.SqlExecutor(datasource, engine); sqlExecutor.columnNameCase = 1; // KEEP sqlExecutor.useColumnLabelAsName = true; return sqlExecutor; }
对于其它数据源,如 h2 db 可编写:
var executor = (function createMemExecutor(){ var datasource = (function(){ var properties = new java.util.Properties(); for(var k in datasourceConfig){ properties.setProperty(k, datasourceConfig[k] + ''); } return Java.type('org.apache.commons.dbcp2.BasicDataSourceFactory').createDataSource(properties); })(); var sqlExecutor = new org.siphon.jssql.SqlExecutor(datasource, engine); sqlExecutor.columnNameCase = datasourceConfig.columnNameCase || 0; // LOWER sqlExecutor.useColumnLabelAsName = true; return sqlExecutor; })();
修改 application.d2js.js 和 application.jssp.js,在 imports("jslib/d2js.js"); 后执行
imports("./spring-datasource.js");
这样,spring-datasource.js 中的 D2JS.init 就覆盖了 base.js 中原来的 D2JS.init,实现了使用 spring 数据源或其它数据源。
如何让多个数据源并存呢?
如上面的内存数据源,登记为 d2js.memSqlExecutor。
d2js.memSqlExecutor = (function createMemExecutor(){ var datasource = (function(){ var properties = new java.util.Properties(); for(var k in datasourceConfig){ properties.setProperty(k, datasourceConfig[k] + ''); } return Java.type('org.apache.commons.dbcp2.BasicDataSourceFactory').createDataSource(properties); })(); var sqlExecutor = new org.siphon.jssql.SqlExecutor(datasource, engine); sqlExecutor.columnNameCase = datasourceConfig.columnNameCase || 0; // LOWER sqlExecutor.useColumnLabelAsName = true; return sqlExecutor; })();
前面的博客介绍过,每个 d2js 实例都是从 d2js 对象复制的,所以每个 d2js 实例都会拥有 memSqlExecutor 成员。
使用时只要通过 this.executor = d2js.memSqlExecutor 就可以切换数据源(记得切换回来)。
如考虑为web容器环境,也可将设为 application.memSqlExecutor。
如果需要对多个数据源前后执行同一条语句,可按如下操作:
d2js.test = function(){ [sqlExecutor1, sqlExecutor2, this.executor].forEach(function(executor){ this.executor = executor; // 循环过程依次切换为 sqlExecutor1, sqlExecutor2, this.executor this.execute(sql, {args}) }, this) }
这个办法只有一个 d2js 对象,此外也可直接创建一些真正的 d2js 对象。
var d = new D2JS(this.executor); for(var k in this){ if(this.hasOwnProperty(k)) { d[k] = this[k]; } else { break; } }
d.executor = executor1;
d 就是一个从当前 d2js 实例复制出来但是数据源不同的 d2js 对象。