-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 
Author Message
 Post subject: HibernateOptimisticLockingFailureException on MariaDB
PostPosted: Thu Sep 08, 2016 4:32 am 
Newbie

Joined: Thu Sep 08, 2016 4:20 am
Posts: 1
We are migrating application from oracle to Mariadb. Using container transactions and Spring transaction management. I am getting error for code where the one record is saved and updated in same transaction(Service bean method). Same code is working fine for Oracle database.

I am the only one who is connected to the mariadb database. Help will be appreciated.

Error:

org.springframework.orm.hibernate4.HibernateOptimisticLockingFailureException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; nested exception is org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1

JDK: 1.6, Tomcat: 7.0.65, Spring: 4.1, hibernate: 4.2.21

mariadb version: 10.1.13-MariaDB

driver: mariadb-java-client-1.1.9

Dialects: org.hibernate.dialect.MySQLInnoDBDialect

and
i tried with org.hibernate.dialect.MySQLDialect also same error is coming.

Code:
@Entity
    @Table(name = "DEAL")
    public class Deal implements Serializable {
   
        private static final long serialVersionUID = 1196605299069938794L;
   
        @Id
        @Column(name = "SK_DEAL_ID")
        @GeneratedValue(strategy = GenerationType.TABLE, generator = "Deal_SEQ")
        @TableGenerator(name = "Deal_SEQ", pkColumnValue = "DEAL_SEQUENCE", allocationSize = 1)
       @Access(AccessType.PROPERTY)
        private Long id;
   
        @Column(name = "INT_DEAL_ID", length = 50)
        private String internalDealId;
   
        @Column(name = "DEAL_DESC", length = 100)
        private String description;
   
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "LAST_UPDATED_ID")
        private SysUser lastUpdatedId;
   
        @Version
        @Type(type = "timestamp")
        @Column(name = "LAST_UPDATED")
        private Date lastUpdated;
   
        @Type(type = "timestamp")
        @Column(name = "CREATION_DATE")
        private Date creationDate;
   
        @Type(type = "timestamp")
        @Column(name = "CREATION_DATE_USER_TZ")
        private Date creationDateUserTz;
   
        @Type(type = "date")
        @Column(name = "END_DATE")
        private Date endDate;
   
       
        public Long getId() {
            return id;
        }
   
        public void setId(Long id) {
            this.id = id;
        }
   
        public String getInternalDealId() {
            return this.internalDealId;
        }
   
        public void setInternalDealId(String internalDealId) {
            this.internalDealId = internalDealId;
        }
   
       
        public String getDescription() {
            return this.description;
        }
   
        public void setDescription(String description) {
            this.description = description;
        }
   
        public SysUser getLastUpdatedId() {
            return this.lastUpdatedId;
        }
   
        public void setLastUpdatedId(SysUser lastUpdatedId) {
            this.lastUpdatedId = lastUpdatedId;
        }
   
        public Date getLastUpdated() {
            return this.lastUpdated;
        }
   
        public void setLastUpdated(Date lastUpdated) {
            this.lastUpdated = lastUpdated;
        }
   
        public Date getCreationDate() {
            return this.creationDate;
        }
   
        public void setCreationDate(Date creationDate) {
            this.creationDate = creationDate;
        }
   
        public Date getCreationDateUserTz() {
            return creationDateUserTz;
        }
   
        public void setCreationDateUserTz(Date creationDateUserTz) {
            this.creationDateUserTz = creationDateUserTz;
        }
   
        public Date getEndDate() {
            return endDate;
        }
   
        public void setEndDate(Date endDate) {
            this.endDate = endDate;
        }
   
   
        @Override
        public String toString() {
            return new StringBuilder("{")
            .append("id=").append(id)
            .append(",internalDealId=").append(internalDealId)
            .append(",description=").append(description)
            .append(",lastUpdatedId=").append(lastUpdatedId != null ? lastUpdatedId.getId() : null)
            .append(",lastUpdated=").append(lastUpdated)
            .append(",creationDate=").append(creationDate)
            .append(",creationDateUserTz=").append(creationDateUserTz)
            .append(",endDate=").append(endDate)
            .append("}")
            .toString();
        }
   
    }



Service class method



Code:
@Override
       @Target({ ElementType.METHOD, ElementType.TYPE })
       @Retention(RetentionPolicy.RUNTIME)
       @Transactional(readOnly = false, rollbackFor = Exception.class)
       public DealVO addNew(DealVO vo) {
            Deal deal = new Deal();
            vo.setEndDate(new Date());
            deal = convertDealVOToDeal(vo, deal);
            dealDao.save(deal);
            //Some other logic based on creation date
          //setting some other deal properties
          dealDao.save(deal);
            //original logger is removed as it contains sensitive deal info
            vo.setCreationDate(deal.getCreationDate());
            vo.setCreationDateUserTz(deal.getCreationDateUserTz());
            vo.setId(deal.getId());
            return vo;
        }


Dao class methods:

Code:
public Session getSession() {
            return getSessionFactory().getCurrentSession();
        }
       
       @Override
       @Target({ ElementType.METHOD, ElementType.TYPE })
       @Retention(RetentionPolicy.RUNTIME)
       @Transactional(readOnly = false, rollbackFor = Exception.class)
        public void save(T domain) {
            getSession().saveOrUpdate(domain);
        }


Queries generated after control coming out of service method

Code:
insert into DEAL (INT_DEAL_ID, DEAL_DESC, LAST_UPDATED_ID, CREATION_DATE, CREATION_DATE_USER_TZ, END_DATE, SK_DEAL_ID) values (?, ?, ?, ?, ?, ?, ?)
   
    update DEAL set INT_DEAL_ID=?, DEAL_DESC=?, LAST_UPDATED_ID=?, CREATION_DATE=?, CREATION_DATE_USER_TZ=?, END_DATE=? where SK_DEAL_ID=? and LAST_UPDATED=?


Top
 Profile  
 
 Post subject: Re: save and update in same transaction Hibernate, Mariadb,Spri
PostPosted: Thu Sep 08, 2016 10:36 am 
Hibernate Team
Hibernate Team

Joined: Thu Sep 11, 2014 2:50 am
Posts: 1628
Location: Romania
I think it might be related to the @Version property type:

Code:
@Version
@Type(type = "timestamp")
@Column(name = "LAST_UPDATED")
private Date lastUpdated;


Most likely, you are using a MySQLDialect which maps timestamp to datetime.

As you can see from, MariaDB docs, the fraction precision is simply discarded if the type does not specify the fractional second precision: datetime(6).

So, during the same second, two concurrent threads cannot update the same entity because you will get an OptimisticLockingException even if the transaction happen one after the other.

To fix it, you need to use the MySQL57InnoDBDialect, which registers the timestamp type as follows:

Code:
registerColumnType( Types.TIMESTAMP, "datetime(6)" );


Now, you'll get microsecond precision, and this issue should be fixed.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
cron
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.