@@ -0,0 +1,3361 @@
+package com.vladmihalcea.book.hpjp.hibernate.batch;%0A%0Aimport com.vladmihalcea.book.hpjp.util.AbstractTest;%0Aimport com.vladmihalcea.book.hpjp.util.exception.ExceptionUtil;%0Aimport com.vladmihalcea.book.hpjp.util.providers.Database;%0Aimport org.hibernate.StaleStateException;%0Aimport org.junit.Test;%0A%0Aimport javax.persistence.*;%0Aimport java.util.ArrayList;%0Aimport java.util.Iterator;%0Aimport java.util.List;%0Aimport java.util.Properties;%0A%0Aimport static org.junit.Assert.assertTrue;%0A%0A/**%0A * @author Vlad Mihalcea%0A */%0Apublic class BatchingOptimisticLockingTest extends AbstractTest %7B%0A%0A    @Override%0A    protected Class%3C?%3E%5B%5D entities() %7B%0A        return new Class%3C?%3E%5B%5D%7B%0A            Post.class%0A        %7D;%0A    %7D%0A%0A    @Override%0A    protected Database database() %7B%0A        return Database.POSTGRESQL;%0A    %7D%0A%0A    @Override%0A    protected void additionalProperties(Properties properties) %7B%0A        properties.put(%22hibernate.jdbc.batch_size%22, %225%22);%0A        properties.put(%22hibernate.order_inserts%22, %22true%22);%0A        properties.put(%22hibernate.order_updates%22, %22true%22);%0A    %7D%0A%0A    @Test%0A    public void testOptimsticLOcking() %7B%0A        doInJPA(entityManager -%3E %7B%0A            for (int i = 1; i %3C= 3; i++) %7B%0A                entityManager.persist(%0A                    new Post()%0A                        .setTitle(String.format(%22Post no. %25d%22, i))%0A                );%0A            %7D%0A        %7D);%0A%0A        try %7B%0A            doInJPA(entityManager -%3E %7B%0A                List%3CPost%3E posts = entityManager.createQuery(%22%22%22%0A                    select p %0A                    from Post p%0A                    %22%22%22, Post.class)%0A                .getResultList();%0A%0A                posts.forEach(post -%3E post.setTitle(post.getTitle() + %22 - 2nd edition%22));%0A%0A                executeSync(%0A                    () -%3E doInJPA(_entityManager -%3E %7B%0A                        Post post = _entityManager.createQuery(%22%22%22%0A                            select p %0A                            from Post p%0A                            order by p.id%0A                            %22%22%22, Post.class)%0A                        .setMaxResults(1)%0A                        .getSingleResult();%0A%0A                        post.setTitle(post.getTitle() + %22 - corrected%22);%0A                    %7D)%0A                );%0A            %7D);%0A        %7D catch (Exception e) %7B%0A            assertTrue(%0A                ExceptionUtil.rootCause(e).getMessage()%0A                    .startsWith(%0A                        %22Batch update returned unexpected row count from update %5B0%5D; %22 +%0A                        %22actual row count: 0; %22 +%0A                        %22expected: 1; %22 +%0A                        %22statement executed:%22%0A                    )%0A            );%0A        %7D%0A    %7D%0A%0A    @Entity(name = %22Post%22)%0A    @Table(name = %22post%22)%0A    public static class Post %7B%0A%0A        @Id%0A        @GeneratedValue(strategy = GenerationType.SEQUENCE)%0A        private Long id;%0A%0A        private String title;%0A%0A        @Version%0A        private short version;%0A%0A        public Long getId() %7B%0A            return id;%0A        %7D%0A%0A        public Post setId(Long id) %7B%0A            this.id = id;%0A            return this;%0A        %7D%0A%0A        public String getTitle() %7B%0A            return title;%0A        %7D%0A%0A        public Post setTitle(String title) %7B%0A            this.title = title;%0A            return this;%0A        %7D%0A%0A        public short getVersion() %7B%0A            return version;%0A        %7D%0A    %7D%0A%7D%0A

Add test case that shows how the optimistic locking failure occurs when using JDBC batching