Hello guys,
Iv got this really weird behavior in my hibernate. I'v got a transactional service method, code is below:
Code:
public Customers applyForPartnerAccount(Customers customer) throws CustomersSQLException, CustomersException {
logger.debug("Starting Partner Application transaction.");
if(customer == null) {
throw new CustomersSQLException("Can not apply account to a null or empty customer.");
}
if(!isValidForPartnerApplication(customer.getPartner())) {
throw new CustomersException("Customer is not allowed to apply for a partner account");
}
customer.setPartner(Constants.CUSTOMERS_PARTNER_P);
logger.debug("Updating roles.");
Role role = (Role) customersDao.get(Role.class, Constants.ROLE_PENDING_APPLY_CODE);
customer.addRole(role);
logger.debug("Persisting updated customer.");
logger.info("Version before save: " + customer.getVersion());
customer = (Customers) customersDao.save(customer);
logger.debug("Creating OperationLogs object for this transaction.");
OperationLogs operationLog = new OperationLogs(
customer.getLoginname(),
Constants.OPERATIONLOGS_APPLY_PARTNER,
customer.getLoginname(),
Constants.FLAG_ONE,
DateUtil.getCurrentTimestamp()); // this does not mean it failed, it means it's still pending flag = 1
logger.debug("Persisting operationLog object: " + operationLog.toString());
logger.info("Version after save: " +customer.getVersion());
customersDao.save(operationLog);
logger.debug("Completed Partner Application transaction.");
return customer;
}
And please examine my stacktrace. It does not make any sense:
Code:
2009-09-05 10:55:40,611 INFO [crown.service.implementations.CustomersServiceImpl] - Version before save: 1 <<<<<<
Hibernate: select customers0_.loginname as loginname0_0_, customers0_.AccountName as AccountN2_0_0_, customers0_.Address as Address0_0_, customers0_.age as age0_0_, customers0_.AliasName as AliasName0_0_, customers0_.createtime as createtime0_0_, customers0_.Credit as Credit0_0_, customers0_.Email as Email0_0_, customers0_.flag as flag0_0_, customers0_.Gender as Gender0_0_, customers0_.keyCode as keyCode0_0_, customers0_.level as level0_0_, customers0_.partner as partner0_0_, customers0_.partnername as partner14_0_0_, customers0_.password as password0_0_, customers0_.phone as phone0_0_, customers0_.points as points0_0_, customers0_.postcode as postcode0_0_, customers0_.subaccount as subaccount0_0_, customers0_.version as version0_0_ from customers customers0_ where customers0_.loginname=?
Hibernate: select roles0_.loginname as loginname1_, roles0_.roleId as roleId1_, role1_.id as id5_0_, role1_.description as descript2_5_0_, role1_.name as name5_0_ from user_role roles0_ left outer join role role1_ on roles0_.roleId=role1_.id where roles0_.loginname=?
2009-09-05 10:55:50,867 INFO [crown.service.implementations.CustomersServiceImpl] - Version after save: 1 <<<<<<<<<
Hibernate: insert into operationlogs (action, createtime, flag, loginname, referencenumber) values (?, ?, ?, ?, ?) <<<<<< insert statement #1
Hibernate: update customers set partner=?, version=? where loginname=? and version=? <<<<<<<<<< update statement #1
Hibernate: insert into user_role (loginname, roleId) values (?, ?)
2009-09-05 10:55:58,226 INFO [crown.service.implementations.CustomersServiceImpl] - Version before save: 1 <<<<<<<<<<
Hibernate: select customers0_.loginname as loginname0_0_, customers0_.AccountName as AccountN2_0_0_, customers0_.Address as Address0_0_, customers0_.age as age0_0_, customers0_.AliasName as AliasName0_0_, customers0_.createtime as createtime0_0_, customers0_.Credit as Credit0_0_, customers0_.Email as Email0_0_, customers0_.flag as flag0_0_, customers0_.Gender as Gender0_0_, customers0_.keyCode as keyCode0_0_, customers0_.level as level0_0_, customers0_.partner as partner0_0_, customers0_.partnername as partner14_0_0_, customers0_.password as password0_0_, customers0_.phone as phone0_0_, customers0_.points as points0_0_, customers0_.postcode as postcode0_0_, customers0_.subaccount as subaccount0_0_, customers0_.version as version0_0_ from customers customers0_ where customers0_.loginname=?
Hibernate: select roles0_.loginname as loginname1_, roles0_.roleId as roleId1_, role1_.id as id5_0_, role1_.description as descript2_5_0_, role1_.name as name5_0_ from user_role roles0_ left outer join role role1_ on roles0_.roleId=role1_.id where roles0_.loginname=?
2009-09-05 10:56:02,730 INFO [crown.service.implementations.CustomersServiceImpl] - Version after save: 1 <<<<<<<<<<
Hibernate: insert into operationlogs (action, createtime, flag, loginname, referencenumber) values (?, ?, ?, ?, ?) <<<<<<< insert statement #2
Hibernate: update customers set partner=?, version=? where loginname=? and version=? <<<<<<< update statement #2
2009-09-05 10:56:02,736 ERROR [org.hibernate.event.def.AbstractFlushingEventListener] - Could not synchronize database state with session
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [crown.model.Customers#p124578]
at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:1765)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2407)
at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2307)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2607)
at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:92)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:250)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:234)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:142)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:655)
// omitted some part
I dont know exactly why is this so, but the sequence of code execution is quite not sync'd with how i expect it to be.
If you examine my code closely, I wanted to print the version number before save, and then save the record, after that, get the version number after save. The problem is, it's not the sequence here. What happen is this, print version number before save, print version number after save, update record, print version number before save (the value is the same with the previous one), print version number after save (value is the same with the previous one), update record and boom exception occurs.
Base on the stacktrace, why do i have two insert statements (operationLogs) and two update statements (customer table)????? And why does the sequence of execution wont match, and why does after saving/persisting/updating, the retrieved customer does not have the correct version. Im quite sure that the customer i passed as parameter in this method is updated since i retrieved the customer first (fresh from the database) before passing it to this method.
Im so confused guys. I need this system up and running already. Can you please shed me some light?
Thanks,
-marckun