I'm trying to implement his Java code with Hibernate in order to make SQL queries:
public List<AttendeeModel> getListOfCds(int firstRow, int rowCount) {
List<AttendeeModel> cdList = null;
try {
session.beginTransaction();
Criteria criteria = session.createCriteria(AttendeeModel.class);
criteria.setFirstResult(firstRow);
criteria.setMaxResults(rowCount);
if (criteria != null) {
cdList = (List<AttendeeModel>) criteria.list();
}
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}
return cdList;
}
public int countRows() {
try {
session.beginTransaction();
Criteria criteria = session.createCriteria(AttendeeModel.class);
if (criteria != null) {
return criteria.list().size();
}
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}
return 0;
}
But for some reason I get this error:
java.lang.IllegalStateException: Session/EntityManager is closed
Do you know how I can fix this issue?
From your code it is unclear where session is decleared and how it is populated. Given that this is done somehow correctly, I suspect that missing transaction commit/rollback before return in countRow leads to the exception, try:
public int countRows() {
int size = 0;
try {
session.beginTransaction();
Criteria criteria = session.createCriteria(AttendeeModel.class);
if (criteria != null) {
size = criteria.list().size();
}
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}
return size;
}
Related
I want to insert a list of Urls in a database under the condition that it doesn't exist in or an other table.
My current attempt is very slow every request can take 100ms - 500ms.
for(URL url : urls) {
if (this.urlToEditService.findByUrl(newUrl).size() == 0 &&
this.rawPageService.findByUrl(newUrl).size() == 0) {
UrlToEdit urlToEdit = new UrlToEdit(newUrl);
urlToEditService.save(urlToEdit);
}
}
This is my save method.
public boolean save(UrlToEdit urlToEdit) {
Transaction transaction = null;
try (Session session = factory.openSession()) {
transaction = session.beginTransaction();
session.save(urlToEdit);
transaction.commit();
} catch (Exception e) {
if (transaction != null) {
transaction.rollback();
}
e.printStackTrace();
return false;
}
return true;
}
Is there a way to insert all with one transaction? I could Imagine that the open and close part is the boodleneck.
EDIT1: I changed the code a bit so I would save in one transaction based on this answer:
List<URLToEdit> list = new ArrayList();
for(URL url : urls) {
if (this.urlToEditService.findByUrl(newUrl).size() == 0 &&
this.rawPageService.findByUrl(newUrl).size() == 0) {
list.add( new UrlToEdit(newUrl));
}
}
public boolean save(List<URLToEdit> urlToEditList) {
Transaction transaction = null;
int counter = 0;
try (Session session = factory.openSession()) {
transaction = session.beginTransaction();
for (UrlToEdit urlToEdit : urlToEditList) {
session.save(urlToEdit);
counter++;
if(counter > 20) {
counter = 0;
session.flush();
session.clear();
}
}
transaction.commit();
} catch (Exception e) {
if (transaction != null) {
transaction.rollback();
}
e.printStackTrace();
return false;
}
return true;
}
But the speed doesn't increase. So the slow part is still the exists check.
With this session handler:
public class SessionHandler {
private static SessionFactory DBContext;
static {
try {
DBContext = HibnerateConfiguration.config().buildSessionFactory();
}
catch(Throwable t) {
throw new ExceptionInInitializerError(t);
}
}
/*
* Returns a session anyway. If currently no session exist, open a new one;
* If there is a current session, use the existing one.
*/
#Override
public Session getSession() {
try {
return DBContext.getCurrentSession();
}
catch (HibernateException he) {
logger.error("session already exist.");
return DBContext.getCurrentSession();
}
}
public void close() {
DBContext.close();
}
}
and the following create and get methods:
public Serializable create(T type_entity) {
Session session = getSessionHandler().getSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
Serializable result = session.save(type_entity);
tx.commit();
return result;
} catch (HibernateException ex) {
ex.printStackTrace();
if (tx!=null) tx.rollback();
throw ex;
} finally {
getSessionHandler().close();
}
}
#SuppressWarnings("unchecked")
public T get(Serializable id) throws InvalidRequestException {
Session session = getSessionHandler().getSession();
Transaction tx = session.beginTransaction();
tx.commit();
try {
Object obj = session.get(_classtype, id);
if (obj == null) {
throw new InvalidRequestException(String.format("requested object with id %s does not exist.", id));
} else {
return (T)obj;
}
} catch(HibernateException ex) {
ex.printStackTrace();
if (tx!=null) tx.rollback();
throw ex;
} finally {
getSessionHandler().close();
}
}
When I create an object that returns me id = 4, and if immediately I make a request on browser that eventually ask for the new object of id 4, I have to wait for a few seconds (last time I tried is > 3 seconds).
When the id is returned from the create, the data should already exist. However the get returns null. I highly suspect the get is using the old cache which then is updated every a few seconds, but I have no idea how to fix it.
Let me know if any info is required and I am happy to provide them.
im trying to test this method to remove an entity from the h2 database:
public boolean delete(T entity) {
if (entity == null) {
throw new IllegalArgumentException();
}
boolean ret = true;
EntityManager em = entityManager();
try {
EntityTransaction tx = em.getTransaction();
tx.begin();
em.remove(em.merge(entity));
tx.commit();
} catch (RollbackException ex) {
ret = false;
} finally {
em.close();
}
return ret;
}
that method is returning true if the entity is in the database and removes it, but it also returns true if the entity given is not in database. Can someone explain me why? thx.
merge will persist an entity if it doesn't already exist. Thus, you are creating an entity (with merge) and then deleting it right away (with remove). Thus no exception is thrown.
If you want to remove an entity and return a boolean whether you removed it or not then you could do...
public boolean delete(T entity) {
if (entity == null) {
throw new IllegalArgumentException();
}
EntityManager em = entityManager();
EntityTransaction tx = em.getTransaction();
try {
tx.begin();
em.refresh(entity);
em.remove(entity);
tx.commit();
return true;
} catch (EntityNotFoundException ex) {
tx.rollback();
return false;
} catch (RuntimeException ex) {
tx.rollback();
throw ex;
} finally {
em.close();
}
}
I develop a java web app using Hibernate. Here are some code :
hibernate.cfg.xml
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=UTF-8&connectionCollation=utf8mb4_general_ci</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">123456</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<!--<property name="hibernate.connection.autocommit">true</property>-->
<property name="hibernate.current_session_context_class">thread</property>
BaseDAO.class
public class BaseDAO {
public Session getSession() {
return HibernateUtil.getSessionFactory().openSession();
}
}
I write a generic class for insert, update, delete, find
public class GenericDAO<T, K extends Serializable> extends BaseDAO implements IGenericDAO<T, K> {
private Class<T> type;
protected Class<T> getType() {
return this.type;
}
protected String getClassName() {
return type.getName();
}
#SuppressWarnings("unchecked")
public GenericDAO() {
Type t = getClass().getGenericSuperclass();
ParameterizedType pt = (ParameterizedType) t;
type = (Class<T>) pt.getActualTypeArguments()[0];
}
#Override
public K save(T t) {
Session session = getSession();
Transaction tran = session.beginTransaction();
try {
K k = (K) session.save(t);
tran.commit();
return k;
} catch (Exception e) {
if (tran.isActive()) {
tran.rollback();
}
System.out.println("Sql Error : " + e.getMessage());
}
return null;
}
#Override
public void saveOrUpdate(T t) {
Session session = getSession();
Transaction tran = session.beginTransaction();
try {
session.saveOrUpdate(t);
tran.commit();
} catch (Exception e) {
if (tran.isActive()) {
tran.rollback();
}
System.out.println("Sql Error : " + e.getMessage());
}
}
#Override
public void update(T t) {
Session session = getSession();
Transaction tran = session.beginTransaction();
try {
session.update(t);
tran.commit();
} catch (Exception e) {
if (tran.isActive()) {
tran.rollback();
}
System.out.println("Sql Error : " + e.getMessage());
}
}
#Override
public void delete(T t) {
Session session = getSession();
Transaction tran = session.beginTransaction();
try {
session.delete(t);
tran.commit();
} catch (Exception e) {
if (tran.isActive()) {
tran.rollback();
}
System.out.println("Sql Error : " + e.getMessage());
}
}
#Override
public void delete(K k) {
Session session = getSession();
Transaction tran = session.beginTransaction();
try {
T t = (T) session.get(type, k);
session.delete(t);
tran.commit();
} catch (Exception e) {
if (tran.isActive()) {
tran.rollback();
}
System.out.println("Sql Error : " + e.getMessage());
}
}
#SuppressWarnings("unchecked")
#Override
public T find(K id) {
Session session = getSession();
Transaction tran = session.beginTransaction();
try {
T t = (T) session.get(type, id);
tran.commit();
return t;
} catch (Exception e) {
if (tran.isActive()) {
tran.rollback();
}
System.out.println("Sql Error : " + e.getMessage());
}
return null;
}
#SuppressWarnings("unchecked")
#Override
public List<T> findAll() {
Session session = getSession();
Transaction tran = session.beginTransaction();
try {
Query query = session.createQuery("from " + type.getSimpleName());
List<T> list = query.list();
tran.commit();
return list;
} catch (Exception e) {
if (tran.isActive()) {
tran.rollback();
}
System.out.println("Sql Error : " + e.getMessage());
}
return new ArrayList<>();
}
#SuppressWarnings("unchecked")
#Override
public List<T> findAllWithOrder(String column, String orderType) {
Session session = getSession();
Transaction tran = session.beginTransaction();
try {
if (orderType == null && orderType.equals("")) {
orderType = "ASC";
}
Query query = session.createQuery(
String.format("from %s order by %s %s", type.getSimpleName(),
column, orderType));
tran.commit();
return query.list();
} catch (Exception e) {
if (tran.isActive()) {
tran.rollback();
}
System.out.println("Sql Error : " + e.getMessage());
}
return new ArrayList<>();
}
}
You can see, I don't close session after each method. This code work fine for insert, update and find . But when I want to delete a object :
TblUser user = (TblUser)find(id);
delete(user);
It's throw exception because I use two session for this function.
Then try to close session in each method :
finally{
session.close();
}
Now I can delete object but I can't use lazy load because session has closed for each transaction.
So, how I can manage session to overcome these situation !!!
Since you have activated the property:
<property name="hibernate.current_session_context_class">thread</property>
why don't you use:
public Session getSession() {
return HibernateUtil.getSessionFactory().getCurrentSession();
}
Instead of opening a new session? By doing this, you don't need to worry about closing your session since Hibernate will close it when you close your sessionFactory.
But be aware that this is not thread safe so if you are working in a multi-thread environment, this is not a good option.
I have one method :
// methods
private void transform(TransformList transformList) {
TableA tA = transformList.getTableA();
TableB tB = transformList.getTableB();
TableC tC = transformList.getTableC();
daoObj.saveA(tA);
daoObj.saveB(tB);
daoObj.saveC(tC);
}
Now,
//saveA mehtod
public void saveA(TableA tA) {
Session session = Context.getHibernateSession();
try {
if(session != null) {
Transaction tx = session.beginTransaction();
tx.begin();
session.merge(tA);
tx.commit();
}
}catch (Exception e) {
tx.rollback();
throw new SomeException(e.getMessage());
}
finally{
if (session != null) {
session.clear();
}
}
}
Similarly,
//saveB mehtod
public void saveB(TableB tB) {
Session session = Context.getHibernateSession();
try {
if(session != null) {
Transaction tx = session.beginTransaction();
tx.begin();
session.merge(tB);
tx.commit();
}
}catch (Exception e) {
tx.rollback();
throw new SomeException(e.getMessage());
}
finally{
if (session != null) {
session.clear();
}
}
}
And,
//saveC mehtod
public void saveC(TableC tC) {
Session session = Context.getHibernateSession();
try {
if(session != null) {
Transaction tx = session.beginTransaction();
tx.begin();
session.merge(tC);
tx.commit();
}
}catch (Exception e) {
tx.rollback();
throw new SomeException(e.getMessage());
}
finally{
if (session != null) {
session.clear();
}
}
}
Now while calling 'transform' method, if saveA and saveB method are success and then some
exception occurs in saveC method, is it possible to rollback TableA and TableB records
(which are committed already) along with TableC records?
No. You'll have move your transaction handling at least one level higher: create a transaction, and call saveA(), saveB() and saveC() inside that transaction. Don't handle transactions inside the save methods.
Of course, this is only one possibility. There are frameworks, like Spring, that greatly help you manage your transactions.