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;
}
}
Related
I have a trouble when running my web application that tries to get all the information from the table snowboard and put it in a list which I will then print out in the xHtml. But I get this exception down below.
org.hibernate.TransactionException: nested transactions not supported
The thing is that I have no clue why this exception happens so would appreciate some explanation. Also if you find any trouble in the code that would be fantastic.
This is the exception that I get.
HibernateUtil
public class HibernateUtil {
private static final SessionFactory sessionFactory;
static {
try {
// Create the SessionFactory from standard (hibernate.cfg.xml)
// config file.
sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
} catch (Throwable ex) {
// Log the exception.
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
SnowHelper, HelperClass
public class SnowHelper {
Session session = null;
public SnowHelper() {
this.session = HibernateUtil.getSessionFactory().getCurrentSession();
}
public List getSnowboards() {
List<Snowboard> snowboardList = null;
try {
Transaction tx = session.beginTransaction();
Query q = session.createQuery("from Snowboard");
snowboardList = (List<Snowboard>) q.list();
} catch (Exception e) {
e.printStackTrace();
}
return snowboardList;
}
}
HibernateCfg
<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://cpsrv01.misshosting.com:3306/etvffqgz_snowshop</property>
<property name="hibernate.connection.username">etvffqgz_user</property>
<property name="hibernate.connection.password">759486456</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.current_session_context_class">thread</property>
<property name="hibernate.query.factory_class">org.hibernate.hql.internal.classic.ClassicQueryTranslatorFactory</property>
<mapping resource="Hibernate/Account.hbm.xml"/>
<mapping resource="Hibernate/Snowboard.hbm.xml"/>
</session-factory>
</hibernate-configuration>
SnowboardBean, ManagedBean class
#Named(value = "snowboardBean")
#Dependent
public class SnowboardBean {
private List<Snowboard> snowList;
private SnowHelper snow;
/**
* Creates a new instance of SnowboardBean
*/
public SnowboardBean() {
snowList = new ArrayList<>();
snow = new SnowHelper();
snowList = snow.getSnowboards();
}
/**
* #return the snowList
*/
public List<Snowboard> getSnowList() {
return snowList;
}
}
In this bit here.. commit your transaction
Transaction tx = session.beginTransaction();
Query q = session.createQuery("from Snowboard");
snowboardList = (List<Snowboard>) q.list();
tx.commit();
Otherwise you simply open a new transaction without closing it every time you invoke this method.. eventually one of them is opened while some other is not commited yet.
If you were using 'container managed transactions' (provided by Spring of EJB's) you would not have to worry about explicitly committing your transactions. Here you are using 'extended transaction management' and you have to take care of that yourself.
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")
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();
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!
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!