EntityManagerFactory is closed when dynamic load persistence data in java - java

main()
{
createEntityManagerFactory(model.getDriver(), model.getUrl(), model.getUser(), model.getPassword());
}
#SuppressWarnings("unused")
public static void createEntityManagerFactory(String driver, String url, String username, String password) {
Map<String, String> persistenceMap = new HashMap<String, String>();
persistenceMap.put("javax.persistence.jdbc.driver", driver);
persistenceMap.put("javax.persistence.jdbc.url", url);
persistenceMap.put("javax.persistence.jdbc.user", username);
persistenceMap.put("javax.persistence.jdbc.password", password);
try {
if (entityManagerFactory == null)
entityManagerFactory = Persistence.createEntityManagerFactory("XYZAPI", persistenceMap);
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
public static EntityManagerFactory getEntityManagerFactory() {
return entityManagerFactory;
}
This is my code which call on server Startup.
And this my get Entity Manager function.
public static EntityManager getDBManager() {
EntityManager entityManager = null;
EntityManagerFactory entityManagerFactory =
Configuration.getEntityManagerFactory();
if(entityManagerFactory != null){
entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
}
return entityManager;
}
But when i hit first time then i am getting data and response able connect database but in second time when i hit then it give exception java.lang.IllegalStateException: EntityManagerFactory is closed
And i am getting Exception here
entityManager = entityManagerFactory.createEntityManager();
At this line please suggest me how to fix this issue i have to load mysql user id and password at server startup time .

Related

Already have an associated managed connection (using parallelStream().foreach())

javax.persistence.PersistenceException: org.hibernate.TransactionException: Already have an associated managed connection
Caused by: org.hibernate.TransactionException: Already have an associated managed connection
I am using parallelStream().foreach() Works on multithreading concept :
private void loadHcpDataIntoCassandra(ResultSet srcHcpData) throws SQLException {
List<Map<String, Object>> hcpDataList = resultSetToList(srcHcpData);
Cluster cluster = HcpDao.getCassandraConnection();
List<String> tblSpecs = HcpDao.getTableSpecs();
Session session = cluster.connect(tblSpecs.get(0));
//Call prepareHcpAndLoad() method :-
hcpDataList.parallelStream().forEach(hcpMap -> prepareHcpAndLoad(hcpMap, session));
cluster.close();
}
I got above mention Exception, and i replace parallelStream().forEach to
for (Map<String,Object> hcpMap : hcpDataList) {
prepareHcpAndLoad(hcpMap, session);
}
The enhance for loop is perfectly work for me. But I need multi-thread concept. How to solve this problem even i use parallelStream().foreach()
private static void prepareHcpAndLoad(Map<String, Object> hcpMap, Session session) {
String hcpHceId = "";
for (Map.Entry<String, Object> entry : hcpMap.entrySet()) {
String colName = entry.getKey();
Object hcpTableRow = entry.getValue();
hcpMasterData.setHcpHceId(hcpTableRow.toString());
hcpHceId = hcpTableRow.toString();
}
/** Get MDM_id */
MdmId mdm = new MdmId();
mdm.setHcpHceId(hcpHceId);
String mdmId = getMdmId(mdm);
/** update mdmId */
hcpMasterData.setMdmId(mdmId);
mapper.save(hcpMasterData);
}
//#PersistenceContext
#PersistenceContext(type = PersistenceContextType.TRANSACTION)
private static EntityManager em = getEntityManager();
public static String getMdmId(MdmId mdm) {
if(em == null) {
em = getEntityManager();
}
String mdmId = "";
EntityTransaction tr = em.getTransaction();
try {
tr.begin(); //Error Line
em.persist(mdm);
em.flush();
mdmId = Long.toString(mdm.getId());
tr.commit();
} catch (Exception error) {
logger.error(error.getMessage());
error.printStackTrace();
}
return mdmId;
}
private static EntityManager getEntityManager() {
return Persistence.createEntityManagerFactory("sql-connection").createEntityManager();
}

How to fix LazyInitializationException in Java?

I work on a small project and I have 2 tables, User and Application. A user can have multiple applications and an application might be used by multiple user, so it is a many-to many relation between them. Each table has some fields(id, name, password, technologies etc) and I also declared 2 arraylists both in User and Application class with the #ManyToMany adnotation. Problem is that in my Business Layer i wrote a method which should add an application to a user and when I try to do user.getListOfApplications().add(app) it gives me that exception...
public class ManagerHibernate
{
private SessionFactory sessionFactory;
public void setup()
{
sessionFactory = new Configuration().configure().buildSessionFactory();
}
public void exit()
{
sessionFactory.close();
}
public void create(Object obj)
{
Session session = sessionFactory.openSession();
session.beginTransaction();
session.save(obj);
session.getTransaction().commit();
session.close();
}
public Object read(Class<?> c, int idObj)
{
Session session = sessionFactory.openSession();
session.beginTransaction();
Object obj = session.get(c, idObj);
System.out.println(obj);
session.getTransaction().commit();
session.close();
return obj;
}
public void update(Object obj)
{
Session session = sessionFactory.openSession();
session.beginTransaction();
session.update(obj);
session.getTransaction().commit();
session.close();
}
public void delete(Object obj)
{
Session session = sessionFactory.openSession();
session.beginTransaction();
session.delete(obj);
session.getTransaction().commit();
session.close();
}
public <T> List<T> loadAllData(Class<T> type)
{
Session session = sessionFactory.openSession();
session.beginTransaction();
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<T> criteria = builder.createQuery(type);
criteria.from(type);
List<T> data = session.createQuery(criteria).getResultList();
session.getTransaction().commit();
session.close();
return data;
}
}
public Boolean addNewApplicationToUser(String userUserName, String applicationName)
{
int okUser = 0;
int okApp = 0;
listOfApplications = managerHibernate.loadAllData(Application.class);
listOfUsers = managerHibernate.loadAllData(User.class);
User user = null;
Application app = null;
for(Application index: listOfApplications)
{
if(index.getApplicationName().equals(applicationName))
{
okApp = 1;
app = index;
}
}
for(User index: listOfUsers)
{
if(index.getUserUserName().equals(userUserName))
{
okUser = 1;
user = index;
}
}
if(okUser == 0 || okApp == 0)
return false;
else
{
user.getListOfApplications().add(app);
//app.getUserList().add(user);
return true;
}
}
The method addNewApplicationToUser is written in another class called ControllerHibernate. Only the else branch is important, the rest is to check if the parameters do actually exist in the database
The issue starts when you are loading data with the following method managerHibernate.loadAllData
public <T> List<T> loadAllData(Class<T> type)
{
// New session was opened here
Session session = sessionFactory.openSession();
session.beginTransaction();
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<T> criteria = builder.createQuery(type);
criteria.from(type);
List<T> data = session.createQuery(criteria).getResultList();
session.getTransaction().commit();
session.close();
//session is close here
return data;
}
So when you are loading data the hibernate framework will only load the user object. Since you have opted to use lazy loading in your model class the application values will be loaded only when your try to access the list. Since you have already closed your session the framework can no longer get the application list resulting in lazy loading exception.
listOfApplications = managerHibernate.loadAllData(Application.class);
//loading user data and close the session associated with it
listOfUsers = managerHibernate.loadAllData(User.class);
User user = null;
Application app = null;
for(Application index: listOfApplications)
{
if(index.getApplicationName().equals(applicationName))
{
okApp = 1;
app = index;
}
}
for(User index: listOfUsers)
{
if(index.getUserUserName().equals(userUserName))
{
okUser = 1;
user = index;
}
}
if(okUser == 0 || okApp == 0)
return false;
else
{
// when you run this line the hibernate framework will try to retrieve the application data.Since you have the closed session lazy load exception occurs
user.getListOfApplications().add(app);
return true;
}
Ways to overcome this issue
1) Try to keep your session open so that the application data is can be fetched by your framework
2) Change lazy loading to eager loading in your model pojo class (Since you are using many to many relationship not advisable to use this way)
since there is no transaction for fetching the lazy listofApplication in user you need to fetch it first. in order to do so you can change loadAllData as follow :
public interface CriteriaSpec
{
public void joinFetch(CriteriaBuilder builder, CriteriaQuery criteria, Root root);
}
public <T> List<T> loadAllData(Class<T> type, Optional<CriteriaSpec> spec)
{
Session session = sessionFactory.openSession();
session.beginTransaction();
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<T> criteria = builder.createQuery(type);
Root root = criteria.from(type);
if(spec.isPresent())
spec.joinFetch(builder, criteria, root);
List<T> data = session.createQuery(criteria).getResultList();
session.getTransaction().commit();
session.close();
return data;
}
then use it :
managerHibernate.loadAllData(Application.class, Optional.empty());
listOfUsers = managerHibernate.loadAllData(User.class, (rootEntity, query,
criteriaBuilder) -> {
rootEntity.fetch("listOfApplications", JoinType.Left_OUTER_JOIN);
});

