Hibernate: "Session is closed" although never closed (manually) - java

I got a really weird problem here and I absolutely cannot understand why this is happening.
The problem looks like this:
I got a class called "SmampiAccount" which holds a list of email accounts. The mapping file looks like this (shortened):
<hibernate-mapping>
<class name="com.smampi.web.model.account.SmampiAccount" table="SMAMPIACCOUNT">
<id name="id" type="long" access="field">
<column name="SMAMPI_ACCOUNT_ID" />
<generator class="native" />
</id>
<bag name="mailAccounts" table="MAILACCOUNTS" lazy="false" inverse="true">
<key column="SMAMPI_ACCOUNT_ID"></key>
<one-to-many class="com.smampi.web.model.mail.account.MailAccount"/>
</bag>
</class>
</hibernate-mapping>
I get instances of this class through this method:
public SmampiAccount loadSmampiAccount(long id) throws FailedDatabaseOperationException {
SmampiAccount smampiAccount = null;
Session session = null;
Transaction transaction = null;
try {
session = getSession();
transaction = session.beginTransaction();
smampiAccount = (SmampiAccount) session.load(com.smampi.web.model.account.SmampiAccount.class, id);
List<MailAccount> mailAccounts = smampiAccount.getMailAccounts();
doSomething(mailAccounts);
transaction.commit();
} catch (Exception e) {
rollback(transaction);
closeSession();
throw new FailedDatabaseOperationException(e);
} finally {
closeSession();
}
return smampiAccount;
}
private Session getSession() {
if (_session == null) {
_session = getSessionFactory().openSession();
}
if (_session.isOpen() == false) {
_session = getSessionFactory().openSession();
}
return _session;
}
This works fine as it is.
Now, I wanted to add a new property to the mapping file in order to save a reference to a default email account:
<many-to-one name="defaultMailAccount" column="DEFAULT_MAIL_ACCOUNT_ID" />
Now, I get an exception in the method public SmampiAccount loadSmampiAccount(long id) in this line:
List<MailAccount> mailAccounts = smampiAccount.getMailAccounts();
Stacktrace:
org.hibernate.SessionException: Session is closed!
at org.hibernate.impl.AbstractSessionImpl.errorIfClosed(AbstractSessionImpl.java:72)
at org.hibernate.impl.SessionImpl.getPersistenceContext(SessionImpl.java:1954)
at org.hibernate.event.def.DefaultPostLoadEventListener.onPostLoad(DefaultPostLoadEventListener.java:49)
at org.hibernate.engine.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:250)
at org.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:982)
at org.hibernate.loader.Loader.doQuery(Loader.java:857)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:274)
at org.hibernate.loader.Loader.loadEntity(Loader.java:2037)
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:86)
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:76)
at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:3293)
at org.hibernate.event.def.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:496)
at org.hibernate.event.def.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:477)
at org.hibernate.event.def.DefaultLoadEventListener.load(DefaultLoadEventListener.java:227)
at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:147)
at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:1090)
at org.hibernate.impl.SessionImpl.immediateLoad(SessionImpl.java:1026)
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:176)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:215)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
at com.smampi.web.model.account.SmampiAccount_$$_javassist_19.getMailAccounts(SmampiAccount_$$_javassist_19.java)
How is this possible?
The session gets not closed manually and .commit() isn't called yet (which would normally close the session).
It's also not possible that another method is interfering here because I create a new hibernate session for each method call which is dedicated just for this one method.
Edit
I added some debug info on the session open status:
session = getSession();
System.err.println(session.isOpen());
transaction = session.beginTransaction(); // 1 (true)
System.err.println(session.isOpen()); // 2 (true)
smampiAccount = (SmampiAccount) session.load(com.smampi.web.model.account.SmampiAccount.class, id);
System.err.println(session.isOpen()); // 3 (true)
List<MailAccount> mailAccounts = smampiAccount.getMailAccounts(); // Throws exception that session is closed
doSomething(mailAccounts);
System.err.println(session.isOpen()); // 4 (not called)
transaction.commit();
This gives me:
true
true
true
org.hibernate.SessionException: Session is closed!

I am the biggest idiot in the world.
In the setter of defaultMailAccount, I had this:
public void setDefaultMailAccount(MailAccount defaultMailAccount) {
this.defaultMailAccount = defaultMailAccount;
try {
databasecontroller.update(this);
} catch (FailedDatabaseOperationException e) {
handleException(e, false, null, null);
}
}
The call to databasecontroller.update(this) caused a cascade whenever Hibernate tried to load a persisted version from the database and that again caused the session to close.
Moving the call of databasecontroller.update(..) to outside the method fixed the issue.
Sorry to everyone for taking up your time and thanks for the help!

