I have a problem using Hibernate. Each time I call a method that performs a query or update on the database, hibernate opens a session in the database and then does not close. I've tried everything, but actually every time it's called em.getTransaction.begin (); It creates a session in Oracle bd and does not close anymore.
Below is the details of my code (persistence.xml, GenericDAO, etc.)
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="FilaTrello" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>integration.wcc.model.Chamado</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:#//10.ip.aqui/xxxint.xxx.com.br"/>
<property name="javax.persistence.jdbc.user" value="x_SUPORTE"/>
<property name="javax.persistence.jdbc.password" value="x_SUPORTE"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle9iDialect"/>
<property name="hibernate.connection.shutdown" value="true"/>
<!-- <property name="hibernate.hbm2ddl.auto" value="none"/> -->
<property name="hibernate.synonyms" value="true"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="false"/>
</properties>
</persistence-unit>
</persistence>
GenericDAO:
package integration.wcc.dao;
import javax.persistence.*;
import javax.persistence.criteria.CriteriaQuery;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
abstract class GenericDAO<T> implements Serializable {
private static final long serialVersionUID = 1L;
private static final EntityManagerFactory emf = Persistence.createEntityManagerFactory("FilaTrello");
private EntityManager em = emf.createEntityManager();;
private Class<T> entityClass;
public void beginTransaction() {
em.clear();
em.getTransaction().begin();
}
public void commit() {
em.getTransaction().commit();
}
public void rollback() {
em.getTransaction().rollback();
}
public void closeTransaction() {
em.close();
}
public void commitAndCloseTransaction() {
commit();
closeTransaction();
}
public void flush() {
em.flush();
}
public void joinTransaction() {
em = emf.createEntityManager();
em.joinTransaction();
}
public GenericDAO(Class<T> entityClass) {
this.entityClass = entityClass;
}
public void save(T entity) {
em.persist(entity);
}
public void delete(Object id, Class<T> classe) {
T entityToBeRemoved = em.getReference(classe, id);
em.remove(entityToBeRemoved);
}
public T update(T entity) {
return em.merge(entity);
}
public T find(int entityID) {
return em.find(entityClass, entityID);
}
public T findL(Long entityID) {
return em.find(entityClass, entityID);
}
public T findReferenceOnly(int entityID) {
return em.getReference(entityClass, entityID);
}
// Using the unchecked because JPA does not have a
// em.getCriteriaBuilder().createQuery()<T> method
#SuppressWarnings({"unchecked", "rawtypes"})
public List<T> findAll() {
CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
cq.select(cq.from(entityClass));
return em.createQuery(cq).getResultList();
}
// Using the unchecked because JPA does not have a
// query.getSingleResult()<T> method
#SuppressWarnings("unchecked")
protected T findOneResult(String namedQuery, Map<String, Object> parameters) {
T result = null;
try {
Query query = em.createNamedQuery(namedQuery);
// Method that will populate parameters if they are passed not null and empty
if (parameters != null && !parameters.isEmpty()) {
populateQueryParameters(query, parameters);
}
result = (T) query.getSingleResult();
} catch (NoResultException e) {
System.out.println("No result found for named query: " + namedQuery);
} catch (Exception e) {
System.out.println("Error while running query: " + e.getMessage());
e.printStackTrace();
}
return result;
}
#SuppressWarnings("unchecked")
protected List<T> findListResult(String namedQuery, Map<String, Object> parameters) {
List<T> result = null;
try {
Query query = em.createNamedQuery(namedQuery);
// Method that will populate parameters if they are passed not null and empty
if (parameters != null && !parameters.isEmpty()) {
populateQueryParameters(query, parameters);
}
//result = (T) query.getSingleResult();
result = (List<T>) query.getResultList();
} catch (NoResultException e) {
System.out.println("No result found for named query: " + namedQuery);
} catch (Exception e) {
System.out.println("Error while running query: " + e.getMessage());
e.printStackTrace();
}
return result;
}
private void populateQueryParameters(Query query, Map<String, Object> parameters) {
for (Map.Entry<String, Object> entry : parameters.entrySet()) {
query.setParameter(entry.getKey(), entry.getValue());
}
}
}
Access DAO class:
public class FilaChamadoDAO extends GenericDAO<FilaChamado> {
private static final long serialVersionUID = 1L;
public FilaChamadoDAO() {
super(FilaChamado.class);
}
public List<FilaChamado> findTicketsByFila(int idFila,String listType) {
Map<String, Object> parameters = new HashMap<String, Object>();
parameters.put("filaNumber", idFila);
parameters.put("listParam", listType);
return super.findListResult(FilaChamado.FIND_TICKETS_FILA_BY_FILA, parameters);
}
Ai eu tenho uma classe facade para cada Model meu, que faz a interface de acesso ao DAO:
I have a Facade class for each Model class, which makes the DAO access interface:
public class FilaChamadoFacade {
private FilaChamadoDAO FilaChamadoDAO = new FilaChamadoDAO();
public List<FilaChamado> listAll() {
FilaChamadoDAO.beginTransaction();
List<FilaChamado> result = FilaChamadoDAO.findAll();
FilaChamadoDAO.closeTransaction();
return result;
}
public List<FilaChamado> findTicketsByFila(int idFila,String listaDestino) {
List<FilaChamado> result = null;
try {
FilaChamadoDAO.beginTransaction();
result = FilaChamadoDAO.findTicketsByFila(idFila, listaDestino);
FilaChamadoDAO.flush();
} catch (HibernateException e) {
if (FilaChamadoDAO != null) {
FilaChamadoDAO.rollback();
}
e.printStackTrace();
} finally {
FilaChamadoDAO.closeTransaction();
}
return result;
}
When I call ListAll() function or any namedWaury, I can't anyway close these opened connections.
I've made a simple test in a Main class:
public class TestNamedQuery {
public static void main(String[] args) {
TrelloUser trelloU = new TrelloUser();
TrelloUserFacade facade2 = new TrelloUserFacade();
List<TrelloUser> trelloUsers1 = new ArrayList<TrelloUser>();
trelloUsers1 = facade2.listAll();
for (TrelloUser trelloUser : trelloUsers1) {
if(trelloUser.getUserToken() != null) {
System.out.println("Selectss do usuario: "+trelloUser.getUserName());
ChamadoCard cards = new ChamadoCard();
cards.InsereChamado(trelloUser);
}
}
}
}
As you can see, in my facade class every time I start a transaction ,I close it, but this does not happen in Oracle, where a session is created for each beginTransaction of my EntityManager.
After a lot of attempts, I just found a post saying that I have to commitor rollback every time I call beginTransaction()method to my Entity Manager.
So I change my code like this in theGenericDA.javaclass:
public void closeTransaction() {
em.getTransaction().commit();
em.close();
}
I still trying to understand why Hibernate forces me to COMMIT a transaction even in a query statement, and I think that i can earn a great performance without do it.
But that change work like a charm for me.
Related
I'm trying to write a Java JSF 2.3 app, with Primefaces and Hibernate as JPA provider.
I'm having trouble updating an entity that has a SortedSet of another entity.
I made the minimal reproducible example.
So let's call them EntityTest like a parent entity and EntityTestChild like a child, as following:
#Entity
public class EntityTest implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String testString;
#OneToMany(fetch = FetchType.LAZY, orphanRemoval = true)
#OrderBy("id ASC")
private SortedSet<EntityTestChild> childs = new TreeSet<>();
//getters and setters for id, testString and childs. omitted for brevity.
//equals based on id, hashcode and toString omitted for brevity.
The other entity:
#Entity
public class EntityTestChild implements Serializable, Comparable<EntityTestChild> {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String stringChild;
public EntityTestChild()
{
stringChild = "Hi, I'm a child";
}
//getters and setters, comparator, equals, hashcode and toString.
With a JSF page, I want to create and persist instances of parent entity EntityTest. And for each of them, I want to manage their child entities EntityTestChild
So for that I made a quick JSF page:
JSF Page code:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>Test</title>
</h:head>
<h:body>
This is a test
<h:form id="testForm">
<p:inputText value="#{viewTestBean.testStr}"/>
<br/>
<p:messages id="msgs"/>
<br/>
<p:commandButton actionListener="#{viewTestBean.addToTable()}"
value="add to table"
update="#form"
icon="pi pi-plus"/>
<br/>
<p:commandButton actionListener="#{viewTestBean.setSelectedEntity(null)}"
icon="pi pi-times"
update="#form"/>
<p:dataTable id="testTable"
value="#{viewTestBean.table}"
var="ent2">
<p:column headerText="string">
<h:outputText value="#{ent2.testString}"/>
</p:column>
<p:column headerText="Action">
<p:commandButton icon="pi pi-check"
update="#form"
style="margin-right:10px"
actionListener="#{viewTestBean.setSelectedEntity(ent2)}"/>
<p:commandButton icon="pi pi-trash"
actionListener="#{viewTestBean.removeTableEnt(ent2)}"
update="#form"/>
</p:column>
</p:dataTable>
<h:panelGroup rendered="#{viewTestBean.selectedEntity != null}">
<p:inputText value="#{viewTestBean.testStr2}"/>
<p:commandButton actionListener="#{viewTestBean.addChild()}"
update="#form"
value="add child"
icon="pi pi-check"/>
<p:dataTable id="tableChilds"
rendered="#{viewTestBean.selectedEntity != null}"
value="#{viewTestBean.selectedEntity.childs}"
var="child">
<p:column headerText="child">
<h:outputText value="#{child.stringChild}"/>
</p:column>
<p:column headerText="action">
<p:commandButton update="#form"
actionListener="#{viewTestBean.removeChild(child)}"
icon="pi pi-trash"/>
</p:column>
</p:dataTable>
</h:panelGroup>
</h:form>
</h:body>
</html>
It has a ViewScoped CDI bean as a backing bean:
#Named(value = "viewTestBean")
#ViewScoped
public class ViewTestBean implements Serializable {
#Inject
DataAppBean dataAppBean;
private List<EntityTest> table;
private String testStr;
private String testStr2;
private EntityTest selectedEntity;
public ViewTestBean() {
}
public void removeChild(EntityTestChild child)
{
selectedEntity.getChilds().remove(child);
try {
dataAppBean.getEntityTestJpaController().edit(selectedEntity);
} catch (Exception ex) {}
try {
dataAppBean.getEntityTestChildController().destroy(child.getId());
} catch (Exception ex) {}
}
public void addChild()
{
EntityTestChild newChild = new EntityTestChild();
newChild.setStringChild(testStr2);
try {
dataAppBean.getEntityTestChildController().create(newChild);
} catch (Exception ex) { }
selectedEntity.getChilds().add(newChild);
try {
dataAppBean.getEntityTestJpaController().edit(selectedEntity);
} catch (Exception ex) { }
}
public EntityTest getSelectedEntity() {
return selectedEntity;
}
public void setSelectedEntity(EntityTest selectedEntity) {
this.selectedEntity = selectedEntity;
}
public void addToTable()
{
EntityTest newEntity = new EntityTest();
newEntity.setTestString(testStr);
try{dataAppBean.getEntityTestJpaController().create(newEntity);}
catch (Exception ex) { return; }
getTable().add(newEntity);
}
public void removeTableEnt(EntityTest ent)
{
if (selectedEntity == ent) selectedEntity = null;
try {
dataAppBean.getEntityTestJpaController().destroy(ent.getId());
} catch (Exception ex) { }
getTable().remove(ent);
}
public List<EntityTest> getTable()
{
if (table == null)
table = dataAppBean.getEntityTestJpaController().findEntityTestEntities();
return table;
}
public String getTestStr() { return testStr; }
public void setTestStr(String testStr) { this.testStr = testStr; }
public String getTestStr2() { return testStr2; }
public void setTestStr2(String testStr2) { this.testStr2 = testStr2; }
}
With a click in the Check button, we should see below the table for child entities.
DataAppBean is an ApplicationScoped CDI bean. That is the data service, and holds the persistence helper classes.
#Named(value = "dataAppBean")
#ApplicationScoped
public class DataAppBean {
private EntityTestJpaController entityTestController;
private EntityTestChildJpaController entityTestChildController;
private EntityManagerFactory emf;
private UserTransaction utx;
public EntityTestJpaController getEntityTestJpaController()
{
if (this.entityTestController == null)
this.entityTestController = new EntityTestJpaController(getUserTransaction(), getEntityManagerFactory());
return this.entityTestController;
}
public EntityTestChildJpaController getEntityTestChildController()
{
if (this.entityTestChildController == null)
this.entityTestChildController = new EntityTestChildJpaController(getUserTransaction(), getEntityManagerFactory());
return this.entityTestChildController;
}
public EntityManagerFactory getEntityManagerFactory()
{
if (this.emf == null)
this.emf = Persistence.createEntityManagerFactory("ar.org.ptpchaco_SICasosTierras_war_1.0PU");
return this.emf;
}
public UserTransaction getNewUserTransaction()
{
UserTransaction output = null;
try {output = (UserTransaction) new InitialContext().lookup("java:comp/UserTransaction");}
catch (NamingException ex) { }
return output;
}
public UserTransaction getUserTransaction()
{
if (this.utx == null)
this.utx = getNewUserTransaction();
return this.utx;
}
The JPA Controllers are auto generated with NetBeans 13 IDE. And looks like following:
public class EntityTestJpaController implements Serializable {
public EntityTestJpaController(UserTransaction utx, EntityManagerFactory emf) {
this.utx = utx;
this.emf = emf;
}
private UserTransaction utx = null;
private EntityManagerFactory emf = null;
public EntityManager getEntityManager() {
return emf.createEntityManager();
}
public void create(EntityTest entityTest) throws RollbackFailureException, Exception {
EntityManager em = null;
try {
utx.begin();
em = getEntityManager();
em.persist(entityTest);
utx.commit();
} catch (Exception ex) {
try {
utx.rollback();
} catch (Exception re) {
throw new RollbackFailureException("An error occurred attempting to roll back the transaction.", re);
}
throw ex;
} finally {
if (em != null) {
em.close();
}
}
}
public void edit(EntityTest entityTest) throws NonexistentEntityException, RollbackFailureException, Exception {
EntityManager em = null;
try {
utx.begin();
em = getEntityManager();
entityTest = em.merge(entityTest);
utx.commit();
} catch (Exception ex) {
try {
utx.rollback();
} catch (Exception re) {
throw new RollbackFailureException("An error occurred attempting to roll back the transaction.", re);
}
String msg = ex.getLocalizedMessage();
if (msg == null || msg.length() == 0) {
Long id = entityTest.getId();
if (findEntityTest(id) == null) {
throw new NonexistentEntityException("The entityTest with id " + id + " no longer exists.");
}
}
throw ex;
} finally {
if (em != null) {
em.close();
}
}
}
public void destroy(Long id) throws NonexistentEntityException, RollbackFailureException, Exception {
EntityManager em = null;
try {
utx.begin();
em = getEntityManager();
EntityTest entityTest;
try {
entityTest = em.getReference(EntityTest.class, id);
entityTest.getId();
} catch (EntityNotFoundException enfe) {
throw new NonexistentEntityException("The entityTest with id " + id + " no longer exists.", enfe);
}
em.remove(entityTest);
utx.commit();
} catch (Exception ex) {
try {
utx.rollback();
} catch (Exception re) {
throw new RollbackFailureException("An error occurred attempting to roll back the transaction.", re);
}
throw ex;
} finally {
if (em != null) {
em.close();
}
}
}
public List<EntityTest> findEntityTestEntities() {
return findEntityTestEntities(true, -1, -1);
}
public List<EntityTest> findEntityTestEntities(int maxResults, int firstResult) {
return findEntityTestEntities(false, maxResults, firstResult);
}
private List<EntityTest> findEntityTestEntities(boolean all, int maxResults, int firstResult) {
EntityManager em = getEntityManager();
try {
CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
cq.select(cq.from(EntityTest.class));
Query q = em.createQuery(cq);
if (!all) {
q.setMaxResults(maxResults);
q.setFirstResult(firstResult);
}
return q.getResultList();
} finally {
em.close();
}
}
This JPA controllers generated by NetBeans, wraps the persist operation with a create method, and merge operation with an edit method. It creates and find the entities but these are quickly detached because of the em.close() instruction. So every data the JSF app handles is always detached. Nothing is managed.
Below is persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="ar.org.ptpchaco_SICasosTierras_war_1.0PU" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/JNDICasosTierras</jta-data-source>
<class>ar.org.ptpchaco.siconflictostierras.storage.EntityTest</class>
<class>ar.org.ptpchaco.siconflictostierras.storage.EntityTestChild</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="hibernate.show_sql" value="false"/>
<property name="hibernate.generate_statistics" value="false"/>
<property name="hibernate.enable_lazy_load_no_trans" value="true"/>
</properties>
</persistence-unit>
</persistence>
So my logic is as following. I first create a parent entity, and persist it. The instance get an ID. the JPA controller executes the transaction and flushes into the database (MySQL). MySQL inserts the row in the table. Fine.
Then I want to add a child to the parent entity. So I create the child, persist it. It receives and id. I add it to the SortedSet of the parent entity. And then try to merge the parent entity, for updating the SortedSet of child entities. That is done with the addChild() method.
My problem is. I load the page. Select any parent entity. Add a child, fine. Add a second child. Have an exception:
16:54:14,140 WARN [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (default task-1)
SQL Error: 1062, SQLState: 23000
16:54:14,140 ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (default task-1)
Duplicate entry '8-28' for key 'PRIMARY'
16:54:14,140 INFO [org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl] (default
task-1) HHH000010: On release of batch it still contained JDBC
statements...
Both entities are inserted in the database, parent and child, but when I try to update the parent (for second time), the relationship join table entitytest_entitytestchild tries to insert a duplicate pair of keys.
As you can see I have no much clue..., and I suspect i'm making so many things so wrong.
Please I need any advice on whatever I am doing wrong.
Why does it work on the first time?, and not on the second time?
Why Hibernate tries to insert two times the same pair of keys?
What is the correct way of updating a parent entity that has a List or Set of other entities?
Is my ApplicationScoped approach of a data service correct?
The emf and utx objects should live as long as app scoped?
I'm using:
JSF 2.3
Primefaces 10
JPA 2.1 with Hibernate 5.3 as persistence provider.
MySQL 5.7 as database
Netbeanas 13 as IDE
Wildfly 26 as server.
I dont know why i cannot call getAll() class in ManagerBase class from UserDAO, but with other class it still be ok
Hibernate code here
protected Session getCurrentSession() throws Exception {
if (session == null){ //check session null
if (sessionFactory == null){ //build sessionFactory if it null
if(sessionFactoryConfigPath == null || sessionFactoryConfigPath.equals("")){
sessionFactory = new Configuration().configure().buildSessionFactory();
}else{
sessionFactory = new Configuration().configure(this.sessionFactoryConfigPath).buildSessionFactory();
}
}
session = sessionFactory.getCurrentSession();
}
return session;
}
ManagerBase code
public abstract class ManagerBase<T> extends HibernateUtil {
private Class<T> persistentClass;
public ManagerBase() throws Exception {
super();
this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments().getClass();
}
public ManagerBase(String sessionFactoryConfigPath) throws Exception {
super(sessionFactoryConfigPath);
this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments().getClass();
}
public Class<T> getPersistentClass() {
return this.persistentClass;
}
public List<T> getAll() {
List<T> list = null;
try {
beginTransaction();
list = getCurrentSession().createCriteria(this.persistentClass).list();
commitAndClose();
} catch (Exception ex) {
System.out.println("getAll Error \n" + ex);
}
return list;
}
UserDAO code here.....
code
public class UserDAO extends ManagerBase<User> {
public UserDAO() throws Exception {
}
public List<User> getAllUser() {
try {
List<User> user = getAll();
return user;
} catch (Exception ex) {
System.out.println("Get All User Error \n" + ex);
return null;
}
}
}
Any body please help me, in the console board that show only Begin and commit and it doesnt has any HQL code.
Introduction
I have a JavaEE Application which consists in a RESTFul Web Service. This WS is responsible to receive some requests and answer with XMLs. There are services to store and services to capture information of a MySQL DB.
The system was done using APIs like JAX-WS and JAX-B and the framework Hibernate for data persistence.
Problem
When I update, delete or insert anything in my DB, directly or through a service of the WS, and try to see the result through a service, the differences doesn't appears unless I restart my WS.
Possibility
I believe it's about Hibernate caching but I didn't find anything that help me to fix it.
Does anybody already had this problem? Any idea?
hibernate.cfg.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<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/context_server</property>
<property name="hibernate.connection.username">user</property>
<property name="hibernate.connection.password"></property>
<mapping class="br.marcelo.bean.CsMediaAudio"/>
<mapping class="br.marcelo.bean.CsMediaImage"/>
<mapping class="br.marcelo.bean.CsMediaVideo"/>
<mapping class="br.marcelo.bean.CsContext"/>
<mapping class="br.marcelo.bean.CsMedia"/>
<mapping class="br.marcelo.bean.CsResource"/>
<mapping class="br.marcelo.bean.CsUser"/>
</session-factory>
</hibernate-configuration>
An service to Get informations:
#GET
#Path("/getResourceByIdXML/{id}")
#Produces(MediaType.APPLICATION_XML)
public CsResource getResourceByIdXML(#PathParam("id")Long id) {
return new DAOResource().find(id);
}
Class: DAOResource with find method used above:
public class DAOResource extends DAOGenerics<CsResource, Long> {
private final Session s;
public DAOResource()
{
s = HibernateSessionFactory.getSession();
}
#Override
public CsResource find(Long id) {
try {
s.flush();
s.clear();
String sql = "from CsResource where id = :id";
Query qr = s.createQuery(sql);
qr.setParameter("id", id);
return (CsResource) qr.uniqueResult();
}catch(HibernateException e){
System.out.println(e);
return null;
} finally {
s.close();
}
}
}
HibernateSessionFactory class with getSession method used above:
public class HibernateSessionFactory {
private static SessionFactory sf;
static
{
try
{
sf = new AnnotationConfiguration().configure("hibernate.cfg.xml").buildSessionFactory();
}
catch (Exception erro)
{
System.err.println(erro);
sf = null;
}
}
public static Session getSession()
{
return sf.openSession();
}
public static Connection getConnection(){
try {
SessionFactoryImplementor sessionFactoryImplementation = (SessionFactoryImplementor) sf;
ConnectionProvider connectionProvider = (ConnectionProvider)sessionFactoryImplementation.getConnectionProvider();
java.sql.Connection connection = connectionProvider.getConnection();
return connection;
} catch (SQLException ex) {
Logger.getLogger(HibernateSessionFactory.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
}
EDIT:
DAOGenerics class with call of flush() and clear() methods
public abstract class DAOGenerics<K, G> {
private final Session s;
public DAOGenerics()
{
s = HibernateSessionFactory.getSession();
}
public abstract K buscar(G obj);
public abstract List<K> buscarTodos();
public boolean inserir(K obj){
try {
s.flush();
s.clear();
s.getTransaction().begin();
s.saveOrUpdate(obj);
s.getTransaction().commit();
s.close();
return true;
}
catch (HibernateException erro){
System.out.println(erro.getMessage());
s.flush();
s.clear();
s.getTransaction().rollback();
s.close();
return false;
}
}
public void apagar(K obj) {
try {
apagar(obj, s);
} finally {
s.flush();
s.clear();
s.close();
}
}
public void apagar(K obj, Session s) {
try {
s.flush();
s.clear();
s.getTransaction().begin();
s.delete(obj);
s.getTransaction().commit();
}
catch (HibernateException erro){
System.out.println(erro);
s.flush();
s.clear();
s.getTransaction().rollback();
}finally{
s.close();
}
}
}
Yes, if you change something outside the "view" of hibernate, the hibernate caching does not realize that. So 2 options:
Use hibernate for your deletes/updates etc: This will take care that hibernate stays in sync and performance is the same as it is right now;
use clear or use stateless sessions: See org.hibernate.Session.clear() considered Harmful? for more details on that.
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 am having quite a bit of trouble with the testing of my dao.
I'll show the code at the end.
The problem is:
When i try to test different methods in dataDao: addData & updateData, I want to start over with a clean slot.
Has if when i call update after add i don't want the data added in the test for addData.
I do open a session in the setUp and close it in tearDown that are respecfully annoted with #Before and #After. The hibernate configuration is create-drop so that tables are new each time the session is closed and reopenned.
I am a bit new to hibernate but I did my research and looked it up on the internet for quite a time/weeks.
Here is what I am testing, the two classes: DataDAO and MyDaoManager (he is used because there are more then one table)
Thank you in advance for your help,
MyDaoManager.java
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
public abstract class MyDaoManager<T> {
private SessionFactory sessionFactory = null ;
/**
* <h2>Constructor which will get the sessionFactory from the class HibernateUtil</h2>
*/
public MyDaoManager(){
this.sessionFactory = HibernateUtil.getSessionFactory() ;
}
/**
* <h2>Method which gets the SessionFactory.</h2>
* #return A SessionFactory.
*/
public SessionFactory getSessionFactory() {
return sessionFactory;
}
/**
* <h2>Method which sets the SessionFactory at the moment of the construction.</h2>
* #param sessionFactory The SessionFactory to set.
*/
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
/**
* <h2>Method which adds a given object from the model in the database.</h2>
* #param object Object to add.
*/
public boolean add(T object){
Session session = getSessionFactory().getCurrentSession();
Transaction transaction = session.beginTransaction();
try {
session.save(object);
transaction.commit();
}
catch (RuntimeException e){
transaction.rollback();
throw e ;
}
return true;
}
/**
* <h2>Method which updates a given Object from the model in the database.</h2>
* #param object Object to update.
*/
public void update(T object){
Session session = getSessionFactory().getCurrentSession();
Transaction transaction = session.beginTransaction();
try {
session.merge(object);
transaction.commit();
}
catch (RuntimeException e){
transaction.rollback();
throw e ;
}
}
/**
* <h2>Method which saves or updates a given Object from the model in the database.</h2>
* #param object Object to update.
*/
public void saveOrUpdate(T object){
Session session = getSessionFactory().getCurrentSession();
Transaction transaction = session.beginTransaction();
try {
session.saveOrUpdate(object);
transaction.commit();
}
catch (RuntimeException e){
transaction.rollback();
throw e ;
}
}
/**
* <h2>Method which gets an object from the model thanks to its id in the database.</h2>
* #param id The object's id to get.
* #return An object.
*/
public abstract T getOne(int id);
/**
* <h2>Method which gets all of an object from the model.</h2>
* #return A list of the object.
*/
public abstract List<T> getAll();
/**
* <h2>Method which deletes a given object thanks to its id.</h2>
* #param id The object's id to delete.
*/
public abstract void delete(int id);
}
Here is dataDao.java:
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
public class DataDao extends MyDaoManager<Data>{
#Override
public Data getOne(int id) {
Session session = getSessionFactory().getCurrentSession();
Transaction transaction = session.beginTransaction();
Data data = null;
try {
Query query = session.createQuery("from Data d where d.id= :id").setParameter("id", id);
data = (Data)query.uniqueResult();
transaction.commit();
}
catch (RuntimeException e){
transaction.rollback();
throw e ;
}
return data;
}
#SuppressWarnings("unchecked")
#Override
public List<Data> getAll() {
Session session = getSessionFactory().getCurrentSession();
Transaction transaction = session.beginTransaction();
List<Data> list = null;
try {
list = session.createQuery("from Data d").list();
transaction.commit();
}
catch (RuntimeException e){
transaction.rollback();
throw e ;
}
return list;
}
#Override
public void delete(int id) {
Session session = getSessionFactory().getCurrentSession();
Data data = getOne(id);
Transaction transaction = session.beginTransaction();
try {
session.delete(data);
transaction.commit();
}
catch (RuntimeException e){
transaction.rollback();
throw e ;
}
}
}
Here is my test, DataDaoTest.java:
import static org.junit.Assert.assertTrue;
import java.util.Date;
import java.util.List;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.hibernate.Session;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class DataDaoTest{
private Session session;
private DataDao dataDao;
#Before
public void setUp(){
session = HibernateUtil.getSessionFactory().openSession();
dataDao = new DataDao();
dataDao.setSessionFactory(session.getSessionFactory());
}
#After
public void tearDown(){
session.close();
}
#Test
public void addDataTestShouldWork(){
Data dataTest = new Data();
dataTest.setDate(new Date(System.currentTimeMillis()));
dataTest.setSensor(new Sensor());
dataTest.setValue("test");
dataTest.setIsOnPhone(true);
assertTrue("No add",dataDao.add(dataTest));
List<Data> founded = dataDao.getAll();
DataEqualsBuilder dataEqualsBuilder = new DataEqualsBuilder(dataTest);
assertTrue("Not the same object added and founded", dataEqualsBuilder.equals(founded.get(0)));
}
#Test(expected=RuntimeException.class)
public void addDataTestShouldNotWork(){
dataDao.add(null);
}
#Test
public void updateDataTestShouldWork(){
Data dataTest = new Data();
dataDao.add(dataTest);
dataTest.setValue("test1");
dataDao.update(dataTest);
List<Data> founded = dataDao.getAll();
DataEqualsBuilder dataEqualsBuilder = new DataEqualsBuilder(dataTest);
assertTrue("Not the same object added and founded", dataEqualsBuilder.equals(founded.get(0)));
}
public class DataEqualsBuilder extends EqualsBuilder {
private Data data;
public DataEqualsBuilder( Data data){ this.data= data; }
#Override
public boolean equals(Object obj) {
if (obj == null) { return false; }
if (obj == this) { return true; }
if (obj.getClass() != data.getClass()) {
return false;
}
Data rhs = (Data) obj;
return (DataEqualsBuilder.reflectionEquals(data, rhs, "sensor"));
}
}
}
Finally my hibernate configuration:
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/APISensor</property>
<!-- TODO create specific user -->
<property name="connection.username">root</property>
<property name="connection.password">root</property>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">false</property>
<property name="hbm2ddl.auto">create-drop</property>
</session-factory>
</hibernate-configuration>
Try removing this Hibernate property:
<property name="current_session_context_class">thread</property>
And change your setup/tearDown to:
#Before
public void setUp(){
session = HibernateUtil.getSessionFactory().openSession();
ThreadLocalSessionContext.bind(session);
dataDao = new DataDao();
dataDao.setSessionFactory(session.getSessionFactory());
}
#After
public void tearDown(){
session.close();
ThreadLocalSessionContext.unbind(sessionFactory);
}