Rest API returns an empty list when connecting to database using JDBC ignoring the data brought from the database

Im doing a project on my own and the point of the project is to make an a rest API in java and bring data from database using JDBC. The problem is when i make the connection and retrieve the data using main method everything works fine but when i try to retrieve the data through a get request, it returns an empty list. This is the endpoint
#Path("/users")
public class UserResource {
UserService userService = new UserService();
#GET
#Path("/all")
#Produces(MediaType.APPLICATION_JSON)
public Response getAllUsers() throws InterruptedException {
List<User> users = userService.getAllUsers();
GenericEntity<List<User>> wrapper = new GenericEntity<List<User>>(users) {
};
return Response.ok(wrapper).build();
}
}
And this is the class that connects to database using JDBC
public class ConnectionJDBC {
private static String USERNAME = "root";
private static String PASSWORD = "root";
private static String CONSTRING = "jdbc:mysql://localhost:3306/";
private static String DATABASE = "users_db";
static Connection connection;
public ConnectionJDBC() {
}
public static Connection getConnectionToDB() {
try {
String url = CONSTRING + DATABASE;
connection = DriverManager.getConnection(url, USERNAME, PASSWORD);
if (connection != null) {
System.out.println("Connected");
} else {
System.out.println("Connection faild");
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("Something went wrong before establishing the connection");
}
return connection;
}
public List<User> getUsers() {
connection = getConnectionToDB();
String query = "SELECT * FROM users_db.user_info;";
List<User> userListRetrived = new ArrayList<>();
try {
PreparedStatement statement = connection.prepareStatement(query);
ResultSet dataRetrieved = statement.executeQuery();
while (dataRetrieved.next()) {
User user = new User(dataRetrieved.getInt("id"),
dataRetrieved.getString(2),
dataRetrieved.getString(3));
userListRetrived.add(user);
return userListRetrived;
}
} catch (Exception e) {
e.printStackTrace();
System.err.println("Something went wrong when retriving the data");
}
return userListRetrived;
}
}
UserService class is here
public class UserService {
private ConnectionJDBC connectionJDBC = new ConnectionJDBC();
public UserService() {
}
public List<User> getAllUsers() {
ConnectionJDBC connectionJDBC = new ConnectionJDBC();
List<User> usersList = connectionJDBC.getUsers();
return usersList;
}
}
The user class is a normal java bean. It feels like getUsers method is ignoring bringing the data from the database and instead it returns the instantiated empty list instead. I'm using jersey and deploying the project on Glassfish.
Any clues on how i can fix that or explanation for this situation?
Many thanks in advance!
You didn't invoke userService.getUsers() method from userResource() class. Please update your code in userResource() class as follows
GenericEntity<List<User>> wrapper = new GenericEntity<List<User>>(userService.getUsers());

Want to delete database value and document from folder in a single hibernate transaction

I want to know is transaction applicable to document deletion with database query execution?I am new in hibernate query transaction.I want to delete a document details from the database table and at the same time particular document must be delete from the document.If there is no deletion takes place in document deletion, then does not occur the database value deletion wise versa.I think this can be done using transaction.Is this applicable?Or Is there any solution to my problem?I try with transaction code.But it shows Transaction not successfully started Exception.
Thank you
In my DAOHibernateImplimentation class
getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(final Session session)throws HibernateException, java.sql.SQLException {
Transaction tx = null;
int deleteStatus=0;
try {
tx = session.beginTransaction();
final String deleteQuery = "delete from tablename where name='"+name+"'";
deleteStatus = (Integer)getHibernateTemplate().execute(new HibernateCallback(){
public Object doInHibernate(final Session session) throws HibernateException, java.sql.SQLException
{
Query query = session.createSQLQuery(deleteQuery);
return query.executeUpdate();
}
});
if(deleteStatus>0){
file.delete();
}
tx.commit();
} catch (Exception e) {
tx.rollback();
e.printStackTrace();
}
return deleteStatus;
}
});
Exception is:
17:09:30,447 ERROR [STDERR] org.springframework.transaction.TransactionSystemException: Could not commit Hibernate transaction; nested exception is org.hibernate.TransactionException: Transaction not successfully started
17:09:30,447 ERROR [STDERR] at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:562)
17:09:30,447 ERROR [STDERR] at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:662)
17:09:30,447 ERROR [STDERR] at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:632)
Try with TransactionTemplate
TransactionTemplate transactionTemplate=new TransactionTemplate();
transactionTemplate.execute(new TransactionCallback() {
#Override
public Object doInTransaction(TransactionStatus status) {
int deleteStatus = 0;
try {
final String deleteQuery = "delete from tablename where name='" + name + "'";
deleteStatus = (Integer) getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(final Session session) throws HibernateException, java.sql.SQLException {
Query query = session.createSQLQuery(deleteQuery);
return query.executeUpdate();
}
});
if (deleteStatus > 0) {
file.delete();
}
} catch (Exception e) {
e.printStackTrace();
}
return deleteStatus;
}
});
It seems like the getHibernateTemplate().execute ... is not executed in the Transaction. Like described here Hibernate transaction not successfully started there might be nothing to commit. I suggest you to remove the HibernateCallback and just directly execute the query.
Edit. Like this!
getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(final Session session)throws HibernateException, java.sql.SQLException {
Transaction tx = null;
int deleteStatus=0;
try {
tx = session.beginTransaction();
final String deleteQuery = "delete from tablename where name='"+name+"'";
Query query = session.createSQLQuery(deleteQuery);
deleteStatus = query.executeUpdate();
if(deleteStatus>0){
boolean deleted = file.delete();
if(!deleted)
throw new IOException("Error deleting");
}
tx.commit();
} catch (Exception e) {
tx.rollback();
e.printStackTrace();
}
return deleteStatus;
});
You need to check the return value of the file.delete() call. (See JavaDoc)

