Get hold of a JDBC Connection object from a Stateless Bean - java

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

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/

Perform VACUUM FULL with JPA

I'm using a PostgreSQL DB and I would like to start VACUUM FULL using JPA EntityManager.
Version 1
public void doVacuum(){
entityManager.createNativeQuery("VACUUM FULL").executeUpdate()
}
throws TransactionRequiredException
Version 2
#Transactional
public void doVacuum(){
entityManager.createNativeQuery("VACUUM FULL").executeUpdate()
}
throws PersistenceException "VACUUM cannot run inside a transaction block"
Version 3
public void doVacuum(){
entityManager.createNativeQuery("VACUUM FULL").getResultList()
}
vacuum is performed but after that I get PersistenceException "No results"
What is the correct way to start this sql command?
As Alay Hay mentioned, using the underlying connection will work:
public void doVacuum(){
org.hibernate.Session session = entityManager.unwrap(org.hibernate.Session);
org.hibernate.internal.SessionImpl sessionImpl = (SessionImpl) session; // required because Session doesn't provide connection()
java.sql.Connection connection = sessionImpl.connection();
connection.prepareStatement("VACUUM FULL").execute();
}
Here is a solution that does not require cast to internal implementation of Hibernate Session. Please keep in mind that VACUUM cannot be run in transaction block, this is why you need to set autoCommit to true.
Session session = entityManager.unwrap(Session.class);
session.doWork(new Work() {
#Override
public void execute(Connection connection) throws SQLException {
connection.setAutoCommit(true);
connection.prepareStatement("VACUUM FULL").execute();
connection.setAutoCommit(false);
}
});

How to find out the transaction isolation level used for the particular query in hibernate?

I am using Spring MVC and hibernate. My underlying database is Sybase ASA. Inside my DAO I want to find out what is the transaction level used for the query
This is what my DAO has.
Session session = getSession();
String SQL_QUERY = "select ..... ";
Query query = session.createSQLQuery(SQL_QUERY);
query.executeUpdate();
I referred to this link but this seems to be outdated so doesn't work
What is default isolation level hibernate uses if not explicitely set?
I would say that question is raised incorrectly: a query itself doesn't have any isolation level. An Isolation level is a feature of a transaction.
So you, most probably, want to know what is the isolation level of current transaction? Hence you, most probably, do not manage this level by your code. In this case it is managed by DBMS default or current settings.
One of possible ways to explore it is described here:
try {
session = getSessionFactory().openSession();
txn = session.beginTransaction();
session.doWork(new Work() {
#Override
public void execute(Connection connection) throws SQLException {
LOGGER.debug("Transaction isolation level is {}", Environment.isolationLevelToString(connection.getTransactionIsolation()));
}
});
txn.commit();
} catch (RuntimeException e) {
if ( txn != null && txn.isActive() ) txn.rollback();
throw e;
} finally {
if (session != null) {
session.close();
}
}

JOOQ initializing DAO Best Approach

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

How to get java.sql.Connection object from Hibernate Session

I have requirement where I need java.sql.Connection. But I am using Hibernate here. Somehow I researched and I found below alternative but that's not working.
import org.hibernate.connection.ProxoolConnectionProvider;
public class ConnectionDB{
//I have imported below class
ProxoolConnectionProvider proxoolProvider = new ProxoolConnectionProvider();
org.hibernate.cfg.Configuration cfg = HibernateUtil.getConfiguration();//this method will return configuration
java.util.Properties props = cfg.getProperties();//This will return Properties Object
//Using properties object I just tried to get The Connection Object by following method
proxoolConn.configure(props);// I just configured the Porperties object
proxoolConn.getConnection();
}
But no luck I just end-up with no exception in console .. I am using Struts 2, Hibernate and JasperReports.
Can any one help me to get the connection object from Hibernate?
The following code assumes you have an existing and open Hibernate org.hibernate.Session:
public void doWorkOnConnection(Session session) {
session.doWork(new Work() {
public void execute(Connection connection) throws SQLException {
//use the connection here...
}
});
}
Should you need information on how to use the above classes, please read the Hibernate 3.5 Javadoc. Specifically, read Session and then Work.
You can also downcast the Session method into a SessionImpl and get the connection object easily:
SessionImpl sessionImpl = (SessionImpl) session;
Connection conn = sessionImpl.connection();

Categories