1
votes

I am using JPA, Hibernate, Spring and MySQL

I tried to save a person with an order. But only the person would appear in the database. Trying to fix this I added cascade = CascadeType.ALL to @OneToMany Resulting into this error

Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1

Database script

CREATE TABLE IF NOT EXISTS `orders` (
  `O_Id` int(11) NOT NULL,
  `OrderNo` int(11) NOT NULL,
  `P_Id` int(11) DEFAULT NULL
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=latin1;

CREATE TABLE IF NOT EXISTS `persons` (
  `P_Id` int(11) NOT NULL,
  `LastName` varchar(255) NOT NULL,
  `FirstName` varchar(255) DEFAULT NULL,
  `Address` varchar(255) DEFAULT NULL,
  `City` varchar(255) DEFAULT NULL
) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=latin1;

ALTER TABLE `orders`
  ADD PRIMARY KEY (`O_Id`),
  ADD KEY `P_Id` (`P_Id`);

ALTER TABLE `persons`
  ADD PRIMARY KEY (`P_Id`);

ALTER TABLE `orders`
  ADD CONSTRAINT `orders_ibfk_1` FOREIGN KEY (`P_Id`) REFERENCES `persons` (`P_Id`);

Order and person entity

@Entity
@Table(name = "orders", catalog = "db1", schema = "")
@XmlRootElement
@NamedQueries({
    @NamedQuery(name = "Orders.findAll", query = "SELECT o FROM Orders o"),
    @NamedQuery(name = "Orders.findByOId", query = "SELECT o FROM Orders o WHERE o.oId = :oId"),
    @NamedQuery(name = "Orders.findByOrderNo", query = "SELECT o FROM Orders o WHERE o.orderNo = :orderNo")})
public class Orders implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "O_Id")
    private Integer oId;
    @Basic(optional = false)
    @NotNull
    @Column(name = "OrderNo")
    private int orderNo;
    @JoinColumn(name = "P_Id", referencedColumnName = "P_Id")
    @ManyToOne
    private Persons pId;

    public Orders() {
    }

    public Orders(Integer oId) {
        this.oId = oId;
    }

    public Orders(Integer oId, int orderNo) {
        this.oId = oId;
        this.orderNo = orderNo;
    }

    public Integer getOId() {
        return oId;
    }

    public void setOId(Integer oId) {
        this.oId = oId;
    }

    public int getOrderNo() {
        return orderNo;
    }

    public void setOrderNo(int orderNo) {
        this.orderNo = orderNo;
    }

    public Persons getPId() {
        return pId;
    }

    public void setPId(Persons pId) {
        this.pId = pId;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (oId != null ? oId.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Orders)) {
            return false;
        }
        Orders other = (Orders) object;
        if ((this.oId == null && other.oId != null) || (this.oId != null && !this.oId.equals(other.oId))) {
            return false;
        }
        return true;
    }       
}




 @Entity
    @Table(name = "persons", catalog = "db1", schema = "")
    @XmlRootElement
    @NamedQueries({
        @NamedQuery(name = "Persons.findAll", query = "SELECT p FROM Persons p"),
        @NamedQuery(name = "Persons.findByPId", query = "SELECT p FROM Persons p WHERE p.pId = :pId"),
        @NamedQuery(name = "Persons.findByLastName", query = "SELECT p FROM Persons p WHERE p.lastName = :lastName"),
        @NamedQuery(name = "Persons.findByFirstName", query = "SELECT p FROM Persons p WHERE p.firstName = :firstName"),
        @NamedQuery(name = "Persons.findByAddress", query = "SELECT p FROM Persons p WHERE p.address = :address"),
        @NamedQuery(name = "Persons.findByCity", query = "SELECT p FROM Persons p WHERE p.city = :city")})
