I've created method to save entity with new id or update existing via hibernate session. When I use next code:
try {
Session session = sessionWrapper.getSession();
sessionWrapper.beginTransaction();
if (user.getId()==null || session.get(User.class, user.getId())==null) {
return (long) session.save(user);
} else {
session.get(User.class, user.getId());
session.merge(user);
return user.getId();
}
} finally {
sessionWrapper.commit();
sessionWrapper.closeSession();
}
it works ok, but when I use session.saveOrUpdate instead in case of new entity generated id is increased by two, not one. Why and how to fix it?
Related
I have 5 tables data those needs to be saved at a same time into database.My code snippet is as below.
public boolean addStudentDetail(RegisterLoginDetail registerLoginDetail,
StudentRegisterBasicDetail studentRegisterBasicDetail, StudentBoardDetail studentBoardDetail,
StudentSchoolDetail studentSchoolDetail, StudentAdditionalDetail studentAdditionalDetail,
StepCompletionMatrix stepCompletionMatrix) {
boolean isSuceess = true;
Session session = sessionFactory.openSession();
Transaction transaction = null;
try {
transaction = session.beginTransaction();
session.saveOrUpdate(registerLoginDetail);
session.saveOrUpdate(studentRegisterBasicDetail);
session.saveOrUpdate(studentBoardDetail);
session.saveOrUpdate(studentSchoolDetail);
session.saveOrUpdate(studentAdditionalDetail);
session.saveOrUpdate(stepCompletionMatrix);
transaction.commit();
} catch (HibernateException e) {
e.printStackTrace();
session.getTransaction().rollback();
isSuceess = false;
} finally {
if (session != null && session.isOpen()) {
session.close();
}
}
return isSuceess;
}
But for my two transaction data entry for insert operation not found in StudentRegisterBasicDetail table and all other table contains entry for one common id shared between each table.My webapplication is in pilot testing mode and concurrent users are making entry through form.So I am not able to figure out for which reason my entry being skipped in that table.There is no exception log for that table entry and if exception occurs then rollback for all table should be happen or not?
Please help me...
what's wrong guys I have that relations in hibernate #oneToMany:
This is in loan class:
#ManyToOne(cascade=CascadeType.ALL)
private users user;
This is in user class:
#OneToMany(mappedBy="user",fetch=FetchType.LAZY)
private Set<loans> loans=new HashSet<loans>(0);
here I have method to insert new loan:
public static void addLoanToUser(Integer userID,String brand,String model,String registration,String loanStart , String loanEnd){
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction transaction = null;
try {
transaction = session.beginTransaction();
users user = (users) session.load(users.class, userID);
Set<loans> loanSet = new HashSet();
loans loan = new loans();
loan.setBrand(brand);
loan.setModel(model);
loan.setRegistration(registration);
loan.setLoanStart(loanStart);
loan.setLoanEnd(loanEnd);
loan.setPaydone("no");
loanSet.add(loan);
user.setLoans(loanSet);
session.saveOrUpdate(user);
session.save(loan);
session.getTransaction().commit();
} catch (HibernateException e) {
transaction.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
When I insert data to the database there is always NULL on Foreign Key.
I tried to find sth on the stack but nothing helped.
Its because you have to set relation on "key holder" in your case that is loan entity. So
users user = (users) session.load(users.class, userID);
loans loan = new loans();
..... setup
loan.setUser(user)
session.saveOrUpdate(user);
And you do realize, that if user will take new loan, you effectively removes other loans of that user (in current session) by setting brand new user.loans set ? :) I wish banking systems work like that :)
I am fully testing an entity on my unit test, and almost everything worked so far: create, update, list. However, when I try to delete a record, it is not getting deleted. Here is the code I am using:
public void delete (Integer id) {
// This doesnt work even though I know user is set and id is not null
User user = find(id);
getSession().delete(user);
// This will work
// Query query = getSession().createSQLQuery("DELETE FROM users WHERE id = " + id);
// query.executeUpdate();
}
private Session getSession() {
if (session == null) {
try {
session = SessionFactoryUtils.getSession(sessionFactory, Boolean.TRUE);
TransactionSynchronizationManager.bindResource(session.getSessionFactory(), new SessionHolder(session));
} catch (Exception e) {
session = SessionFactoryUtils.getSession(sessionFactory, Boolean.FALSE);
}
}
return session;
}
If I execute the query directly it works but using the delete() method doesnt. I think it may be related to committing the transaction but I already tried something like that and no luck. Any ideas?
I found the problem with this one.
First, find() method was evicting my user model, and probably taking it out of the session.
After delete(), I also needed to session.flush()
First time that I ran into this error I've surrounded my tx.commit() with a if condition but am not sure why I am still receiving this error.
Struts Problem Report
Struts has detected an unhandled exception:
Messages:
Transaction not successfully started
File: org/hibernate/engine/transaction/spi/AbstractTransactionImpl.java
Line number: 200
Stacktraces
org.hibernate.TransactionException: Transaction not successfully started
org.hibernate.engine.transaction.spi.AbstractTransactionImpl.rollback(AbstractTransactionImpl.java:200)
After a product has been selected by user, in my main function I will call two functions as following.
First function to retrieve the object of selected product.
Second function to check if selected user has the product therefore it returns true if client has the product otherwise returns false;
Function 1
....
Product pro = new Product();
final Session session = HibernateUtil.getSession();
try {
final Transaction tx = session.beginTransaction();
try {
pro = (Product) session.get(Product.class, id);
if (!tx.wasCommitted()) {
tx.commit();
}
} catch (Exception e) {
tx.rollback();
e.printStackTrace();
}
} finally {
HibernateUtil.closeSession();
}
.....
Function 2
.....
final Session session = HibernateUtil.getSession();
try {
final Transaction tx = session.beginTransaction();
try {
User user = (User) session.get(User.class, id);
if (!tx.wasCommitted()) {
tx.commit();
}
if(client.hasProduct(proId)){
return client.getProduct(proId);
}
return false;
} catch (Exception e) {
tx.rollback(); <<<Error is on this line
e.printStackTrace();
}
} finally {
HibernateUtil.closeSession();
}
....
Take a look at Transaction.isActive() method. You can wrap call to rollback() method with condition, checking whether transaction is still active. And the second, I'd prefer the following code:
final Session session = HibernateUtil.getSession();
try {
final Transaction tx = session.beginTransaction();
// do things
tx.commit();
} finally {
if (tx.isActive()) {
try {
tx.rollback();
} catch (Exception e) {
logger.log("Error rolling back transaction", e);
}
}
try {
session.close();
} catch (Exception e) {
logger.log("Error closing session", e);
}
}
Of course, code in the finally section better to wrap into public static method and just call it in every finally.
BTW, why are you doing something outside tranaction? I usually commit after all things get done, to achieve a better consistency and avoid LazyInitializationException.
One possibility is that the exception you are catching in the second functions is from the code after the commit(), so you end up trying to rollback a transaction that is already committed, which is not allowed.
You could try reorganizing your code to make sure that rollback is never called after commit. Maybe even something simple like reducing the scope of the inner try-catch:
final Session session = HibernateUtil.getSession();
try {
final Transaction tx = session.beginTransaction();
try {
User user = (User) session.get(User.class, id);
if (!tx.wasCommitted()) {
tx.commit();
}
} catch (Exception e) {
tx.rollback();
e.printStackTrace();
}
if(client.hasProduct(proId)){
return client.getProduct(proId);
}
return false;
} finally {
HibernateUtil.closeSession();
}
The error indicates the transaction wasn't started at the time tried to roll back - and the problem may be that you are trying to wrap a get, which does not alter the db state and does not leave behind garbage that needs to be committed or rolled back. Nothing changes when you perform select *.
In addition to this, you may want to extract this transaction handling into a common method that is independent of the work being done, so you don't have to write this over and over again, that leaves your code open for bugs. Basically, it seems like you are getting DB objects but then intermingling some business logic withing the same method. Perhaps consider doing something like below:
DB Handling Function
public static <T> T getDBObject( Class<T> clazz, Serializable id )
throws SQLException
{
Session session = null;
try
{
session = HibernateUtil.getSession();
return (T)session.get( clazz, id );
}
finally
{
if ( session != null )
{
session.close();
}
}
}
Now that you can pull object of the DB (note that they will be detached, but still valid), you can then perform work on the objects. I many not have captured exactly what you need to check, but it seems like it is something like:
Example Comparison Function
public boolean doesUserHaveProduct(Serializable userId, Serializable productId)
{
try
{
User user = getDBObject(User.class, userId);
Product product = getDBObject( Product.class, productId );
return user.hasProduct( product );
}
catch (SQLException e)
{
e.printStackTrace();
return false;
}
}
i am using the following approach to sole lazy initialization problem in hibernate.Pleas tell me whether it will work or not .
I have to implement my transcation in my persistance layer compulsary due to some reasons.
public class CourseDAO {
Session session = null;
public CourseDAO()
{
this.session = this.session = HibernateUtil.getSessionFactory().getCurrentSession();
}
public Course findByID(int cid){
Course crc = null;
Transaction tx = null;
try {
tx = session.beginTransaction();
Query q = session.createQuery("from Course as course where course.cid = "+cid+" ");
crc = (Course) q.uniqueResult();
//note that i am not commiting my transcation here.Because If i do that i will not be able to
//do lazy fetch
}
catch (HibernateException e)
{
e.printStackTrace();
tx.rollback();
throw new DataAccessLayerException(e);
}
finally
{
}
return crc;
}
}
and in the filter i am using the folling code
session = HibernateUtil.getSessionFactory().getCurrentSession();
if(session.isOpen())
HibernateUtil.getSessionFactory().getCurrentSession().getTransaction().commit();
IS this approach right??
Can it can have any problem
could you explain why do you need to have ur transactions in ur repositories? the problem there is that they are going to be so fine-grained, so you are not gonna get any advantage from the session caching
then you are opening the transaction there but closing it in your filter. what happens if you access multiple repositories in your service? Maybe i am not understanding what you mean but i think you need to re-think the reasons that force you to manage your transactions in your repositories
When do you create you CourseDAO? If it is a singleton bean or something else that lives longer than a page view, it will need to keep a SessionFactory and generate a new Session when it needs one rather than keeping a Session.