Why Hibernate session object's delete method is not working?

Why session object's delete method is not working in GenericDAOImpl.java, neither its giving any exception nor its showing any output. All other methods working fine expect public void delete(T object), Please help me, Sorry if i asked this question in wrong way.
public class GenericDAOImpl<T> implements IGenericDAO<T> {
private SessionFactory sessionFactory;
public GenericDAOImpl(Class<T> cl, SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
if (sessionFactory == null)
throw new RuntimeException("Session factory is null!!!");
}
#Override
public T get(Class<T> cl, Long id) {
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
#SuppressWarnings("unchecked")
T element = (T) session.get(cl, id);
session.getTransaction().commit();
return element;
}
#Override
public T get(Class<T> cl, Serializable obj) {
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
#SuppressWarnings("unchecked")
T element = (T) session.get(cl, obj);
session.getTransaction().commit();
return element;
}
#Override
public T save(T object) {
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
session.save(object);
session.getTransaction().commit();
return object;
}
#Override
public void update(T object) {
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
session.update(object);
session.getTransaction().commit();
}
#Override
public void delete(T object) {
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
session.delete(object);
session.getTransaction().commit();
}
#SuppressWarnings("unchecked")
#Override
public T findUniqueByQuery(String hsql, Map<String, Object> params) {
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
Query query = session.createQuery(hsql);
if (params != null) {
for (String i : params.keySet()) {
query.setParameter(i, params.get(i));
}
}
return (T) query.uniqueResult();
}
#SuppressWarnings("unchecked")
#Override
public List<T> query(String hsql, Map<String, Object> params) {
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
Query query = session.createQuery(hsql);
if (params != null) {
for (String i : params.keySet()) {
query.setParameter(i, params.get(i));
}
}
List<T> result = null;
if ((hsql.toUpperCase().indexOf("DELETE") == -1)
&& (hsql.toUpperCase().indexOf("UPDATE") == -1)
&& (hsql.toUpperCase().indexOf("INSERT") == -1)) {
result = query.list();
} else {
}
session.getTransaction().commit();
return result;
}
}
As investigated in comments, you are facing
org.hibernate.TransactionException: nested transactions not supported exception
This is happening because you began transaction and never committed or rollbacked upon an exception.
I can see one of it's case in your code. See your code below
#SuppressWarnings("unchecked")
#Override
public T findUniqueByQuery(String hsql, Map<String, Object> params) {
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
Query query = session.createQuery(hsql);
if (params != null) {
for (String i : params.keySet()) {
query.setParameter(i, params.get(i));
}
}
return (T) query.uniqueResult();
}
See, you began and never committed a transaction. Like wise check all other places in your project.
I have the same problem. Although I was not using transaction at all. I was using namedQuery like this :
Query query = session.getNamedQuery(EmployeeNQ.DELETE_EMPLOYEES);
int rows = query.executeUpdate();
session.close();
It was returning 2 rows but the database still had all the records. Then wrap up the above code with this :
Transaction transaction = session.beginTransaction();
Query query = session.getNamedQuery(EmployeeNQ.DELETE_EMPLOYEES);
int rows = query.executeUpdate();
transaction.commit();
session.close();
Then it started working fine. I was using SQL server. But I think if we use h2 above code (without transaction) will also work fine.
org.hibernate.TransactionException: nested transactions not supported exception
Most probably you're not closing your session after an update or insert, and then you're doing the delete.

Categories