I'm after a bit of advice regarding configuring a DAO factory with a pooled datasource. Suppose its a JDBC DAO factory (from an abstract factory) and the pooled datasource is configured and managed by the application server e.g. Glassfish
When the factory is created for the first time (Singleton pattern) it does a JNDI lookup for the pooled datasource e.g. from a properties file, which will set the pooled datasource on the JDBC DAO factory.
Then, when you instantiate and return the concrete DAO would you pass it a reference to datasource so it could retrieve a connection to the database?
Basically what I did was encapsulate that datasource as a field in a base class called DAO. In the constructor of the DAO you pass in the JNDI name of the connection you want.
public DAO(String jndiName) throws NamingException {
ds = DataSourceFactory.getInstance().lookup(jndiName);
}
Then in all of your concrete classes you simply extend from DAO and can use the datasource as you want.
public concreteDAO() throws NamingException {
super("Some JNDI Name That this DAO should know");
}
The same DAO class has some other utility methods like a cleanup method, that silently closes the ResultSet, Statements and Connections. So that way I just have to add this in the finally clause of all my methods.
Related
I'm using Spring JPA to connect to a relational database. I want to have multiple connection pools connecting to the same database so scheduled tasks can't clog up the connection pool for user interactions.
This works fine if I define multiple DataSources like it is described in Spring JPA Hikari multiple connection pool with same datasource. Currently I define multiple different EntityManagerFactoryBeans and PlatformTransactionManagers, one for each DataSource. But I would like to be able to use the same physical transaction spanning calls to different JpaRepositories backed by different DataSources.
#Service
public class FooService {
// ..
#Transactional
public saveFoo(Foo foo) {
fooRepository.save(foo);
barService.somethingElse(foo);
}
}
#Service
public class BarService {
#Transactional(propagation = Propagation.MANDATORY)
public somethingElse(Foo foo) {
// BarRepository is backed by another DataSource as FooRepository,
// but both DataSources connect to the same database
barRepository.saveAndFlush(new FoobarEvent(foo));
}
}
The call to BarRepository fails for me with:
InvalidDataAccessApiUsageException: no transaction is in progress; nested exception is javax.persistence.TransactionRequiredException: no transaction is in progress
It seems like multiple different DataSources are needed because the DataSources define the connection pool. But since the PlatformTransactionManager and the EntityManagerFactoryBean references the DataSource it's not really possible to have transactions span multiple repositories that are backed by different DataSources because Spring doesn't know that both DataSources point to the same database. Is there a way to configure Spring JPA to achieve what I want?
If your service is running through an interface from your controller, then Transactional method should come on the interface layer method.
And use javax.persistance.Transactional class for the annotation instead of org.springframework.transaction.annotation.Transactional
and specify #EnableTransactionManagement in your application class to enable transactions.
Say I have an #ApplicationScoped service class.
#ApplicationScoped
class MyCustomerService {
...
}
I then want to inject a Connection object into that service.
#ApplicationScoped
class MyCustomerService {
private final Connection connection;
#Inject
MyCustomerService(final Connection connection) {
this.connection = connection;
}
...
}
The Connection object is produced by a #Produces method, using a DataSource.
class ConnectionProducer {
...
#Produces
Connection getConnection(final DataSource dataSource) {
return dataSource.getConnection();
}
...
}
Will the Connection class be proxied? Will CDI invoke the producer method each time I use the connection bean (not like RequestScoped, I really mean for each invocation)?
I know I could just #Inject the DataSource, this is just "learning" how CDI manages scopes.
Will CDI invoke the producer method each time I use the connection bean
No. the producer method called once because the default scope is Dependent . your connection lifecyle bounded to MyCustomerService lifecycle
Will the Connection class be proxied
If the bean is in #Dependent scope, then the client holds a direct reference to its instance(clientproxy is just created for NormalScope)
but if the bean has decorator or interceptor a proxy will be created(client proxy is not created because there is not any context for selecting bean but another proxy is created for applying decorators and interceptors) I tested this at weblogic application server
I want to alter Oracle session for every connection that I get from the connection pool.
I found that it can be done by simply execute a statement. See here.
Is there a way to hook into the jdbc template or the datasource and execute a statement after the connection pool creates a new connection.
I'm using Spring Boot and creating the datasource that way:
#Bean
#ConfigurationProperties(prefix="datasource.local")
public DataSource localDataSource() {
return DataSourceBuilder.create().build();
}
There are a lot of ways to do so.
The first one:
DataSource is an interface, so why don't you implement it yourself (use Proxy pattern)? Create something like this:
class MyDataSource implements DataSource {
private DataSource realDataSource;
public Connection getConnection() {
Connection c = realDataSource.getConnection();
// do whatever you want to do and
return c;
}
}
All other methods will delegate directly to realDataSource.
This proxy can be used in a provided code snippet.
You can use some AOP - just provide an advice that after get connection is created will run and do whatever you need there. Basically it's the same proxy but automatically created by Spring.
I have got:
a DAO class in JOOQ that in its constructor takes a javax.sql.DataSource, which is injected by Guice
a service class that calls the methods from the DAO class
I want to:
be able to annotate a few methods inside the service class as methods requiring a transaction
Possible solution: https://github.com/jOOQ/jOOQ/tree/master/jOOQ-examples/jOOQ-spring-guice-example i.d.:
a method interceptor invoked when a method is annotated with the Transactional annotation
the method interceptor calls rollback() if there were exceptions or commit() if everything was fine
Guice provides a javax.sql.DataSource (BoneCP pooled connection)
the BoneCP pooled connections have the defaultAutoCommit attribute set to false
Finally, my question:
I want the datasource with autocommit set to false to be injected into all the methods that are called from the method annotated with #Transactional, in all the other cases the datasource with autocommit set to true
How this can be achieved?
There is a simple but not elegant way: create two DataSource instances and inject appropriately.
There is also a bit more complex way with a single DataSource instance. Roughly:
AutoCommit is a property of java.sql.Connection and there is a setter for it.
Implement org.jooq.ConnectionProvider to make JOOQ use your DataSource instance.
This ConnectionProvider implementation will have a special method, e.g. startTransaction() that can create a connection with autocommit=false and cache it in a ThreadLocal member. I.e.
Connection conn = dataSource.createConnection();
conn.setAutoCommit(false);
threadLocal.set(conn);
return conn;
ConnectionProvider.acquire() will do smth like (simplified version):
return threadLocal.get() != null ?
threadLocal.get() :
dataSource.createConnection();
Other two "special" methods would be commit() and rollback() - they will do a corresponding operation on the cached connection, close the connection and remove it from threadLocal.
The #Transactional method interceptor will call the "special" methods
try {
connectionProvider.startTransaction();
interceptedMethod.invoke();
connectionProvider.commit();
} catch (Exception e) {
connectionProvider.rollback();
}
Essentially, this is the most simple transaction manager.
I have such things as:
1) DAO class with methods, used to perform transaction, such as withdrawSum(int idAccount, float amount) and putSum(int idAccount, float amount) which use java.sql.Connection and java.sql.PreparedStatement classes to perform atomic operations with DB.
2) java.lang.reflect.InvocationHandler implementor, whick is used to get connection before transaction and commit/rollback after transaction:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Connection connection = null;
try{
connection = DaoUtil.INSTANCE.getConnection();
connection.setAutoCommit(false);
method.invoke(connection, args);
connection.commit();
} catch(InvocationTargetException ex){
connection.rollback();
} finally{
DaoUtil.INSTANCE.closeConnection(connection);
}
return null;
}
3) Transaction manager, which creates Proxy instance and with its help calls method which executes transaction, something like this:
TransactionManager transManager = new TransactionManager();
InvocationHandler transHandler = new MyInvocationHandler(transManager);
TransactionManager proxy = (TransactionManager) Proxy.newProxyInstance(
transManager.getClass().getClassLoader(), transManager.getClass().getInterfaces(), transHandler);
proxy.transferMoney(withdrawAccountid, putAccountId, transactionSum);
.....
public void transferMoney(int withdrawAccountid, int putAccountId, float transactionSum){
AccountDao.getInstance().withdrawSum(withdrawAccountid, transactionSum);
AccountDao.getInstance().putSum(putAccountId, transactionSum);
}
The question is: to execute statement in DAO methods, I need initialized Connection object. It is intialized and passed to the invoke-method of the InvocationHandler. How it should be correctly initialized in DAO-methods? Any ideas? Thanks in advance.
Since transactions are naturally associated with threads, a typical approach here is to store Connection in a ThreadLocal storage during the scope of transaction.
Then you can make these connections available to DAOs using different approaches:
DAOs can obtain Connections by calling some static method
A custom DataSource can be injected into DAOs - its getConnection() method would return the connection associated with current transaction, note that connection should be proxied in order to ignore close(). This approach doesn't couple your DAOs with transaction management code.
Also note that all these things are already implemented by some libraries, for example, by Spring Framework. Perhaps you can leverage it instead of creating your own solution, or at least take a look at their design (in Spring, different approaches for obtaining connections are implemented by DataSourceUtils and TransactionAwareDataSourceProxy, respectively).
See also:
10. Transaction Management
12. Data access with JDBC