Related

Hibernate get data .list() depricated and table not mapped. what to do?

I saw nearly all questions and answers for this on stackoverflow, but all answers are the same. That you should use something like this Query query = session.createQuery("from theme").list();
but .list() is depricated and I can´t use it anymore.
So the first Question is, what should I use instead of .list()and why I get this exeption java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: theme is not mapped [from theme]
Query Method
public ObservableList<String> getThemes(){
ObservableList<String> obsList = FXCollections.observableArrayList();
SessionFactory factory = new Configuration()
.configure("hibernate.cfg.xml")
.buildSessionFactory();
Session session = factory.getCurrentSession();
try {
session.beginTransaction();
Query query = session.createQuery("from theme"); // why not mapped
//cant use .list()?
session.getTransaction().commit();
System.out.println("query " + query);
} catch (Exception e) {
e.printStackTrace();
}finally{
session.close();
}
return obsList; // nothing at the moment
hibernate.cfg.xml
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.driver_class">org.sqlite.JDBC</property>
<!-- I know sqlite with an mysql dialect isnt the best, in the future it
will be mySql--> <property
name="connection.url">jdbc:sqlite:C:\\DokiDB\\database.db</property>
<property name="connection.username">progdm</property>
<property name="connection.password">release</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="connection.pool_size">1</property>
<property name="show_sql">true</property>
<property name="current_session_context_class">thread</property>
</session-factory>
</hibernate-configuration>
mapped class
#Entity
#Table(name="theme")
public class mapTheme {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="theme_id")
private int theme_id;
#Column(name="theme_name")
private String theme_name;
public int getTheme_id() {
return theme_id;
}
public void setTheme_id(int theme_id) {
this.theme_id = theme_id;
}
public String getTheme_name() {
return theme_name;
}
public void setTheme_name(String theme_name) {
this.theme_name = theme_name;
}
public mapTheme(String theme_name) {
super();
this.theme_name = theme_name;
}
public mapTheme(){
}
}
what can I do?
The table name used in the query is not the name of the table in database, it should be the name of the entity class.
In this case you must use
Query query = session.createQuery("from mapTheme");
instead of :
Query query = session.createQuery("from theme")

Using Hibernate To Save Failed

