@@ -0,0 +1,2875 @@
+package com.vladmihalcea.book.hpjp.hibernate.concurrency.upsert;%0A%0Aimport com.vladmihalcea.book.hpjp.util.AbstractSQLServerIntegrationTest;%0Aimport org.hibernate.annotations.NaturalId;%0Aimport org.junit.Test;%0A%0Aimport javax.persistence.Entity;%0Aimport javax.persistence.Id;%0Aimport javax.persistence.LockModeType;%0Aimport javax.persistence.Table;%0Aimport java.util.concurrent.CountDownLatch;%0A%0A/**%0A * @author Vlad Mihalcea%0A */%0Apublic class SQLServerUpsertAlternativeTest extends AbstractSQLServerIntegrationTest %7B%0A%0A    @Override%0A    protected Class%3C?%3E%5B%5D entities() %7B%0A        return new Class%3C?%3E%5B%5D%7B%0A            Book.class%0A        %7D;%0A    %7D%0A%0A    @Test%0A    public void testUpsertWithInsertAndUpdateLock() %7B%0A        CountDownLatch aliceCountDownLatch = new CountDownLatch(1);%0A%0A        doInJPA(entityManager -%3E %7B%0A            Book book = new Book();%0A            book.setId(1L);%0A            book.setTitle(%22Book 1%22);%0A%0A            entityManager.persist(book);%0A            entityManager.flush();%0A%0A            executeAsync(() -%3E %7B%0A                doInJPA(_entityManager -%3E %7B%0A                    try %7B%0A                        LOGGER.info(%22Bob tries to lock the record%22);%0A                        Book _book = _entityManager.find(Book.class, 1L, LockModeType.PESSIMISTIC_READ);%0A                        if (_book == null) %7B%0A                            LOGGER.info(%22Bob inserts%22);%0A                            _book = new Book();%0A                            _book.setId(1L);%0A                            _book.setTitle(%22Book 2%22);%0A                            _entityManager.persist(_book);%0A                        %7D else %7B%0A                            LOGGER.info(%22Bob updates%22);%0A                            _book.setTitle(%22Book 2%22);%0A                        %7D%0A                    %7D catch (Exception e) %7B%0A                        e.printStackTrace();%0A                    %7D finally %7B%0A                        aliceCountDownLatch.countDown();%0A                    %7D%0A                %7D);%0A            %7D);%0A%0A            LOGGER.info(%22Alice starts sleeping%22);%0A            sleep(5000);%0A            LOGGER.info(%22Alice woke up and releases the logs after she commits%22);%0A        %7D);%0A%0A        LOGGER.info(%22%22);%0A        awaitOnLatch(aliceCountDownLatch);%0A    %7D%0A%0A%0A    @Entity(name = %22Book%22)%0A    @Table(name = %22book%22)%0A    public static class Book %7B%0A%0A        @Id%0A        private Long id;%0A%0A        @NaturalId%0A        private String isbn;%0A%0A        private String title;%0A%0A        public Long getId() %7B%0A            return id;%0A        %7D%0A%0A        public void setId(Long id) %7B%0A            this.id = id;%0A        %7D%0A%0A        public String getIsbn() %7B%0A            return isbn;%0A        %7D%0A%0A        public void setIsbn(String isbn) %7B%0A            this.isbn = isbn;%0A        %7D%0A%0A        public String getTitle() %7B%0A            return title;%0A        %7D%0A%0A        public void setTitle(String title) %7B%0A            this.title = title;%0A        %7D%0A    %7D%0A%7D%0A

Add SQL Server UPSERT alternative using locks