Should EntityManagerFactory be closed at application shutdown? - java

I have a Java application that has a GUI made with Swing and that uses two databases interchangeably. One of the two databases is mongoDB and the other one is MySQL. Which database to use is chosen with a command line option. For the MySQL database I am also using Hibernate and JPA. The code I have looks like this:
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import java.awt.EventQueue;
import java.util.concurrent.Callable;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
#Command(mixinStandardHelpOptions = true)
public class App implements Callable<Void> {
private static final Logger LOGGER = LogManager.getLogger(App.class);
#Option(names = { "--database" }, description = "'mongo' or 'mysql'")
private String databaseType = "mysql";
public static void main(String[] args) {
new CommandLine(new App()).execute(args);
}
#Override
public Void call() throws Exception {
EventQueue.invokeLater(() -> {
switch (databaseType) {
case "mysql":
EntityManagerFactory emf;
EntityManager entityManager;
try {
emf = Persistence.createEntityManagerFactory("name");
entityManager = emf.createEntityManager();
// other stuff
} catch (Exception e) {
LOGGER.log(Level.ERROR, "MySQL Exception", e);
}
break;
case "mongo":
// mongo stuff, no EntityManagerFactory here
break;
default:
LOGGER.log(Level.ERROR, "--database must be either 'mysql' or 'mongo'");
System.exit(1);
}
//...
try {
View view = new View();
view.setVisible(true);
} catch (Exception e) {
LOGGER.log(Level.ERROR, "Exception", e);
}
});
return null;
}
In mysql case I am creating an EntityManagerFactory and an EntityManager. The entityManager created here is passed as argument to the constructor of the repositories and used throughout the whole life of the application.
I was wondering what is the best practice about closing the entityManager and the factory.
Searching in the documentation I found this:
Closing an EntityManagerFactory should not be taken lightly. It is
much better to keep a factory open for a long period of time than to
repeatedly create and close new factories. Thus, most applications
will never close the factory, or only close it when the application is
exiting.
So I was wondering, what is the difference between closing the factory and entity manager at application shutdown and not closing it? Also in my case I'm declaring emf and entityManager inside the mysql case since are not required for mongodb. In order to close them at application shutdown what should I do? I found something about Runtime.getRuntime().addShutdownHook(). I tried using it like the code below, but it seems like it is not working.
try {
emf = Persistence.createEntityManagerFactory("name");
entityManager = emf.createEntityManager();
Thread closeHook = new Thread(() -> {
if (emf != null) {
entityManager.close();
emf.close();
LOGGER.log(Level.INFO, "Close entity manager and entity manager factory");
}
});
Runtime.getRuntime().addShutdownHook(closeHook);
// other stuff
} catch (Exception e) {
LOGGER.log(Level.ERROR, "MySQL Exception", e);
}

Short answer, yes, it should be closed. And the reason can be found at this answer:
The JVM will release all active resources upon termination; however, this does not ensure that the other end will free the resource too, so explicitly closing resources is in every programmer's best interest.
So in my case, it is true that the EntityManager and factory are closed at application shutdown, but this does not ensure that they are properly dealt with on the other end.
I didn't mention it in my question, but in fact the same thing holds true for the Mongo Client as well (see this answer):
If you ever re-deploy your web application without first restarting your application server, you must ensure that the MongoClient is closed when your web application is shutdown.
About the implementation I made an interface that I called DBInitializer. I instantiated an object of type MongoInitializer or MySQLInitializer (both implementing DBInitializer) inside the main method. See code for more clarity.
DBInitializer:
public interface DBInitializer {
public void startDbConnection();
public void closeDbConnection();
}
MySQLInitializer:
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class MySQLInitializer implements DBInitializer {
private EntityManagerFactory emf;
private EntityManager entityManager;
private final Logger logger = LogManager.getLogger(MySQLInitializer.class);
#Override
public void startDbConnection() {
try {
emf = Persistence.createEntityManagerFactory("name");
entityManager = emf.createEntityManager();
// other stuff
} catch (Exception e) {
logger.log(Level.ERROR, "MySQL Exception", e);
}
}
#Override
public void closeDbConnection() {
if (emf != null) {
entityManager.close();
emf.close();
}
}
}
MongoInitializer:
import com.mongodb.MongoClient;
import com.mongodb.ServerAddress;
public class MongoInitializer implements DBInitializer {
private MongoClient client;
private final Logger logger = LogManager.getLogger(MongoInitializer.class);
#Override
public void startDbConnection() {
try {
client = new MongoClient(new ServerAddress("localhost", 27017));
// other stuff
} catch (Exception e) {
logger.log(Level.ERROR, "Mongo Exception", e);
}
}
#Override
public void closeDbConnection() {
client.close();
}
}
App:
import java.awt.EventQueue;
import java.util.concurrent.Callable;
import DBInitializer;
import MongoInitializer;
import MySQLInitializer;
import View;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
#Command(mixinStandardHelpOptions = true)
public class App implements Callable<Void> {
private static final Logger LOGGER = LogManager.getLogger(App.class);
#Option(names = { "--database" }, description = "Either 'mongo' or 'mysql'")
private String databaseType = "mysql";
public static void main(String[] args) {
new CommandLine(new App()).execute(args);
}
DBInitializer dBInitializer;
#Override
public Void call() throws Exception {
EventQueue.invokeLater(() -> {
try {
switch (databaseType) {
case "mysql":
dBInitializer = new MySQLInitializer();
break;
case "mongo":
dBInitializer = new MongoInitializer();
break;
default:
LOGGER.log(Level.ERROR, "--database must be either 'mysql' or 'mongo'");
System.exit(1);
}
dBInitializer.startDbConnection();
// other stuff
View view = new View();
view.setVisible(true);
} catch (Exception e) {
LOGGER.log(Level.ERROR, "Exception", e);
}
});
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
dBInitializer.closeDbConnection();
}
});
return null;
}
}