Using Hibernate To Save Failed
When I use hibernate to save an entity to the database. Althogh there is no exception or error in the console(I've corretly configured log4j).
There is no an insert sql in the console and there is no data in the database.
It's strange, I can successfully use hibernate to get data from database and there are select sql in the console.
BTW.I used myeclipse reverse engeering to build the model and hbm file.
I tried several ways but failed:
It's not about transaction,I commit in TeamService.
I set log4j.properties to see all the errors ,but there is no exception.
I tried to assign the entity I need to save to a new instance, but still, no data in
I thought it is about composite-id in hbm ,but I don't know how to fix it .
Here's my Team entity(I eliminated the irrelevant part)
private TeamId id;
private Classes classes;
Here's my Team hbm
<hibernate-mapping>
<class name="edu.wzy.model.Team" table="team" catalog="test3" >
<composite-id name="id" class="edu.wzy.model.TeamId">
<key-property name="TNo" type="java.lang.Integer">
<column name="T_NO" />
</key-property>
<key-many-to-one name="SUser" class="edu.wzy.model.SUser">
<column name="S_ID" />
</key-many-to-one>
</composite-id>
<many-to-one name="classes" class="edu.wzy.model.Classes" fetch="select">
<column name="C_ID" not-null="true">
</column>
</many-to-one>
</class>
</hibernate-mapping>
Here's my TeamService
public class TeamServiceImpl implements TeamService
{
TeamDAO teamDAO=new TeamDAO();
public void save(Team t)
{
Session session=HibernateUtil.getCurrentSession();
session.getTransaction().begin();
teamDAO.save(t);
session.getTransaction().commit();
}
}
Here's my Dao
public void save(Team transientInstance)
{
try
{
getSession().save(transientInstance);
log.debug("save successful");
} catch (RuntimeException re)
{
log.error("save failed", re);
throw re;
}
}
Here's my action(I eliminated the irrelevant part)
public class TeamAction extends BaseAction implements ModelDriven<Team>
{
public String add()
{
Classes classes = classesService.findbyid(team.getClasses().getId());
Set s = team.getClasses().getStudents();
Iterator it = s.iterator();
while (it.hasNext())
{studentid = (String) it.next();}
Student student = studentService.findbyid(Integer.parseInt(studentid));
Team t=new Team();
t.setId(team.getId());
classes.getStudents().add(student);
t.setClasses(classes);
teamService.save(t);
return SUCCESS;
}
}
Try session.flush() before commit. Just like
public class TeamServiceImpl implements TeamService {
TeamDAO teamDAO = new TeamDAO();
public void save(Team t) {
Session session = HibernateUtil.getCurrentSession();
session.getTransaction().begin();
teamDAO.save(t);
session.flush();
session.clear();
session.getTransaction().commit();
session.close();
}
}
I have found where the problem is.
The problem is that the save method is not in the same session that TeamService provide.
I made a mistake.
The Dao classes are generated by machine, they extends a fathre class which has a method to generate session. But I also create a class HibernateUtil to generate session.
So save method is not in the same session as Service,which lead to failed saving.
The answer to this question is to modify the method in Dao.
public void save(Classes transientInstance)
{
log.debug("saving Classes instance");
try
{
HibernateUtil.getCurrentSession().save(transientInstance);
log.debug("save successful");
} catch (RuntimeException re)
{
log.error("save failed", re);
throw re;
}
}

HQL many to many query in the same class

I have a database with two tables, Account and Favorites. Favorites is a many-to-many table. It holds:
listowner (foreign key referencing the Account primary key)
favorite (also a foreign key referencing the Account primary key)
Favorites does not have its own class in my program. I only have Account.java, which holds two sets.
private Set<Account> favorites;
private Set<Account> listOwner;
//the getters and setters for these sets
The relevant mapping file:
<set name="favorites" table="favorites" inverse="true" cascade="all">
<key column="listowner" />
<many-to-many column="favorite" class="Models.Account" />
</set>
<set name="listOwner" table="favorites" cascade="all">
<key column="favorite" />
<many-to-many column="listowner" class="Models.Account" />
</set>
Now, saving to the database works fine. I can save a favorite account with a listowner and see him appear when directly accessing the database. But I can't get this information out of the database again. I want a list of all favorites of an account. In SQL, this would be:
SELECT favorite
FROM favorites
WHERE listowner = "Bob"
My current attempt:
public static List<Account> getFavorites(Account account)
{
List<Account> list = null;
Transaction tx = null;
try
{
tx = session.beginTransaction();
list = session.createQuery("from Account a where a.listOwner.accountName = :name").setParameter("name", account.getAccountName()).list();
tx.commit();
} catch (Exception e)
{
if (tx != null)
{
tx.rollback();
}
System.out.println("getFavorites failed");
e.printStackTrace();
} finally
{
return list;
}
}
According to the debugger, it's failing on
list = session.createQuery("from Account a where a.listOwner.accountName = :name").setParameter("name", account.getAccountName()).list();
What am I doing wrong? I'm not getting any exceptions.
Your query is wrong. a.listOwner is of type Set<Account>. And a Set<Account> doesn't have any accountName property. To be able to add restrictions on an element of a.listOwner, you need an explicit join:
select a from Account a
inner join a.listOwner owner
where owner.accountName = :name
That said, your whole method should simply be replaced by
return account.getFavorites();

Expected positional parameter count: 1, actual parameters: []

I am getting this below exception when I am trying to execute a Stored procedure using HIbernate from DaoImpl Class.
I am not sure of what is wrong ..I tried all the ways to fix it but did not resolve the issue.
Could anyone please help me ,figure out whats wrong with the code or the mapping file.
The more I am trying to fix ,something the more exceptions I am getting.. I am connectuing to Oracle 9i DB.
I am struggling on this from really 2 weeks ending up no where.. can anyone please help me fix this issue.
Mapping file:
<hibernate-mapping>
<sql-query name="proc_drsrr_sel_ValDDSummaryBal">
<!--CALL proc_drsrr_sel_ValDDSummaryBal(:param1)]]>-->
{ call DEFAULT_SCHEMA.proc_name(?,:param1) }
Main-Class:
public static void main(String[] args) {
String procName = "proc_name";// args[0];
String params = "param1:500089" ;
DAO Implementation:
#SuppressWarnings("unchecked")
public void callProc(String procName, Map paramMap) throws SQLException {
Session session = null;
Transaction tx = null;
try {
session = HibernateUtils.getSessionFactory().getCurrentSession();
tx = session.beginTransaction();
String dbURL = session.connection().getMetaData().getURL().toString();
System.out.println("Conenction DB URL "+ dbURL );
tx.setTimeout(5);
String[] keys = new String[paramMap.size()];
keys = (String[]) paramMap.keySet().toArray(keys);
Query query = session.getNamedQuery(procName)
.setParameter("param1", "5501010");
}
List result = query.list();
System.out.println(query.getQueryString());
for (int i = 0; i < result.size(); i++) {
// logging the information.
log.info(i);
}
tx.commit();
} catch (RuntimeException exception) {
exception.printStackTrace();
try {
tx.rollback();
} catch (RuntimeException rbe) {
log.error("Couldn’t roll back transaction", rbe);
rbe.printStackTrace();
}
throw exception;
} finally{
if(session !=null){
session.flush();
session.close();
}
cfg.xml
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.url">jdbc:oracle:thin:#ldap://hdsoid.ute.ovi.com:3060/UT1DEV,cn=OracleContext,dc=ute,dc=ovi,dc=com</property>
<property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
<property name="hibernate.connection.username">nameapp</property>
<property name="connection.password">nameapp</property>
<property name="connection.pool_size">1</property>
<property name="hibernate.dialect">org.hibernate.dialect.OracleDialect</property>
<!-- <property name="connection.release_mode">after_statement</property> -->
<property name="default_schema">DEFAULT_SCHEMA</property>
<property name="current_session_context_class">thread</property>
<property name="hibernate.show_sql">true</property>
<!-- mapping files -->
<mapping resource="com/ovi/domain/hibernate.hbm.xml" />
</session-factory>
</hibernate-configuration>
You are missing to set the ? parameter which is a so called positional parameter. In contrast to named parameters like :foo
When you have some SQL you must also ensure not to have any Question Marks inside comments! That's what I just ran into. Same holds for : in comments, especially if they are followed by a space.

understanding NonUniqueObjectException in hibernate

Trying to understand more about Hibernate,I wrote some code which creates some entities and saves them in db and then tries to delete one of the entities.
The mapping file for entity Customer has id generator set to native.I am using postgresql as db.
...
<class name="Customer" table="CUSTOMER">
<id column="CUSTOMER_ID" name="customer_id" type="java.lang.Long">
<generator class="native"/>
</id>
...
I came across hibernate.NonUniqueObjectException.
org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [org.me.hibernatestore.Customer#129]
Full stack trace here
I fired up the eclipse debugger and found that the object involved has same address in all the involved methods ..
The relevant part of the code is
public class Main {
CustomerDao custdao;
Customer mark;
public void storeDemo(){
custdao = DaoFactory.getCustomerDao();
createCustomers();
updateEntities();
deleteCustomer(mark);
}
private void createCustomers() {
mark = new Customer();
mark.setName("mark");
mark.setEmailAddress("mark#home");
mark.setAddress("121,3rd avenue");
mark.setCity("San Diego");
mark.setState("CA");
mark.setCountry("U.S.A");
}
private void updateEntities() {
Transaction tx = null;
Session session = HibernateUtil.getCurrentSession();
try{
tx = session.beginTransaction();
custdao.saveOrUpdateCustomer(mark);
tx.commit();
}catch(RuntimeException e){
tx.rollback();
throw e;
}
}
private void deleteCustomer(Customer cust){
Transaction tx = null;
Session session = HibernateUtil.getCurrentSession();
try{
tx = session.beginTransaction();
String custName = cust.getName();
custdao.deleteCustomer(cust);
tx.commit();
}catch(RuntimeException e){
tx.rollback();
throw e;
}
}
public static void main(String[] args) {
new Main().storeDemo();
}
}
With the help of debugger I found the address of object 'mark'
Main.createCustomers(): mark-> Customer#2bc3f5
CustomerDaoImpl.saveOrUpdateCustomer(Customer customer):customer-> Customer#2bc3f5
BaseDaoImpl.saveOrUpdate(T obj):obj-> Customer#2bc3f5
Main.deleteCustomer(Customer customer):customer-> Customer#2bc3f5
CustomerDaoImpl.deleteCustomer(Customer customer):customer-> Customer#2bc3f5
BaseDaoImpl.delete(T obj):obj-> Customer#2bc3f5
Experimenting further,I modified the code and through dao.findById() got a different object with same id and used that in deleteCustomer().This time the code worked without throwing any exception
public class Main {
CustomerDao custdao;
Customer mark;
public void storeDemo(){
custdao = DaoFactory.getCustomerDao();
createCustomers();
updateEntities();
Long mark_id = mark.getCustomer_id();
Customer mark2 = getCustomer(mark_id);
deleteCustomer(mark2);
}
private Customer getCustomer(Long id){
Transaction tx = null;
Customer cust = null;
Session session = HibernateUtil.getCurrentSession();
try{
tx = session.beginTransaction();
return custdao.findCustomerById(id);
}catch(RuntimeException e){
throw e;
}
}
...
}
Can someone explain this behaviour?My understanding about the 'a different object with the same identifier value' part of the error message is fuzzy ..The object as shown in debugger in the first case has same memory address everywhere in the code.Then how can it be a different object?
sincerely
Jim
This exception usually occurs when dealing with detached objects. In order to avoid that, you have to get the object and delete it in the same session or reattach it to the session and then delete it.
Hope this helps!

Categories