I'm trying to create a base project with Play Framework 2.5 and jOOQ 3.9 using PostgreSQL 9.5 as database. This project is structured in three main layers: controllers, services and daos (and I only have one instance of every service and dao due to Guice dependency injection).
To work with jOOQ transactions over controller's methods I have developed the following Java Action:
public class DatabaseTransactionAction extends Action.Simple {
#Inject
private Database database;
private Connection connection;
#Override
public CompletionStage<Result> call (Http.Context ctx) {
connection = database.getDataSource().getConnection();
// Make JOOQ work with the connection acquired
DSLContext dslContext = DSL.using (connection,
SQLDialect.POSTGRES, new Settings());
// Wrap everything inside the same transaction
return dslContext.transactionResultAsync (configuration -> {
/**
* Save the transaction configuration in the action context arguments so that
* the action can pass down the same transaction into the services it depends on
*/
ctx.args.put (Constants.DATABASE_TRANSACTION_KEY, configuration);
// Make the call to the action itself
return delegate.call (ctx);
// Commit and release the connection when the action terminates
}).thenComposeAsync (resultCompletionStage -> {
return resultCompletionStage.thenApply (result -> {
try {
this.connection.commit();
JDBCUtils.safeClose (this.connection);
} catch (Exception e) {
throw new DatabaseException (e);
}
return result;
});
// In case something wrong happens, rollback the transaction
}).exceptionally (throwable -> {
try {
this.connection.rollback();
JDBCUtils.safeClose (this.connection);
} catch (Exception e) {
throw new DatabaseException (e);
}
throw new DatabaseException (throwable);
});
}
}
The problem of this approach is that I need to create a new class (very similar to jOOQ DAOImpl class) to use the configuration stored in the Http context:
public abstract class DAOImpl<R extends UpdatableRecord<R>, P, T> implements DAO<R, P, T> {
...
#Override
public /* non-final */ Configuration configuration() {
if (Http.Context.current.get() != null)
return (Configuration) Http.Context.current().args.get (Constants.DATABASE_TRANSACTION_KEY);
return this.configuration;
}
...
#Override
public /* non-final */ List<P> findAll() {
return using(configuration())
.selectFrom(table)
.fetch()
.map(mapper());
}
...
}
Other problem is that I need to set the configuration manually if I try to access to the database using a Dao when the Http context does not exist yet (in an ActionCreator for example).
I have read several links about it:
jOOQ initializing DAO Best Approach
jOOQ examples
But I'm not sure what is the best way to do the following:
Work with only one configuration due to I only has one database.
I would like to know if there is a better approach than I have developed, that is, without "overwrite" the DAOImpl class (taking into account that I would like to have only one instance of every Dao)
Related
I use jooq to handle SQL Queries on a PostgreSQL database in an Wildfly web application. The DSLContext is injected via CDI into my beans following the example on http://awolski.com/integrating-jooq-easy/. A bean looks like this:
public class Foo {
private #Inject DSLContext jooq;
...
public boolean update....
{
...
try {
jooq.doStuff();
}
catch(Exception e) {
System.out.println(e.getCause().getMessage());
}
finally {
jooq.close();
}
...
}
When I run the application, every connection leaks. What am I missing ?
The constructor was the critical point.
Since the documentation on https://www.jooq.org/doc/3.10/manual/sql-building/dsl-context/connection-vs-datasource/ says that jooq will manage the connection, passing the datasource object instead of the connection object solves the issue:
public DSLContext getDSLContext() throws SQLException {
return DSL.using(ds, SQLDialect.MYSQL);
}
in http://awolski.com/integrating-jooq-easy/
I imagine that this is a common problem, but after some searching I wasn't able to find anything relevant.
The problem I'm having is that I'm getting a No Hibernate Session bound to thread exception when annotating my resource method with #UnitOfWork and inside my resource method, making an asynchronous DAO call. The idea behind this design is to make the database call on a separate I/O thread so that it frees up the Jersey resource thread.
Unfortunately, as the exception says, this RxIoScheduler-2 thread doesn't have a hibernate session bound to it.
Any suggestions?
Hibernate Session is not thread safe, so we need a strategy how to get the current session for the current thread. Such strategy is called CurrentSessionContext.
The current session is a session which we get by this call:
sessionFactory.getCurrentSession()
Hibernate can be configured with various current session strategies. #UnitOfWork uses this strategy:
hibernate.current_session_context_class = managed
For this strategy you should put a session to the context by an explicit call of the
ManagedSessionContext.bind(session)
So, as we know a Session is not thread safe, you should create a new session for a separate thread and put that session in the ManagedSessionContext. After that you can call your DAO by the same way as in the endpoint methods with #UnitOfWork.
Keep in mind that you should unbind the session before closing it with
ManagedSessionContext.unbind(factory)
You can use this utility class to create a session for a separate thread:
public final class HibernateSessionUtils {
private HibernateSessionUtils() {
}
public static void request(SessionFactory factory, Runnable request) {
request(factory, () -> {
request.run();
return null;
});
}
public static <T> T request(SessionFactory factory, Supplier<T> request) {
Transaction txn = null;
Session session = factory.openSession();
try {
ManagedSessionContext.bind(session);
txn = session.beginTransaction();
T result = request.get();
commit(txn);
return result;
} catch (Throwable th) {
rollback(txn);
throw Throwables.propagate(th);
} finally {
session.close();
ManagedSessionContext.unbind(factory);
}
}
private static void rollback(Transaction txn) {
if (txn != null && txn.isActive()) {
txn.rollback();
}
}
private static void commit(Transaction txn) {
if (txn != null && txn.isActive()) {
txn.commit();
}
}
}
Throwables from guava.
It can be used by this way
List<Campaign> getCampaigns(SessionFactory factory, CampaignDao dao) {
return HibernateSessionUtils.request(
factory,
dao::getCampaigns
);
}
In the dao.getCampaigns() method you can get the session
sessionFactory.getCurrentSession()
You can inject the factory everywhere using Guice.
Other option is to use UnitOfWorkAwareProxyFactory.
Consider this two classes: EmployeeDetailDAOImpl and EmployeeDAOImpl. Assume if I want to create a new employee, I should also create a new record for EmployeeDetail.
Given the below implementation, I wonder if the outer transaction(EmployeeDAOImpl's tx) is rolled back due to any exceptions happened after the detailDAO.create(employeeId) call, will the transaction of new EmployeeDetail be rolled back as well?
public class SessionHandler {
public static getSession() {
return Configuration.buildSessionFactory().openSession(); //ignore the isConnected or other exception handling for now
}
}
public class EmployeeDetailDAOImpl {
public void create(Serializable employeeId) {
Session session = SessionHandler().getSession();
Transaction tx = session.beginTransaction();
try {
EmployeeDetail detail = new EmployeeDetail(employeeId);
session.save(detail );
} catch (Exception e) {
if (tx!= null) {
tx.rollback;
}
}
session.close();
}
}
public class EmployeeDAOImpl {
public void add(String name) {
Session session = SessionHandler().getSession();
Transaction tx = session.beginTransaction();
try {
Employee employee = new Employee(name);
Serializable employeeId= session.save(employee);
EmployeeDetailDAOImpl detailDAO = new EmployeeDetailDAOImpl();
detailDAO.create(employeeId);
//more things here, that may through exceptions.
} catch (Exception e) {
if (tx!= null) {
tx.rollback;
}
}
session.close();
}
}
Actually, none of the given answers is 100% correct.
It depends on the calling party/service.
If you are calling the methods from an EJB, you will have 1 transaction covering both method calls. That way, the transaction will roll back both operations in case of an exception. Reason behind this is that every method in EJB is transaction Required, unless specified otherwise in the annotation or ejb deployment descriptor.
If you are using spring or any other DI framework, then it depends on your configuration. In a normal setup, your calling transaction will be suspended, since the JPA EJB will create its own transaction. You can however use the JTATransactionManager (As specified here) to make sure that both your EJB and your Spring bean share the same transaction.
If you call the JPA methods from a POJO, then you will have to take care of the JTA transaction handling yourself.
Yes, it will rollback the entity Employee as well. It doesn't even depend on whether the other entities are related.
It depends on the scope of the transaction, which here includes both Employee and EmployeeDetails
You are creating two different transaction for each method.Hence rollback can not happen.
To rollback the transaction you require the propogation in Transaction.
You need to write the code like below::
#Transactional(propagation=Propagation.REQUIRED)
public void testRequired(User user) {
testDAO.insertUser(user);
try{
innerBean.testRequired();
} catch(RuntimeException e){
// handle exception
}
}
Below is link for more information of Propogation.
http://docs.spring.io/spring-framework/docs/2.5.6/api/org/springframework/transaction/annotation/Propagation.html
http://www.byteslounge.com/tutorials/spring-transaction-propagation-tutorial
I want to know Best practices for initilizing JOOQ generated DAO. Now,I am using following approach for initilization of JOOQ generated DAO. In following case StudentDao is JOOQ generated.
public class ExtendedStudentDAO extends StudentDao {
public ExtendedStudentDAO () {
super();
}
public ExtendedStudentDAO (Connection connection) {
Configuration configuration = DSL.using(connection,
JDBCUtils.dialect(connection)).configuration();
this.setConfiguration(configuration);
}
//adding extra methods to DAO using DSL
public String getStudentName(Long ID)
throws SQLException {
try (Connection connection = ServiceConnectionManager.getConnection()) {
DSLContext dslContext = ServiceConnectionManager
.getDSLContext(connection);
Record1<String> record = dslContext
.select(Student.Name)
.from(Student.Student)
.where(Student.ID
.equal(ID)).fetchOne();
if (record != null) {
return record.getValue(Student.Name);
}
return null;
}
}
}
and I have doubt with using above DAO my example code is below.
try (Connection connection = ServiceConnectionManager.getConnection()) {
ExtendedStudentDAO extendedStudentDAO =new ExtendedStudentDAO(connection);
Student stud=new Student();
.....
....
//insert method is from Generated DAO
extendedStudentDAO.insert(stud);
//this method is added in extended class
extendedStudentDAO.getStudentName(12);
}
There are two ways to look at this kind of initialisation:
Create DAOs every time you need them
Your approach is correct, but might be considered a bit heavy. You're creating a new DAO every time you need it.
As of jOOQ 3.7, a DAO is a pretty lightweight object. The same is true for the Configuration that wraps your Connection.
Once your project evolves (or in future jOOQ versions), that might no longer be true, as your Configuration initialisation (or jOOQ's DAO initialisation) might become heavier.
But this is a small risk, and it would be easy to fix:
Use dependency injection to manage DAO or Configuration references
Most people will set up only a single jOOQ Configuration for their application, and also only a single DAO instance (per DAO type), somewhere in a service. In this case, your Configuration must not share the Connection reference, but provide a Connection to jOOQ via the ConnectionProvider SPI. In your case, that seems trivial enough:
class MyConnectionProvider implements ConnectionProvider {
#Override
public Connection acquire() {
return ServiceConnectionManager.getConnection();
}
#Override
public void release(Connection connection) {
try {
connection.close();
}
catch (SQLException e) {
throw new DataAccessException("Error while closing", e);
}
}
}
I've got a Spring + Hibernate + MySQL web application, which is just a hello-world-test-area for now.
One of my Service classes implements this method:
public List<Offerta> tutte() {
List<Offerta> tutte = null;
TransactionStatus status = txm.getTransaction( new DefaultTransactionDefinition() );
try {
tutte = dao.getAll(Offerta.class);
txm.commit(status);
} catch (Exception e) {
e.printStackTrace();
txm.rollback(status);
}
return tutte;
}
'txm' is an injected PlatformTransactionManager.
What I want now, is to avoid duplicating the "wrapping" transaction code in all my service's methods!
I would like something like this:
someHelperTransactionClass.doThisInTransaction(new TransactionAction() {
List l = dao.queryForSomething();
});
But that's a inner class: how can I pass in and out data from it? I mean, how can I get the resulting "l" list from that TransactionAction? You could answer in a number of ways to this specific case, but what I need is a generic TransactionAction or a different solution which let me write the actual database code, without having to write each time the same boring code.
Please do not answer "Why don't you use #Transactional annotations or AOP tx:advice configuration?" because I CAN'T!
Why? I am on Google AppEngine, and that cool guys are not so cool: the disabled access to the javax.naming package, and something in those great ways to declarative transactions touches it. :-\
You can imitate basic AOP mechanism using Proxy objects. Such as http://www.devx.com/Java/Article/21463/1954
This is a mock. But I really doubt it plays well with Spring or GAE. PLease note that you need to use interfaces for Proxies.
interface Dao {
List<Foo> getAllFoo();
}
public class MyDao implements Dao {
public MyDao() {
}
public List<Foo> getAllFoo() {
//.. get list of foo from database. No need to use transactions
}
public static void main(String[] args) {
Dao dao = new MyDao();
InvocationHandler handler = new TransactionProxyHandler(dao);
Dao proxy = (Dao) Proxy.newProxyInstance(MyDao.class.getClassLoader(), MyDao.class.getInterfaces(), handler);
List<Foo> all = proxy.getAllFoo();
}
}
class TransactionProxyHandler implements InvocationHandler {
protected Object delegate;
PlatformTransactionManager txm = new PlatformTransactionManager();
public TransactionProxyHandler(Object delegate) {
this.delegate = delegate;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
TransactionStatus status = txm.getTransaction();
Object res = null;
try {
res = method.invoke(delegate, args);
txm.commit(status);
} catch (Exception e) {
e.printStackTrace();
txm.rollback(status);
}
return res;
}
}