I'm trying to modify existing Java app (WildFly, Jboss, oracle) which currently working fine as using persistence-unit and EntityManager connect to Oracle database(using standalone.xml and persistence.xml). However, I need to create every time new connection to database for the user which calls new GET API Endpoint using credentials from the HttpHeaders. Currently, I'm creating new entitymanager object which session is commit, rollback nad close. Unfortunately time response for every call become higher and higher. There is warning about "PersistenceUnitUser" being already registered and memory usage constantly growing. So that is bad solution.
Is there any proper way to do it, which works witout any harms ?
P.S.
Currently app using standalone.xml and persistence.xml. And that is working fine. I'm calling java api endpoint using entity manager being connected as Admin user/pass but I need to create new connection using user/pass from the httpHeaders and call one sql statement to see proper results as ORACLE uses reserved word such us: 'user'. For instance : select * from table where create_usr = user. When done 'Main EntityManager will use data from it to continue some process.
Please see code example below :
#GET
#Path("/todo-list-enriched")
#Produces(MediaType.APPLICATION_JSON)
public Response getToDoListEnriched(#Context HttpHeaders httpHeaders, #QueryParam("skip") int elementNumber, #QueryParam("take") int pageSize, #QueryParam("orderby") String orderBy)
{
String userName = httpHeaders.getHeaderString(X_USER_NAME);
String userName = httpHeaders.getHeaderString(X_PASSWORD);
EntityManager entityManager = null;
try {
Map<String, String> persistenceMap = new HashMap<String, String>();
persistenceMap.put("hibernate.dialect","org.hibernate.dialect.Oracle8iDialect");
persistenceMap.put("hibernate.connection.username", asUserName);
persistenceMap.put("hibernate.connection.password", asPassword);
EntityManagerFactory emf = Persistence.createEntityManagerFactory("PersistenceUnitUser", persistenceMap);
entityManager = emf.createEntityManager();
if (!entityManager.getTransaction().isActive()) {
entityManager.getTransaction().begin();
}
-- Do some works as select, update, select
-- and after that
if (entityManager.getTransaction().isActive()) {
entityManager.getTransaction().commit();
}
}
catch (Exception ex)
{
if (entityManager != null && entityManager.getTransaction().isActive()) {
entityManager.getTransaction().rollback();
}
}
finally {
if (entityManager != null && entityManager.isOpen()) {
entityManager.close();
}
}
}
}
``
Best Regards
Marcin
You should define a connection pool and a datasource in the standalone.xml (cf. https://docs.wildfly.org/26.1/Admin_Guide.html#DataSource) and then use it in your persistence.xml and inject the EntitytManager in your rest service class (cf. https://docs.wildfly.org/26.1/Developer_Guide.html#entity-manager).
You may look at this example application: https://github.com/wildfly/quickstart/tree/main/todo-backend
I have recently created a web service that uses a static method in Java to obtain a list of items from the database.
The web service works perfectly and returns JSON back to the caller. However, it works only once. If you try to refresh or make a new request, I get a EntityManagerFactory is closed error.
Here's how the Web Service class looks like:
public class WebService extends HttpServlet {
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//obtain the list of vehicles from the database
List<Vehicle> vehicles = ExecuteVehicle.getVehicleList();
//create the Gson object and generate the Json
Gson gson = new Gson();
JsonElement element = gson.toJsonTree(vehicles, new TypeToken<List<Vehicle>>(){}.getType());
//send the list of vehicles
JsonArray jsonArray = element.getAsJsonArray();
resp.setContentType("application/json");
resp.getWriter().print(jsonArray);
}
}
As you can see, the list of vehicles is being populated using the ExecuteVehicle.getVehicleList() method.
Here's how that method looks like:
public static List<Vehicle> getVehicleList(){
//open a Session
Session session = HibernateUtilities.getSessionFactory().openSession();
//start a transaction
session.beginTransaction();
//SELECT STATEMENT for the entire list of Vehicles
Query<Vehicle> query = session.getNamedQuery("SelectAllVehicles"); //query name is declared in the mapping file
List<Vehicle> vehicles = query.list();
//commit the changes and end the transaction
session.getTransaction().commit();
//close the Session
session.close();
//close the SessionFactory
HibernateUtilities.getSessionFactory().close();
return vehicles;
}
Here's the HibernateUtilities class that takes care of the Session and so on:
public class HibernateUtilities {
private static SessionFactory sessionFactory;
private static StandardServiceRegistry standardServiceRegistry;
static{
try {
//configure and build the service registry
standardServiceRegistry = new StandardServiceRegistryBuilder().configure("hibernate.cfg.xml").build();
//create the metadata
Metadata metadata = new MetadataSources(standardServiceRegistry).getMetadataBuilder().build();
//build the SessionFactory
sessionFactory = metadata.getSessionFactoryBuilder().build();
} catch (HibernateException e) {
//in case the SessionFactory cannot be built, then the stackTrace is displayed
e.printStackTrace();
}
}
//method that returns the Hibernate session factory
public static SessionFactory getSessionFactory(){
return sessionFactory;
}
}
The question I have is - how can I avoid the EntityManagerFactory is closed error. Furthermore, I will have to obtain this list again and again, in a real time manner. Is that feasible with Hibernate? To obtain a list of items from a database in a real-time manner (say, every 2 seconds or so)? I know this depends on the number of items and so on, but I'm asking from a technical standpoint - from what I understand, opening and closing the Session takes a long time - could I do this over and over again in the same Session and if so, how?
I would say that you are doing too much there.
You have to flush/commit the transaction and close the session as you are using the openSession() method of the factory.
But i dont think you need to close the SessionFactory itself
//close the SessionFactory
HibernateUtilities.getSessionFactory().close();
remove this line and you can would be able to use the factory many times.
My MongoDB is getting a lot of "xxx connections now open" show at the console, i cant understand why, i created a DataStore Factory and im using Inject, why it dont close the connection? im using .getDB.requestDone() too...
where i get my DS:
public class DSFactory {
Morphia morphia = new Morphia();
Datastore ds = null;
public DSFactory() {
morphia.map(User.class);
try {
this.ds = morphia.createDatastore(new MongoClient("localhost"),
"userDB");
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public Datastore getInstance() {
return ds;
}
}
my DAO:
public class UserDAO {
#Inject DSFactory dsFactory;
public void newUser(User user) {
dsFactory.getInstance().save(user);
dsFactory.getInstance().getDB().requestDone();
}
}
every newUser i add, is a new connection in the MongoDB, so for 30new users, i will finish with "30 or more connections open", it just go to low number or 0 when i close the eclipse
I assume you inject UserDao somewhere, when that happens the container will try to create a new DSFactory. Each UserDao will try to create its own DSFactory, with each factory having its own Morphia datastore.
You probably one want one morphia datastore at a time, you could try to make the datastore into a #Singleton so each DAO gets the same DSFactory.
We have been using annotation based JPA with Hibernate as JpaVendorAdapter.
We had to schedule a job to refresh an entire table data using spring scheduler.
The code is as follows,
#Scheduled(fixedDelay=120000)
public void refreshTable() {
EntityManager em = null;
try {
EntityManagerFactory emf = entityManager.getEntityManagerFactory();
em = emf.createEntityManager();
em.getTransaction().begin();
/// do something like delete and fill table
// this block is done for the sake of batch mode operation
em.getTransaction().commit();
} catch (Exception e) {
logger.error("Failed to refresh table", e);
} finally{
if(em != null && em.getTransaction().isActive()){
em.getTransaction().rollback();
logger.info("Failure while refreshing table, rolling back transaction.");
}
}
}
This used to build memory utilization and caused application hang.
We added, at the end of finally block,
if(em != null){
em.close();
}
Which solved the memory problem.
So, why does not EntityManager execute close() while being GC'ed?
The JPAConnector has various connections associated with it and it does not close all of them whereas waiting for garbage collector to do it is not a wise approach.
Closing the connections(i.e EntityManager and EntityManagerFactory) as and when they are no more needed is the best way to address this issue.
Hope this helps!
Good luck!
We have a JPA application (using hibernate) and we need to pass a call to a legacy reporting tool that needs a JDBC database connection as a parameter. Is there a simple way to get access to the JDBC connection hibernate has setup?
As per the hibernate docs here,
Connection connection()
Deprecated. (scheduled for removal in 4.x). Replacement depends on need; for doing direct JDBC stuff use
doWork(org.hibernate.jdbc.Work) ...
Use Hibernate Work API instead:
Session session = entityManager.unwrap(Session.class);
session.doWork(new Work() {
#Override
public void execute(Connection connection) throws SQLException {
// do whatever you need to do with the connection
}
});
Where you want to get that connection is unclear. One possibility would be to get it from the underlying Hibernate Session used by the EntityManager. With JPA 1.0, you'll have to do something like this:
Session session = (Session)em.getDelegate();
Connection conn = session.connection();
Note that the getDelegate() is not portable, the result of this method is implementation specific: the above code works in JBoss, for GlassFish you'd have to adapt it - have a look at Be careful while using EntityManager.getDelegate().
In JPA 2.0, things are a bit better and you can do the following:
Connection conn = em.unwrap(Session.class).connection();
If you are running inside a container, you could also perform a lookup on the configured DataSource.
If you are using JAVA EE 5.0, the best way to do this is to use the #Resource annotation to inject the datasource in an attribute of a class (for instance an EJB) to hold the datasource resource (for instance an Oracle datasource) for the legacy reporting tool, this way:
#Resource(mappedName="jdbc:/OracleDefaultDS") DataSource datasource;
Later you can obtain the connection, and pass it to the legacy reporting tool in this way:
Connection conn = dataSource.getConnection();
if you use EclipseLink:
You should be in a JPA transaction to access the Connection
entityManager.getTransaction().begin();
java.sql.Connection connection = entityManager.unwrap(java.sql.Connection.class);
...
entityManager.getTransaction().commit();
Hibernate 4 / 5:
Session session = entityManager.unwrap(Session.class);
session.doWork(connection -> doSomeStuffWith(connection));
Since the code suggested by #Pascal is deprecated as mentioned by #Jacob, I found this another way that works for me.
import org.hibernate.classic.Session;
import org.hibernate.connection.ConnectionProvider;
import org.hibernate.engine.SessionFactoryImplementor;
Session session = (Session) em.getDelegate();
SessionFactoryImplementor sfi = (SessionFactoryImplementor) session.getSessionFactory();
ConnectionProvider cp = sfi.getConnectionProvider();
Connection connection = cp.getConnection();
The word pure doesn't match to the word hibernate.
EclipseLink
Getting a JDBC Connection from an EntityManager
It's somewhat straightforward as described in above link.
Note that the EntityManager must be joined to a Transaction or the unwrap method will return null. (Not a good move at all.)
I'm not sure the responsibility of closing the connection.
// --------------------------------------------------------- EclipseLink
try {
final Connection connection = manager.unwrap(Connection.class);
if (connection != null) { // manage is not in any transaction
return function.apply(connection);
}
} catch (final PersistenceException pe) {
logger.log(FINE, pe, () -> "failed to unwrap as a connection");
}
Hibernate
It should be, basically, done with following codes.
// using vendor specific APIs
final Session session = (Session) manager.unwrap(Session.class);
//return session.doReturningWork<R>(function::apply);
return session.doReturningWork(new ReturningWork<R>() {
#Override public R execute(final Connection connection) {
return function.apply(connection);
}
});
Well, we (at least I) might don't want any vendor-specific dependencies. Proxy comes in rescue.
try {
// See? You shouldn't fire me, ass hole!!!
final Class<?> sessionClass
= Class.forName("org.hibernate.Session");
final Object session = manager.unwrap(sessionClass);
final Class<?> returningWorkClass
= Class.forName("org.hibernate.jdbc.ReturningWork");
final Method executeMethod
= returningWorkClass.getMethod("execute", Connection.class);
final Object workProxy = Proxy.newProxyInstance(
lookup().lookupClass().getClassLoader(),
new Class[]{returningWorkClass},
(proxy, method, args) -> {
if (method.equals(executeMethod)) {
final Connection connection = (Connection) args[0];
return function.apply(connection);
}
return null;
});
final Method doReturningWorkMethod = sessionClass.getMethod(
"doReturningWork", returningWorkClass);
return (R) doReturningWorkMethod.invoke(session, workProxy);
} catch (final ReflectiveOperationException roe) {
logger.log(Level.FINE, roe, () -> "failed to work with hibernate");
}
OpenJPA
Runtime Access to DataSource
OPENJPA-1803 Unwrap EntityManager to Connection
I'm not sure OpenJPA already serves a way using unwrap(Connection.class) but can be done with the way described in one of above links.
It's not clear the responsibility of closing the connection. The document (one of above links) seems saying clearly but I'm not good at English.
try {
final Class<?> k = Class.forName(
"org.apache.openjpa.persistence.OpenJPAEntityManager");
if (k.isInstance(manager)) {
final Method m = k.getMethod("getConnection");
try {
try (Connection c = (Connection) m.invoke(manager)) {
return function.apply(c);
}
} catch (final SQLException sqle) {
logger.log(FINE, sqle, () -> "failed to work with openjpa");
}
}
} catch (final ReflectiveOperationException roe) {
logger.log(Level.FINE, roe, () -> "failed to work with openjpa");
}
Hibernate uses a ConnectionProvider internally to obtain connections. From the hibernate javadoc:
The ConnectionProvider interface is not intended to be exposed to the application. Instead it is used internally by Hibernate to obtain connections.
The more elegant way of solving this would be to create a database connection pool yourself and hand connections to hibernate and your legacy tool from there.
I ran into this problem today and this was the trick I did, which worked for me:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("DAOMANAGER");
EntityManagerem = emf.createEntityManager();
org.hibernate.Session session = ((EntityManagerImpl) em).getSession();
java.sql.Connection connectionObj = session.connection();
Though not the best way but does the job.
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;
}
}
I'm using a old version of Hibernate (3.3.0) with a newest version of OpenEJB (4.6.0). My solution was:
EntityManagerImpl entityManager = (EntityManagerImpl)em.getDelegate();
Session session = entityManager.getSession();
Connection connection = session.connection();
Statement statement = null;
try {
statement = connection.createStatement();
statement.execute(sql);
connection.commit();
} catch (SQLException e) {
throw new RuntimeException(e);
}
I had an error after that:
Commit can not be set while enrolled in a transaction
Because this code above was inside a EJB Controller (you can't commit inside a transaction). I annotated the method with #TransactionAttribute(value = TransactionAttributeType.NOT_SUPPORTED) and the problem was gone.
Here is a code snippet that works with Hibernate 4 based on Dominik's answer
Connection getConnection() {
Session session = entityManager.unwrap(Session.class);
MyWork myWork = new MyWork();
session.doWork(myWork);
return myWork.getConnection();
}
private static class MyWork implements Work {
Connection conn;
#Override
public void execute(Connection arg0) throws SQLException {
this.conn = arg0;
}
Connection getConnection() {
return conn;
}
}
I am a little bit new to Spring Boot, I have needing the Connection object to send it to Jasperreport also, after trying the different answers in this post, this was only useful for me and, I hope it helps someone who is stuck at this point.
#Repository
public class GenericRepository {
private final EntityManager entityManager;
#Autowired
public GenericRepository(EntityManager entityManager, DataSource dataSource) {
this.entityManager = entityManager;
}
public Connection getConnection() throws SQLException {
Map<String, Object> properties = entityManager.getEntityManagerFactory().getProperties();
HikariDataSource dataSource = (HikariDataSource) properties.get("javax.persistence.nonJtaDataSource");
return dataSource.getConnection();
}
}