@Component("aPerson") // I do not how else to get it 
    public class Persons implements Serializable {

        private static final long serialVersionUID = 1L;
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Basic(optional = false)
        @Column(name = "P_Id")
        private Integer pId;
        @Basic(optional = false)
        @NotNull
        @Size(min = 1, max = 255)
        @Column(name = "LastName")
        private String lastName;
        @Size(max = 255)
        @Column(name = "FirstName")
        private String firstName;
        @Size(max = 255)
        @Column(name = "Address")
        private String address;
        @Size(max = 255)
        @Column(name = "City")
        private String city;
        @OneToMany(mappedBy = "pId", cascade = CascadeType.ALL)
        private Collection<Orders> ordersCollection;

        @Autowired
        @Transient
        SessionFactory sessionFactory;

        @Transactional
        public void add(Persons person) {
            sessionFactory.getCurrentSession().saveOrUpdate(person);
        }

        public Persons() {
        }

        public Persons(Integer pId) {
            this.pId = pId;
        }

        public Persons(Integer pId, String lastName) {
            this.pId = pId;
            this.lastName = lastName;
        }

        public Integer getPId() {
            return pId;
        }

        public void setPId(Integer pId) {
            this.pId = pId;
        }

        public String getLastName() {
            return lastName;
        }

        public void setLastName(String lastName) {
            this.lastName = lastName;
        }

        public String getFirstName() {
            return firstName;
        }

        public void setFirstName(String firstName) {
            this.firstName = firstName;
        }

        public String getAddress() {
            return address;
        }

        public void setAddress(String address) {
            this.address = address;
        }

        public String getCity() {
            return city;
        }

        public void setCity(String city) {
            this.city = city;
        }

        @XmlTransient
        public Collection<Orders> getOrdersCollection() {
            return ordersCollection;
        }

        public void setOrdersCollection(Collection<Orders> ordersCollection) {
            this.ordersCollection = ordersCollection;
        }

        @Override
        public int hashCode() {
            int hash = 0;
            hash += (pId != null ? pId.hashCode() : 0);
            return hash;
        }

        @Override
        public boolean equals(Object object) {
            // TODO: Warning - this method won't work in the case the id fields are not set
            if (!(object instanceof Persons)) {
                return false;
            }
            Persons other = (Persons) object;
            if ((this.pId == null && other.pId != null) || (this.pId != null && !this.pId.equals(other.pId))) {
                return false;
            }
            return true;
        }

    }

How I try to save the objects.

       @Controller
public class HelloController {

    @Autowired
    SessionFactory sessionFactory;

    @Autowired
    private ApplicationContext applicationContext;



    @RequestMapping("hi")
    @ResponseBody
  //  @Transactional
    public String hi() {

        Persons personContext = (Persons) applicationContext.getBean("aPerson");

        Persons person = new Persons();

        person.setFirstName("jan");
        person.setAddress("jan");
        person.setCity("Eindhoven");
        person.setLastName("jansen");

        Orders order = new Orders(12, 12);

        Collection<Orders> orderses = new HashSet<Orders>();
        orderses.add(order);
        order.setPId(person);
        person.setOrdersCollection(orderses);

        //sessionFactory.getCurrentSession().persist(person);
       // sessionFactory.getCurrentSession().saveOrUpdate(person);


        personContext.add(person);

        return "ok";
    }
}

Stack trace

type Exception report

message Request processing failed; nested exception is 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

description The server encountered an internal error that prevented it from fulfilling this request.

exception

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is 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
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:978)
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:857)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:618)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:393)
root cause

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
    org.springframework.orm.hibernate4.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:205)
    org.springframework.orm.hibernate4.HibernateTransactionManager.convertHibernateAccessException(HibernateTransactionManager.java:730)
    org.springframework.orm.hibernate4.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:592)
    org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:757)
    org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:726)
    org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:521)
    org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:291)
    org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
    org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653)
    com.springcookbook.dao.Persons$$EnhancerBySpringCGLIB$$4ce50ac7.add(<generated>)
    com.springcookbook.controller.HelloController.hi(HelloController.java:68)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    java.lang.reflect.Method.invoke(Method.java:497)
    org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
    org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
    org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:777)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:706)
    org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:857)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:618)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:393)
root cause

org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
    org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:81)
    org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:73)
    org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:63)
    org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3281)
    org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:3183)
    org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3525)
    org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:159)
    org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:465)
    org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:351)
    org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:350)
    org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:56)
    org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1222)
    org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:425)
    org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
    org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:177)
    org.springframework.orm.hibernate4.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:584)
    org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:757)
    org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:726)
    org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:521)
    org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:291)
    org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
    org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653)
    com.springcookbook.dao.Persons$$EnhancerBySpringCGLIB$$4ce50ac7.add(<generated>)
    com.springcookbook.controller.HelloController.hi(HelloController.java:68)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    java.lang.reflect.Method.invoke(Method.java:497)
    org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
    org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
    org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:777)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:706)
    org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:857)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:618)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:393)
1
can you try sessionFactory.getCurrentSession().persist().. - Jos
I don't know it is any better error: Could not obtain transaction-synchronized Session for current thread - Davidto

1 Answers

1
votes

You're never setting the order's person, and it can't be null since you have a not null constraint on p_id.

Also, irrelevant, but annotating entities with @Component and @Transactional makes no sense at all. You should remove those annotations.

EDIT:

the additional problem is that you're creating an order with an assigned ID (12), although you told Hibernate that the ID is supposed to be automatically generated. Consequence, when "saving or updating" the order, Hibernate must decide if it must save it, or update it. How does it do that? By checking if the entity already has an ID or not. Since it has one (12), it decides to update, and not to save. And that fails, since there is no order with ID 12 in the database.