Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>If your database change infrequently, you could use the data source that comes with the database's JDBC driver and isolate the calls to the 3rd party library in a provider (My example uses the one provided by the H2 dataabse, but all JDBC providers should have one). If you change to a different implementation of the DataSource (e.g. c3PO, Apache DBCP, or one provided by app server container) you can simply write a new Provider implementation to get the datasource from the appropriate place. Here I've use singleton scope to allow the DataSource instance to be shared amongst those classes that depend on it (necessary for pooling).</p> <pre><code>public class DataSourceModule extends AbstractModule { @Override protected void configure() { Names.bindProperties(binder(), loadProperties()); bind(DataSource.class).toProvider(H2DataSourceProvider.class).in(Scopes.SINGLETON); bind(MyService.class); } static class H2DataSourceProvider implements Provider&lt;DataSource&gt; { private final String url; private final String username; private final String password; public H2DataSourceProvider(@Named("url") final String url, @Named("username") final String username, @Named("password") final String password) { this.url = url; this.username = username; this.password = password; } @Override public DataSource get() { final JdbcDataSource dataSource = new JdbcDataSource(); dataSource.setURL(url); dataSource.setUser(username); dataSource.setPassword(password); return dataSource; } } static class MyService { private final DataSource dataSource; @Inject public MyService(final DataSource dataSource) { this.dataSource = dataSource; } public void singleUnitOfWork() { Connection cn = null; try { cn = dataSource.getConnection(); // Use the connection } finally { try { cn.close(); } catch (Exception e) {} } } } private Properties loadProperties() { // Load properties from appropriate place... // should contain definitions for: // url=... // username=... // password=... return new Properties(); } } </code></pre> <p>To handle transactions a Transaction Aware data source should be used. I wouldn't recommend implementing this manually. Using something like warp-persist or a container supplied transaction management, however it would look something like this:</p> <pre><code>public class TxModule extends AbstractModule { @Override protected void configure() { Names.bindProperties(binder(), loadProperties()); final TransactionManager tm = getTransactionManager(); bind(DataSource.class).annotatedWith(Real.class).toProvider(H2DataSourceProvider.class).in(Scopes.SINGLETON); bind(DataSource.class).annotatedWith(TxAware.class).to(TxAwareDataSource.class).in(Scopes.SINGLETON); bind(TransactionManager.class).toInstance(tm); bindInterceptor(Matchers.any(), Matchers.annotatedWith(Transactional.class), new TxMethodInterceptor(tm)); bind(MyService.class); } private TransactionManager getTransactionManager() { // Get the transaction manager return null; } static class TxMethodInterceptor implements MethodInterceptor { private final TransactionManager tm; public TxMethodInterceptor(final TransactionManager tm) { this.tm = tm; } @Override public Object invoke(final MethodInvocation invocation) throws Throwable { // Start tx if necessary return invocation.proceed(); // Commit tx if started here. } } static class TxAwareDataSource implements DataSource { static ThreadLocal&lt;Connection&gt; txConnection = new ThreadLocal&lt;Connection&gt;(); private final DataSource ds; private final TransactionManager tm; @Inject public TxAwareDataSource(@Real final DataSource ds, final TransactionManager tm) { this.ds = ds; this.tm = tm; } public Connection getConnection() throws SQLException { try { final Transaction transaction = tm.getTransaction(); if (transaction != null &amp;&amp; transaction.getStatus() == Status.STATUS_ACTIVE) { Connection cn = txConnection.get(); if (cn == null) { cn = new TxAwareConnection(ds.getConnection()); txConnection.set(cn); } return cn; } else { return ds.getConnection(); } } catch (final SystemException e) { throw new SQLException(e); } } // Omitted delegate methods. } static class TxAwareConnection implements Connection { private final Connection cn; public TxAwareConnection(final Connection cn) { this.cn = cn; } public void close() throws SQLException { try { cn.close(); } finally { TxAwareDataSource.txConnection.set(null); } } // Omitted delegate methods. } static class MyService { private final DataSource dataSource; @Inject public MyService(@TxAware final DataSource dataSource) { this.dataSource = dataSource; } @Transactional public void singleUnitOfWork() { Connection cn = null; try { cn = dataSource.getConnection(); // Use the connection } catch (final SQLException e) { throw new RuntimeException(e); } finally { try { cn.close(); } catch (final Exception e) {} } } } } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload