I'm using MyBatis-guice 3.3 to connect to a first database using a java Properties object and a ScriptRunner to run few scripts:
Environment environment = injector.getInstance(SqlSessionFactory.class).getConfiguration().getEnvironment();
DataSource source = environment.getDataSource();
ScriptRunner runner = new ScriptRunner(source.getConnection());
runner.setLogWriter(null);
runner.setStopOnError(true);
runner.runScript(Resources.getResourceAsReader(properties.getProperty("script.dbA.create.schema")));
Now I would like to add a second datasource (dbB) using the same approach. Following the MyBatis-guice reference guide I have to use 2 PrivateModule. This part works fine.
But then how should I call my ScriptRunner to run some scripts for dbA and some others for dbB?
Create 2 qualifier annotations @DbA and @DbB or similar.
Now each of the private modules will call (via the MyBatisModule)
binder().bind(SqlSessionFactory.class).toProvider(SqlSessionFactoryProvider.class).in(Scopes.SINGLETON);
that means it is not possible to do
expose(SqlSessionFactory.class).annotatedWith(DbA.class);
that would require
binder().bind(SqlSessionFactory.class).annotatedWith(DbA.class).toProvider(SqlSessionFactoryProvider.class).in(Scopes.SINGLETON);
Instead you need to provide an intermediate class that gets injected with SqlSessionFactory and is exposed with qualifier annotation.
And in each private module do something in the lines of
bind(MyBatisEnv.class).to(MyBatisImpl.class).annotatedWith(DbX.class);
expose(MyBatisEnv.class).annotatedWith(DbX.class);
Here is a solution.
Injector injector = Guice.createInjector(
new PrivateModule() {
@Override protected void configure() {
install(new MyBatisModule() {
@Override protected void initialize() {
bindDataSourceProviderType(BasicDataSourceProvider.class);
bindTransactionFactoryType(JdbcTransactionFactory.class);
// add all your mappers here nowhere else
addMapperClass(MapperA1.class);
}
});
Names.bindProperties(binder(), createProperties("dbA"));
// expose all your mappers here
expose(MapperA1.class);
// bind&expose all db specific stuff here (SessionFactory, SessionManager, etc.)
bind(SqlSessionFactory.class).annotatedWith(DbA.class).to(SqlSessionFactory.class);
expose(SqlSessionFactory.class).annotatedWith(DbA.class);
}},
new PrivateModule() {
@Override protected void configure() {
install(new MyBatisModule() {
@Override protected void initialize() {
bindDataSourceProviderType(BasicDataSourceProvider.class);
bindTransactionFactoryType(JdbcTransactionFactory.class);
// add all your mappers here nowhere else
addMapperClass(MapperB1.class);
}
});
Names.bindProperties(binder(), createProperties("dbB"));
// expose all your mappers here
expose(MapperB1.class);
// bind&expose all db specific stuff here (SessionFactory, SessionManager, etc.)
bind(SqlSessionFactory.class).annotatedWith(DbB.class).to(SqlSessionFactory.class);
expose(SqlSessionFactory.class).annotatedWith(DbB.class);
}}
);
DataSource dbA dataSource = injector.getInstance(Key.get(SqlSessionFactory.class), DbA.class).getConfiguration().getEnvironment().getDataSource();
ScriptRunner runner = new ScriptRunner(source.getConnection());
runner.runScript(Resources.getResourceAsReader("dbA/path/create_db.sql"));
runner.closeConnection();
private static Properties createDbProperties(String schema) {
final Properties p = new Properties();
p.setProperty("mybatis.environment.id", "test");
p.setProperty("JDBC.driver", "org.hsqldb.jdbcDriver");
p.setProperty("JDBC.url", "jdbc:hsqldb:mem" + schema + ";sql.syntax_ora=true");
p.setProperty("JDBC.username", "sa");
p.setProperty("JDBC.password", "");
return p;
}
If anyone is looking for a solution in GWT Platform environment, here is the configuration from an working environment. Hope this is useful.
// mybatis-dbA-config.xml
<configuration>
<settings>
<setting name="cacheEnabled" value="false" />
<setting name="useGeneratedKeys" value="true" />
<setting name="defaultExecutorType" value="REUSE" />
</settings>
<typeAliases>
<package name="com.example.domain" />
</typeAliases>
<environments default="test">
<environment id="test">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@//localhost:1521/SchemaName" />
<property name="username" value="user" />
<property name="password" value="pwd" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/example/mapper/DomainAMapper.xml" />
</mappers>
</configuration>
...
//dbA Dao implementation
public class DbADaoImpl implements DbADao {
@Inject
@Named("DbA")
private SqlSession sqlSession;
public List<DomainA> listDbADomains() {
return this.sqlSession.selectList("com.example.mapper.DomainAMapper.listDomainAs");
}
...
//dbB Dao implementation
public class DbBDaoImpl implements DbBDao {
@Inject
@Named("DbB")
private SqlSession sqlSession;
public List<DomainB> listDbBDomains() {
return this.sqlSession.selectList("com.example.mapper.DomainBMapper.listDomainBs");
}
...
// Service implementation
public class MyServiceImpl implements MyService {
@Inject
private DbADao aDao;
@Inject
private DbBDao bDao;
@Transactional(isolation = Isolation.SERIALIZABLE)
@Override
public Boolean doBusinessStuff() {
// use aDao.
// use bDao.
}
...
// DbA Module
public class DbAModule extends PrivateModule {
@Override
protected void configure() {
install(new XMLMyBatisModule() {
@Override
protected void initialize() {
setEnvironmentId("test");
setClassPathResource("mybatis-dbA-config.xml");
useJdbcDriverClassLoaderoracle.jdbc.OracleDriver.class.getClassLoader());
addProperties(createTestProperties());
}
});
bind(SqlSession.class).annotatedWith(Names.named("DbA")).toProvider(SqlSessionManagerProvider.class).in(Scopes.SINGLETON);
expose(SqlSession.class).annotatedWith(Names.named("DbA"));
}
protected static Properties createTestProperties() {
final Properties myBatisProperties = new Properties();
myBatisProperties.setProperty("mybatis.environment.id", "test");
myBatisProperties.setProperty("JDBC.autoCommit", "false");
return myBatisProperties;
}
}
...
// DbB Module
// identical to the above replacing DbA with DbB
...
//
// GWTP Configurations
//
//
public class DaoServiceModule extends AbstractModule {
@Override
protected void configure() {
bind(Service.class).to(ServiceImpl.class);
bind(DbADao.class).to(DbADaoImpl.class);
bind(DbBDao.class).to(DbBDaoImpl.class);
}
public class GuiceServletConfig extends GuiceServletContextListener {
@Override
protected Injector getInjector() {
return Guice.createInjector(new ServerModule(),
new DispatchServletModule(),
new DbAModule(),
new DbAModule(),
new DaoServiceModule());
}