JOOQ initializing DAO Best Approach - java

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);
}
}
}

Related

Injected JOOQ Context leaks connections

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/

What happen on Transaction.rollback in nested session/transactions?

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

Use jOOQ with Play Framework

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)

Get hold of a JDBC Connection object from a Stateless Bean

In a Stateless Session Bean an EntityManager is injected but I would like to get hold of a Connection object in order to invoke a DB Procedure.
Is there any solution to this ?
This is going to be JPA provider specific code. Typically this is done by invoking unwrap() on the EntityManager class.
If you are using EclipseLink, the following code (from the EclipseLink wiki) will be useful (in the case you are using an application-managed EntityManager) :
JPA 2.0
entityManager.getTransaction().begin();
java.sql.Connection connection = entityManager.unwrap(java.sql.Connection.class); // unwraps the Connection class.
...
entityManager.getTransaction().commit();
JPA 1.0
entityManager.getTransaction().begin();
UnitOfWork unitOfWork = (UnitOfWork)((JpaEntityManager)entityManager.getDelegate()).getActiveSession();
unitOfWork.beginEarlyTransaction();
Accessor accessor = unitOfWork.getAccessor();
accessor.incrementCallCount(unitOfWork.getParent());
accessor.decrementCallCount();
java.sql.Connection connection = accessor.getConnection();
...
entityManager.getTransaction().commit();
Note, that the solution provided for JPA 2.0 will fail for Hibernate 3.6.5 with a PersistenceException containing the message
Hibernate cannot unwrap interface java.sql.Connection
Use the code provided by Skaffman to get it to work against Hibernate (verified to work under 3.6.5 even for container managed persistence contexts).
However, the EclipseLink wiki points out one useful bit of info - if you are using JTA managed datasources, you should be injecting it using the #Resource annotation or retrieving it using a JNDI lookup. As long as you need to perform transactional work against the database, it is immaterial as to whether you are obtaining a new connection from the data source or an existing one; most connection pools will anyway provide the same connection that is associated with the current thread (i.e. the one already used by the entity manager). You would therefore avoiding unwrapping the entity manager this way, and also perform transactional activity against the database; do remember that the persistence context cache, and a second-level cache may not be synchronized if you do this.
In Hibernate, the solution posted by skaffman resulted in the following error message:
Hibernate cannot unwrap class org.hsqldb.Session
I did get it to work using SessionImpl rather than Session:
Connection connection = entityManager().unwrap(SessionImpl.class).connection();
An example of solving the problem using Session.doWork() is as follows:
private void executeNative(final String query) {
Session session = entityManager.unwrap(Session.class);
session.doWork(new Work() {
#Override
public void execute(Connection connection) throws SQLException {
Statement s = null;
try {
s = connection.createStatement();
s.executeUpdate(query);
}
finally {
if (s != null) {
s.close();
}
}
}
});
}
The JPA API itself doesn't seem to offer this, not surprisingly, but if you're willing to couple your code to a specific implementation, then you can use something like this (Hibernate):
Session hibernateSession = entityManager.unwrap(Session.class);
Connection jdbcConnection = hibernateSession.connection();
Note that Session.connection() is deprecated for removal in Hibernate 4. Consider using Session.doWork() instead.
You must take the underlying delegate using entitymanager.getDelegate() or entitymanager.unwrap(which is the better way), cast it to the specific implementation(in Hibernate it is called Session). Then you can call the connection() method. Be aware this is deprecated, use the Work class instead. Read more here.
In JPA2.0, if need JDBC is por DTO nomodel or entity for query more
complex. Sometimes JPA is not all...
I hope this will help you:
Statement statement = null;
EntityManager em = null;
em = emf.createEntityManager();
EntityTransaction et = em.getTransaction();
if(!et.isActive()) {
et.begin();
}
java.sql.Connection connection = em.unwrap(java.sql.Connection.class);
String qquerry="SELE ...
try {
statement = connection.createStatement();
ResultSet rs = statement.executeQuery(qquerry);
if (!rs.next()) {
return null;
}
else{
wwwwas=rs.getString(4);
}
statement.close();
}
catch (SQLException e) {
System.out.println("\n b-03:"+e);
throw new RuntimeException(e.getMessage(), e);
}
finally {
try {
// em.getTransaction().commit();
if(connection != null )
connection.close();
}
catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
This works awesomely and you can use the connection object elsewhere if needed
SessionImpl sessionImpl = (SessionImpl) session;
Connection conn = sessionImpl.connection();
Where session is the name of the Hibernate Session object
Below is the code that worked for me. We use jpa 1.0, Apache openjpa implementation.
import java.sql.Connection;
import org.apache.openjpa.persistence.OpenJPAEntityManager;
import org.apache.openjpa.persistence.OpenJPAPersistence;
public final class MsSqlDaoFactory {
public static final Connection getConnection(final EntityManager entityManager) {
OpenJPAEntityManager openJPAEntityManager = OpenJPAPersistence.cast(entityManager);
Connection connection = (Connection) openJPAEntityManager.getConnection();
return connection;
}
}

How to use SQLErrorCodeSQLExceptionTranslator and DAO class with #Repository in Spring?

I'm using Spring 3.0.2 and I have a class called MovieDAO that uses JDBC to handle the db. I have set the #Repository annotations and I want to convert the SQLException to the Spring's DataAccessException I have the following example:
#Repository
public class JDBCCommentDAO implements CommentDAO {
static JDBCCommentDAO instance;
ConnectionManager connectionManager;
private JDBCCommentDAO() {
connectionManager = new ConnectionManager("org.postgresql.Driver", "postgres", "postgres");
}
static public synchronized JDBCCommentDAO getInstance() {
if (instance == null)
instance = new JDBCCommentDAO();
return instance;
}
#Override
public Collection<Comment> getComments(User user) throws DAOException {
Collection<Comment> comments = new ArrayList<Comment>();
try {
String query = "SELECT * FROM Comments WHERE Comments.userId = ?";
Connection conn = connectionManager.getConnection();
PreparedStatement stmt = conn.prepareStatement(query);
stmt = conn.prepareStatement(query);
stmt.setInt(1, user.getId());
ResultSet result = stmt.executeQuery();
while (result.next()) {
Movie movie = JDBCMovieDAO.getInstance().getLightMovie(result.getInt("movie"));
comments.add(new Comment(result.getString("text"), result.getInt("score"), user, result.getDate("date"), movie));
}
connectionManager.closeConnection(conn);
} catch (SQLException e) {
e.printStackTrace();
//CONVERT TO DATAACCESSEXCEPTION
}
return comments;
}
}
I Don't know how to get the Translator and I don't want to extends any Spring class, because that is why I'm using the #Repository annotation
You must provide a bean-post processor to get your goal
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
Or use SQLExceptionSubclassTranslator
private SQLExceptionTranslator sqlExceptionTranslator = new SQLExceptionSubclassTranslator();
catch(SQLException e) {
throw sqlExceptionTranslator.doTranslate("<WHICH_TASK>", "<WHICH_SQL_QUERY>", e);
}
instead
JDBC doesn't work very well with #Repository and automatic exception translation, because SQLException is not a runtime exception. #Repository-style exception translation only really works with data access APIs that use runtime exceptions, e.g. Hibernate and JPA.
The #Repository annotation is used by the Spring context to auto-generate a proxy wrapper around your DAO, translating the exceptions as they get thrown. This only works with runtime exceptions, though. Specifically, if your DAO implementation class methods throw SQLException, then so must your interface method signatures, and so must the proxy wrapper, and so the client code must handle that exception, which all rather defeats the point of exception translation.
For JDBC, some coupling to the Spring API is usually necessary, either by extending JdbcDaoSupport and using getExceptionTranslator(), or manually constructing your own SQLExceptionTranslator instance. Either way, you need to catch SQLException inside the DAO and translate it into a DataAccessException.
catch (SQLException e) {
throw new DataAccessException("some message",e);
}

Categories