what is the difference between closing the factory and entity manager at application shutdown and not closing it?
A potential resource leak (e.g. an unclosed connection pool) vs lack thereof. Also:
I tried using it like the code below, but it seems like it is not working.
Why not use a try-with-resources statement?

Related

EntityManager and createEntityManagerFactory with application.properties

I have to create singleton classes using DAO classes.
Following is a DAO reading class example:
package com.luiz.teste.dao;
import com.luiz.teste.exceptions.postgres.ReadSubjectDaoFindException;
import org.eclipse.microprofile.opentracing.Traced;
import javax.enterprise.context.RequestScoped;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.NoResultException;
import javax.persistence.Persistence;
import javax.persistence.PersistenceException;
#Traced
#ApplicationScoped
public class ReadSubjectDao {
private static ReadSubjectDao instance = new ReadSubjectDao();
protected EntityManager em;
public static ReadSubjectDao getInstance() {
return instance;
}
private ReadSubjectDao() {
if (em == null) {
em = Persistence.createEntityManagerFactory("postgres").createEntityManager();
}
}
public ReadSubject findById(int id) throws ReadSubjectDaoFindException {
try {
return em.find(ReadSubject.class, id);
}
catch (NoResultException e) {
return null;
}
catch (PersistenceException e) {
throw new ReadSubjectDaoFindException(e);
}
}
}
Following is a DAO writing class example:
package com.luiz.teste.dao;
import com.luiz.teste.exceptions.mysql.WriteSubjectDaoFindException;
import com.luiz.teste.exceptions.mysql.WriteSubjectDaoPersistException;
import com.luiz.teste.exceptions.mysql.WriteSubjectDaoMergeException;
import org.eclipse.microprofile.opentracing.Traced;
import javax.enterprise.context.RequestScoped;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.NoResultException;
import javax.persistence.Persistence;
import javax.persistence.PersistenceException;
#Traced
#ApplicationScoped
public class WriteSubjectDao {
private static WriteSubjectDao instance = new WriteSubjectDao();
protected EntityManager em;
public static WriteSubjectDao getInstance() {
return instance;
}
private WriteSubjectDao() {
if (em == null) {
em = Persistence.createEntityManagerFactory("mysql").createEntityManager();
}
}
public WriteSubject findById(int id) throws WriteSubjectDaoFindException {
try {
return em.find(WriteSubject.class, id);
}
catch (NoResultException e) {
return null;
}
catch (PersistenceException e) {
throw new WriteSubjectDaoFindException(e);
}
}
public void persist(WriteSubject writeSubject) throws WriteSubjectDaoPersistException {
EntityTransaction et = em.getTransaction();
try {
et.begin();
em.persist(writeSubject);
et.commit();
}
catch (Exception e) {
if (et.isActive())
et.rollback();
throw new WriteSubjectDaoPersistException(e);
}
}
public void merge(WriteSubject writeSubject) throws WriteSubjectDaoMergeException {
EntityTransaction et = em.getTransaction();
try {
et.begin();
em.merge(writeSubject);
et.commit();
}
catch (Exception e) {
if (et.isActive())
et.rollback();
throw new WriteSubjectDaoMergeException(e);
}
}
}
Following is application.properties:
# Configuration file
# key = value
quarkus.log.console.format=%d{HH:mm:ss} %-5p [%c{2.}] (%t) %X{requestID} %s%e%n
mp.metrics.tags=app=${quarkus.application.name},version=${quarkus.application.version}
%test.mp.metrics.tags=app=app-test,version=1.0.0
mp.openapi.filter=com.luiz.teste.dev.ext.filters.OpenApiFilter
quarkus.swagger-ui.path=/api-docs
quarkus.smallrye-openapi.path=/api-docs-json
quarkus.swagger-ui.always-include=true
quarkus.http.test-port=8083
quarkus.http.test-ssl-port=8446
quarkus.datasource.jdbc.enable-metrics=true
# Postgre - Build time
quarkus.datasource."postgres".db-kind=db2
quarkus.datasource."postgres".jdbc.url=${POSTGRE_JDBC}
quarkus.datasource."postgres".username=${POSTGRE_USER}
quarkus.datasource."postgres".password=${POSTGRE_PASSWORD}
quarkus.hibernate-orm."postgres".datasource=postgres
quarkus.hibernate-orm."postgres".packages=com.luiz.teste.models.postgres
quarkus.hibernate-orm."postgres".log.jdbc-warnings=false
quarkus.hibernate-orm."postgres".log.sql=true
# MySQL - Build time
quarkus.datasource."mysql".db-kind=mysql
quarkus.datasource."mysql".jdbc.url=${MYSQL_JDBC}
quarkus.datasource."mysql".username=${MYSQL_USER}
quarkus.datasource."mysql".password=${MYSQL_PASSWORD}
quarkus.hibernate-orm."mysql".datasource=mysql
quarkus.hibernate-orm."mysql".packages=com.luiz.teste.models.mysql
quarkus.hibernate-orm."mysql".log.jdbc-warnings=false
quarkus.hibernate-orm."mysql".log.sql=true
As far as I've searched through this site (and through https://www.google.com too), I know so far only by using persistence.xml.
How to achieve the same result using only the application.properties when calling createEntityManagerFactory?
UPDATE (2022-01-03): As requested, changed from #RequestScoped to #ApplicationScoped and changed from postgre to postgres.
Finally found a solution to this issue, after searching lots here and googling for any answer.
Instead of manually creating instance field on those classes, to make singleton classes within Quarkus you shall use #Singleton annotation.
Fixed ReadSubjectDao.java:
package com.luiz.teste.dao.postgres;
import com.luiz.teste.exceptions.postgres.ReadSubjectDaoFindException;
import org.eclipse.microprofile.opentracing.Traced;
import javax.inject.Singleton;
import javax.inject.Inject;
import io.quarkus.hibernate.orm.PersistenceUnit;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceException;
#Traced
#Singleton
public class ReadSubjectDao {
#Inject
#PersistenceUnit("postgres")
EntityManager em;
public ReadSubject findById(int id) throws ReadSubjectDaoFindException {
try {
return em.find(ReadSubject.class, id);
}
catch (NoResultException e) {
return null;
}
catch (PersistenceException e) {
throw new ReadSubjectDaoFindException(e);
}
}
}
Fixed WriteSubjectDao.java:
package com.luiz.teste.dao.mysql;
import com.luiz.teste.exceptions.mysql.WriteSubjectDaoFindException;
import com.luiz.teste.exceptions.mysql.WriteSubjectDaoPersistException;
import com.luiz.teste.exceptions.mysql.WriteSubjectDaoMergeException;
import org.eclipse.microprofile.opentracing.Traced;
import javax.inject.Singleton;
import javax.inject.Inject;
import io.quarkus.hibernate.orm.PersistenceUnit;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceException;
import javax.transaction.Transactional;
#Traced
#Singleton
public class WriteSubjectDao {
#Inject
#PersistenceUnit("mysql")
EntityManager em;
public WriteSubject findById(int id) throws WriteSubjectDaoFindException {
try {
return em.find(WriteSubject.class, id);
}
catch (NoResultException e) {
return null;
}
catch (PersistenceException e) {
throw new WriteSubjectDaoFindException(e);
}
}
#Transactional
public void persist(WriteSubject writeSubject) throws WriteSubjectDaoPersistException {
try {
em.persist(writeSubject);
}
catch (Exception e) {
throw new WriteSubjectDaoPersistException(e);
}
}
#Transactional
public void merge(WriteSubject writeSubject) throws WriteSubjectDaoMergeException {
try {
em.merge(writeSubject);
}
catch (Exception e) {
throw new WriteSubjectDaoMergeException(e);
}
}
}
The application.properties remain unchanged.
To call any of those 2 singleton DAO classes, just use #Inject annotation on caller classes, as usual.
Your pattern is extremely weird.
If you want a singleton DAO, just use #ApplicationScoped for the scope of your DAO. Don't make it #RequestScoped and then have a static instance, it's going to be broken.
Then, with Quarkus, you shouldn't create the EntityManagerFactory yourself. You can just inject an EntityManager with:
#Inject
#PersistenceUnit("postgre")
EntityManager entityManager;
and you're done.

