While developing the backend for a web app, we used hibernate to handle the database. So, while testing, we had a test failing.
package com.app.db.hibernate.test;
import java.util.HashMap;
import com.app.db.hibernate.UserManager;
import com.app.db.utils.TestUtils;
import org.junit.*;
import static org.junit.Assert.*;
public class HibernateUserTest {
public final UserManager um = new UserManager();
public Integer id;
public HashMap<String, Object> userParams;
#Before
public void setup(){
this.userParams = TestUtils.loadParams();
this.id = this.um.agregar(this.userParams);
}
#Test
public void deleteUserTest(){
//Se elimina el usuario de la db:
um.deleteUser(userParams);
//Se comprueba que no esta:
Integer id_ = um.search(userParams);
assertNull(id_);
}
#After
public void cleanUp(){
um.reset();
}
}
So here we add a user to the database, call the deleteUser() method, and check if it works (search(userParams) should return null). The thing is that the test fails since, even though um.deleteUser(userParams) deletes the dummy user from the database, um.search(userParams) still "finds" it (by returning the id of the user just deleted, I checked that by debugging the code), I do not know from where, thus failing. Here's the code for delete() and search():
public void deleteUser(HashMap<String, Object> params){
Session sesion = sessionFactory.openSession();
try{
sesion.beginTransaction();
User u = (User)sesion.get(User.class, search(params));
sesion.delete(u);
sesion.getTransaction().commit();
}catch(HibernateException he){
he.printStackTrace();
}finally{sesion.close();}
}
public Integer search(HashMap<String, Object> params) {
Session sesion = sessionFactory.openSession();
Integer id = null;
try{
List lista = sesion.createCriteria(User.class).add(
Restrictions.eq("name",(String)params.get("name"))).list();
if(lista.size() == 1){id = ((User)lista.get(0)).getId();}
}catch(HibernateException he){
he.printStackTrace();
}finally{sesion.close();}
return id;
}
reset() just cleans the users table:
public void reset() {
Session session = sessionFactory.openSession();
session.beginTransaction();
Query q = session.createQuery("delete from User");
q.executeUpdate();
session.getTransaction().commit();
}
So, my question is: Is there something i'm missing here to make the test pass? Thanks in advance.
well, the trick was to add some lines, to get the transaction from the session, and commiting, to go from this:
public Integer search(HashMap<String, Object> params) {
Session sesion = sessionFactory.openSession();
Integer id = null;
try{
List lista = sesion.createCriteria(User.class).add(
Restrictions.eq("name",(String)params.get("name"))).list();
if(lista.size() == 1){id = ((User)lista.get(0)).getId();}
}catch(HibernateException he){
he.printStackTrace();
}finally{sesion.close();}
return id;
}
to this:
public Integer search(HashMap<String, Object> params) {
Session sesion = sessionFactory.openSession();
Integer id = null;
//get the transaction object:
Transaction tx = sesion.beginTransaction();
try{
//a new restriction added to the search:
Criteria criteria = sesion.createCriteria(User.class);
criteria.add(Restrictions.eq("name", (String)params.get("name")));
criteria.add(Restrictions.eq("email", (String)params.get("email")));
List lista = criteria.list();
//commit:
tx.commit();
//only one should be found, this is yet to be implemented:
if(lista.size() == 1){id = ((User)lista.get(0)).getId();}
}catch(HibernateException he){
//in case of an exception thrown while committing, roll back transaction:
tx.rollback();
he.printStackTrace();
}finally{sesion.close();}
return id;
}
That made the test pass :)
Related
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();
}
I am using Hibernate and I have Many methods of this type:
public static void modifySchemeEvents(String schmCode, String username) {
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
Criteria cr = session.createCriteria(SchmEventsTable.class);
cr.add(Restrictions.eq("schmCode", schmCode));
SchmEventsTable evt = (SchmEventsTable) cr.uniqueResult();
evt.setLchgUserId(username);
tx.commit();
} catch (HibernateException asd) {
log.debug(asd.getMessage());
if (tx != null) {
tx.rollback();
}
} finally {
session.close();
}
}
This updated the database with the username where schmCode is <schmCode> I am attempting to convert to generic so that I do not have to write a separate method for all updates so I have come up with this generic method:
public static <T> T getUpdateObject(Class c, Map<String, ?> params) {
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx = null;
T value = null;
try {
tx = session.beginTransaction();
Criteria cr = session.createCriteria(c);
for (Map.Entry<String, ?> entry : params.entrySet()) {
cr.add(Restrictions.eq(entry.getKey(), entry.getValue()));
}
value = (T) cr.uniqueResult();
////How to set the values here?***
tx.commit();
} catch (HibernateException asd) {
log.debug(asd.getMessage());
if (tx != null) {
tx.commit();
}
} finally {
session.close();
}
return value;
}
I am attempting to use it this way:
Map<String, String> schemeEventMap = new HashMap();
schemeEventMap.put("schmCode", "CA201");
SchmEventsTable evt = DataOperation.getUpdateObject(SchmEventsTable.class, schemeEventMap);
evt.setLchgUserId(username);
This does not update the table like the first method. I am wondering how to pass the parameters in the generic Method Dynamically.
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);
});
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.
i have to update some rows in database using Hibernate and Struts2:
the method DAO where i put the requete is:
public void modifier(String cond) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
try{Query query = session.createQuery("Update Processus set selectionne = '1' where"+cond );
// query.setString("idproc",idprocessus);
// query.setLong("idsi", identifiantsi);
}catch(HibernateException e) {
e.printStackTrace();
session.getTransaction().rollback();
}
session.getTransaction().commit();
}
In my action class where i call the DAO, i specify the cond:
public String update(){
cond="id_processus="+checked;
procdao.modifier(cond);
return SUCCESS;
}
can u help me it doens't show any error in the console but the row's value don't change!!!!
Following code could be helpful: Processus Table name selectionne and idproc are column name
You need to execute the query
To check the number of updated rows.
public Boolean modifier(String cond) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
Boolean returnValue = false;
try {
Query query = session.createQuery("Update Processus set selectionne = '1' where idproc=:cond");
query.setString("cond", cond);
int noOfUpdate = query.executeUpdate();
returnValue = (noOfUpdate > 0);
} catch (HibernateException e) {
e.printStackTrace();
session.getTransaction().rollback();
}
session.getTransaction().commit();
return returnValue;
}