Cannot close derby connection with EntityManagerFactory

I need to compress a database inside a zip file after it's been created (and delete the original version of the database). After creating it using EntityManagerFactory I close it so that the connection is freed and I can manipulate the database file.
The problem is that even if I close the EntityManagerFactory the database directory is still blocked because it says it is in use (it shouldn't?).
I created a mre recreating the problem...
import java.util.HashMap;
import java.util.Map;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class Main {
private static EntityManagerFactory entityManagerFactory;
public static void main(String[] args) {
String dbURL = "jdbc:derby:C:\\Users\\XXX\\Desktop\\MyDB;create=true";
Map<String, String> persistenceMap = new HashMap<String, String>();
persistenceMap.put("javax.persistence.jdbc.url", dbURL);
entityManagerFactory = Persistence.createEntityManagerFactory("PUBLIC", persistenceMap);
entityManagerFactory.close();
entityManagerFactory = null;
System.out.println("DONE");
//I should be able to delete the database directory now (I'm not).
try {
Thread.sleep(Long.MAX_VALUE);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Problem solved, I had to shutdown the database.
try {
DriverManager.getConnection(
"jdbc:derby:" + TEMP + "/" + projectName + ";user=xxxx;password=xxxx;shutdown=true");
} catch (SQLException sqle) {
//If catches exception went well
}

Using neo4j-jdbc open-connection is bottleneck

I am using neo4-jdbc with pool lib BasicDataSource.
I had huge latency problems so we profiled the app and we found out that opening connection is the cause. I didnt understand why open-connection takes so long we using pool. this is screenshot from our profiles:
This is how the Neo4jDatasourceRemote looks like:
package com.comp.wm.common.repo;
import com.comp.wm.common.utils.Constants;
import org.apache.commons.dbcp.BasicDataSource;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import javax.annotation.PostConstruct;
import java.sql.Connection;
import java.sql.SQLException;
private final Logger logger = Logger.getLogger(Neo4jDataSourceRemote.class);
private BasicDataSource ds;
#Value("${neo4j.host:localhost}")
private String NEO4J_HOST;
#Value("${neo4j.port:7474}")
private String NEO4J_PORT;
#Value("${neo4j.username:nouser}")
private String NEO4J_USERNAME;
#Value("${neo4j.password:nopass}")
private String NEO4J_PASSWORD;
#Value("${neo4j.pool.size:200}")
private int NEO4J_POOL_SIZE;
private String GetUrl() {
return String.format(Constants.NEO4J_JDBC_CONNECTIVITY_STRING, NEO4J_HOST, NEO4J_PORT);
}
#PostConstruct
public void init(){
ds = new BasicDataSource();
ds.setInitialSize(300);
ds.setDriverClassName("org.neo4j.jdbc.Driver");
ds.setUrl(GetUrl());
ds.setUsername(NEO4J_USERNAME);
ds.setPassword(NEO4J_PASSWORD);
}
#Override
public Connection openConnection() throws SQLException {
return this.ds.getConnection();
}
#Override
public void closeConnection(Connection conn) {
try {
if (conn != null)
conn.close();
} catch (SQLException ex) {
logger.info("error closing connection", ex);
}
}
}
and this is a sample of how I execute query against the graph:
public List<NearbyItem> executeQuery(..) {
conn = neo4jDataSource.openConnection();
String getUsersStatement = "some query..";
try (PreparedStatement ps = conn.prepareStatement(getUsersStatement)) {
..
ResultSet rs = ps.executeQuery();
while (rs.next()) {
...
}
} catch (Exception e) {
throw new RuntimeException("Error returning userId=" + userIdInput, e);
} finally {
neo4jDataSource.closeConnection(conn);
}
return distItemDatas;
}
any ideas?
Based on comments above, I'll add this as a reply.
By default Neo4j runs in the http interface 10 threads for core. You can tweak the total number of threads in neo4j-server.properties
org.neo4j.server.webserver.maxthreads=200
However the more threads you have the more you're suffering from context switches and lock contention. If you increase the number of threads I won't expect a large increase of throughput, you just shift the point where you have to wait. From initialization (openCOnnection) to processing the query.

Orientdb: Import database in memory and use it as graph

This is my Java DB class in which I open database and import database export file in memory graph database, where I define all database schema information for testing cases.
Operation going well but how can I access the imported database as graph instance and not document instance of database?
I try so many things but I have failed...
Error :
The Person class exist in my schema so something else is going wrong.
Caused by:
> com.orientechnologies.orient.core.exception.OCommandExecutionException:
> Class 'PERSON' was not found in current database
Code:
import com.orientechnologies.orient.core.db.tool.ODatabaseExportException;
import com.orientechnologies.orient.core.db.tool.ODatabaseImport;
import com.orientechnologies.orient.core.sql.OCommandSQL;
import com.tinkerpop.blueprints.Vertex;
import com.tinkerpop.blueprints.impls.orient.OrientGraphFactory;
import com.tinkerpop.blueprints.impls.orient.OrientGraphNoTx;
import lombok.Getter;
import java.io.IOException;
public class Db {
#Getter private static OrientGraphFactory factory;
#Getter private static OrientGraphNoTx graph;
static public void main(String[] args){
open("memory","database");
importDB("/schemas/diary-11202016.gz");
try {
seed();
} catch (InterruptedException e) {
e.printStackTrace();
}
closeDB();
}
public static void open(String dbType, String dbUrl) {
String dbInfo = dbType + ":" + dbUrl;
System.out.println(dbInfo);
factory = new OrientGraphFactory(dbInfo, "root", "root").setupPool(1, 10);
graph = factory.getNoTx();
}
public static void importDB(String path) {
try {
ODatabaseImport importDb = new ODatabaseImport(graph.getRawGraph(), Db.class.getResourceAsStream(path), (iText) -> {
System.out.print(iText);
});
importDb.setMerge(true);
importDb.importDatabase();
importDb.close();
System.out.println("\nImporting database: OK");
} catch (ODatabaseExportException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void seed() throws InterruptedException {
System.out.println("Starting to seed...");
for (Vertex v : (Iterable<Vertex>) graph.command( new OCommandSQL("select from Person")).execute()) {
System.out.println("- Bought: " + v.getProperty("name"));
}
System.out.println("Finish to seed...");
}
public static void closeDB() {
factory.close();
}
}
Replace the following piece of code
ODatabaseImport importDb = new ODatabaseImport(graph.getRawGraph(), Db.class.getResourceAsStream(path), (iText) -> {
System.out.print(iText);
});
importDb.setMerge(true);
with
ODatabaseImport importDb = new ODatabaseImport(graph.getRawGraph(), path, (iText) -> {
System.out.print(iText);
});
// importDb.setMerge(true);

Multiple messages on a Grizzly Websocket Connection

We are using Websockets from the Grizzly project and had expected that the implementation would allow multiple incoming messages over a connection to be processed at the same time. It appears that this is not the case or there is a configuration step that we have missed. To validate this I have created a modified echo test that delays in the onMessage after echoing the text. When a client sends multiple messages over the same connection the server always blocks until onMessage completes before processing a subsequent message. Is this the expected functionality?
The simplified server code is as follows:
package com.grorange.samples.echo;
import java.util.concurrent.atomic.AtomicBoolean;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.grizzly.http.server.NetworkListener;
import org.glassfish.grizzly.websockets.DataFrame;
import org.glassfish.grizzly.websockets.WebSocket;
import org.glassfish.grizzly.websockets.WebSocketAddOn;
import org.glassfish.grizzly.websockets.WebSocketApplication;
import org.glassfish.grizzly.websockets.WebSocketEngine;
public class Echo extends WebSocketApplication {
private final AtomicBoolean inMessage = new AtomicBoolean(false);
#Override
public void onClose(WebSocket socket, DataFrame frame) {
super.onClose(socket, frame);
System.out.println("Disconnected!");
}
#Override
public void onConnect(WebSocket socket) {
System.out.println("Connected!");
}
#Override
public void onMessage(WebSocket socket, String text) {
System.out.println("Server: " + text);
socket.send(text);
if (this.inMessage.compareAndSet(false, true)) {
try {
Thread.sleep(10000);
} catch (Exception e) {}
this.inMessage.set(false);
}
}
#Override
public void onMessage(WebSocket socket, byte[] bytes) {
socket.send(bytes);
if (this.inMessage.compareAndSet(false, true)) {
try {
Thread.sleep(Long.MAX_VALUE);
} catch (Exception e) {}
this.inMessage.set(false);
}
}
public static void main(String[] args) throws Exception {
HttpServer server = HttpServer.createSimpleServer("http://0.0.0.0", 8083);
WebSocketAddOn addOn = new WebSocketAddOn();
addOn.setTimeoutInSeconds(60);
for (NetworkListener listener : server.getListeners()) {
listener.registerAddOn(addOn);
}
WebSocketEngine.getEngine().register("", "/Echo", new Echo());
server.start();
Thread.sleep(Long.MAX_VALUE);
}
}
The simplified client code is:
Yes, it's expected.
The way to go is to pass message processing, inside onMessage, to a different thread.

Categories