/* * Hibernate, Relational Persistence for Idiomatic Java * * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. */ package org.hibernate.test.dialect.functional; import java.util.List; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Inheritance; import javax.persistence.InheritanceType; import javax.persistence.LockModeType; import javax.persistence.NamedQuery; import javax.persistence.PersistenceException; import javax.persistence.QueryHint; import org.hibernate.LockMode; import org.hibernate.LockOptions; import org.hibernate.Session; import org.hibernate.annotations.QueryHints; import org.hibernate.boot.SessionFactoryBuilder; import org.hibernate.dialect.Oracle8iDialect; import org.hibernate.exception.SQLGrammarException; import org.hibernate.testing.RequiresDialect; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; import org.hibernate.test.util.jdbc.SQLStatementInterceptor; import org.junit.Before; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; /** * @author Vlad Mihalcea */ @RequiresDialect(value = { Oracle8iDialect.class }) @TestForIssue(jiraKey = "HHH-9486") public class OracleFollowOnLockingTest extends BaseNonConfigCoreFunctionalTestCase { private SQLStatementInterceptor sqlStatementInterceptor; @Override protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) { sqlStatementInterceptor = new SQLStatementInterceptor( sfb ); } @Override protected Class<?>[] getAnnotatedClasses() { return new Class[] { Product.class, Vehicle.class, SportsCar.class, Truck.class }; } @Before public void init() { final Session session = openSession(); session.beginTransaction(); for ( int i = 0; i < 50; i++ ) { Product product = new Product(); product.name = "Product " + i % 10; session.persist( product ); } Truck truck1 = new Truck(); Truck truck2 = new Truck(); SportsCar sportsCar1 = new SportsCar(); session.persist( truck1 ); session.persist( truck2 ); session.persist( sportsCar1 ); session.getTransaction().commit(); session.close(); } @Override protected boolean isCleanupTestDataRequired() { return true; } @Test public void testPessimisticLockWithMaxResultsThenNoFollowOnLocking() { final Session session = openSession(); session.beginTransaction(); sqlStatementInterceptor.getSqlQueries().clear(); List<Product> products = session.createQuery( "select p from Product p", Product.class ) .setLockOptions( new LockOptions( LockMode.PESSIMISTIC_WRITE ) ) .setMaxResults( 10 ) .getResultList(); assertEquals( 10, products.size() ); assertEquals( 1, sqlStatementInterceptor.getSqlQueries().size() ); session.getTransaction().commit(); session.close(); } @Test public void testPessimisticLockWithFirstResultsThenFollowOnLocking() { final Session session = openSession(); session.beginTransaction(); sqlStatementInterceptor.getSqlQueries().clear(); List<Product> products = session.createQuery( "select p from Product p", Product.class ) .setLockOptions( new LockOptions( LockMode.PESSIMISTIC_WRITE ) ) .setFirstResult( 40 ) .setMaxResults( 10 ) .getResultList(); assertEquals( 10, products.size() ); assertEquals( 11, sqlStatementInterceptor.getSqlQueries().size() ); session.getTransaction().commit(); session.close(); } @Test public void testPessimisticLockWithNamedQueryExplicitlyEnablingFollowOnLockingThenFollowOnLocking() { final Session session = openSession(); session.beginTransaction(); sqlStatementInterceptor.getSqlQueries().clear(); List<Product> products = session.createNamedQuery( "product_by_name", Product.class ) .getResultList(); assertEquals( 50, products.size() ); assertEquals( 51, sqlStatementInterceptor.getSqlQueries().size() ); session.getTransaction().commit(); session.close(); } @Test public void testPessimisticLockWithCountDistinctThenFollowOnLocking() { final Session session = openSession(); session.beginTransaction(); sqlStatementInterceptor.getSqlQueries().clear(); List<Product> products = session.createQuery( "select p from Product p where ( select count(distinct p1.id) from Product p1 ) > 0 ", Product.class ) .setLockOptions( new LockOptions( LockMode.PESSIMISTIC_WRITE ).setFollowOnLocking( false ) ) .getResultList(); assertEquals( 50, products.size() ); assertEquals( 1, sqlStatementInterceptor.getSqlQueries().size() ); session.getTransaction().commit(); session.close(); } @Test public void testPessimisticLockWithFirstResultsWhileExplicitlyDisablingFollowOnLockingThenFails() { final Session session = openSession(); session.beginTransaction(); sqlStatementInterceptor.getSqlQueries().clear(); try { List<Product> products = session.createQuery( "select p from Product p", Product.class ) .setLockOptions( new LockOptions( LockMode.PESSIMISTIC_WRITE ) .setFollowOnLocking( false ) ) .setFirstResult( 40 ) .setMaxResults( 10 ) .getResultList(); fail( "Should throw exception since Oracle does not support ORDER BY if follow on locking is disabled" ); } catch ( PersistenceException expected ) { assertEquals( SQLGrammarException.class, expected.getCause().getClass() ); } } @Test public void testPessimisticLockWithFirstResultsWhileExplicitlyEnablingFollowOnLockingThenFollowOnLocking() { final Session session = openSession(); session.beginTransaction(); sqlStatementInterceptor.getSqlQueries().clear(); List<Product> products = session.createQuery( "select p from Product p", Product.class ) .setLockOptions( new LockOptions( LockMode.PESSIMISTIC_WRITE ) .setFollowOnLocking( true ) ) .setFirstResult( 40 ) .setMaxResults( 10 ) .getResultList(); assertEquals( 10, products.size() ); assertEquals( 11, sqlStatementInterceptor.getSqlQueries().size() ); session.getTransaction().commit(); session.close(); } @Test public void testPessimisticLockWithMaxResultsAndOrderByThenFollowOnLocking() { final Session session = openSession(); session.beginTransaction(); sqlStatementInterceptor.getSqlQueries().clear(); List<Product> products = session.createQuery( "select p from Product p order by p.id", Product.class ) .setLockOptions( new LockOptions( LockMode.PESSIMISTIC_WRITE ) ) .setMaxResults( 10 ) .getResultList(); assertEquals( 10, products.size() ); assertEquals( 11, sqlStatementInterceptor.getSqlQueries().size() ); session.getTransaction().commit(); session.close(); } @Test public void testPessimisticLockWithMaxResultsAndOrderByWhileExplicitlyDisablingFollowOnLockingThenFails() { final Session session = openSession(); session.beginTransaction(); sqlStatementInterceptor.getSqlQueries().clear(); try { List<Product> products = session.createQuery( "select p from Product p order by p.id", Product.class ) .setLockOptions( new LockOptions( LockMode.PESSIMISTIC_WRITE ) .setFollowOnLocking( false ) ) .setMaxResults( 10 ) .getResultList(); fail( "Should throw exception since Oracle does not support ORDER BY if follow on locking is disabled" ); } catch ( PersistenceException expected ) { assertEquals( SQLGrammarException.class, expected.getCause().getClass() ); } } @Test public void testPessimisticLockWithMaxResultsAndOrderByWhileExplicitlyEnablingFollowOnLockingThenFollowOnLocking() { final Session session = openSession(); session.beginTransaction(); sqlStatementInterceptor.getSqlQueries().clear(); List<Product> products = session.createQuery( "select p from Product p order by p.id", Product.class ) .setLockOptions( new LockOptions( LockMode.PESSIMISTIC_WRITE ) .setFollowOnLocking( true ) ) .setMaxResults( 10 ) .getResultList(); assertEquals( 10, products.size() ); assertEquals( 11, sqlStatementInterceptor.getSqlQueries().size() ); session.getTransaction().commit(); session.close(); } @Test public void testPessimisticLockWithDistinctThenFollowOnLocking() { final Session session = openSession(); session.beginTransaction(); sqlStatementInterceptor.getSqlQueries().clear(); List<Product> products = session.createQuery( "select distinct p from Product p", Product.class ) .setLockOptions( new LockOptions( LockMode.PESSIMISTIC_WRITE ) ) .getResultList(); assertEquals( 50, products.size() ); assertEquals( 51, sqlStatementInterceptor.getSqlQueries().size() ); session.getTransaction().commit(); session.close(); } @Test public void testPessimisticLockWithDistinctWhileExplicitlyDisablingFollowOnLockingThenFails() { final Session session = openSession(); session.beginTransaction(); sqlStatementInterceptor.getSqlQueries().clear(); try { List<Product> products = session.createQuery( "select distinct p from Product p where p.id > 40", Product.class ) .setLockOptions( new LockOptions( LockMode.PESSIMISTIC_WRITE ) .setFollowOnLocking( false ) ) .getResultList(); fail( "Should throw exception since Oracle does not support DISTINCT if follow on locking is disabled" ); } catch ( PersistenceException expected ) { assertEquals( SQLGrammarException.class, expected.getCause().getClass() ); } } @Test public void testPessimisticLockWithDistinctWhileExplicitlyEnablingFollowOnLockingThenFollowOnLocking() { final Session session = openSession(); session.beginTransaction(); sqlStatementInterceptor.getSqlQueries().clear(); List<Product> products = session.createQuery( "select distinct p from Product p where p.id > 40" ) .setLockOptions( new LockOptions( LockMode.PESSIMISTIC_WRITE ) .setFollowOnLocking( true ) ) .setMaxResults( 10 ) .getResultList(); assertEquals( 10, products.size() ); assertEquals( 11, sqlStatementInterceptor.getSqlQueries().size() ); session.getTransaction().commit(); session.close(); } @Test public void testPessimisticLockWithGroupByThenFollowOnLocking() { final Session session = openSession(); session.beginTransaction(); sqlStatementInterceptor.getSqlQueries().clear(); List<Object[]> products = session.createQuery( "select count(p), p " + "from Product p " + "group by p.id, p.name " ) .setLockOptions( new LockOptions( LockMode.PESSIMISTIC_WRITE ) ) .getResultList(); assertEquals( 50, products.size() ); assertEquals( 51, sqlStatementInterceptor.getSqlQueries().size() ); session.getTransaction().commit(); session.close(); } @Test public void testPessimisticLockWithGroupByWhileExplicitlyDisablingFollowOnLockingThenFails() { final Session session = openSession(); session.beginTransaction(); sqlStatementInterceptor.getSqlQueries().clear(); try { List<Object[]> products = session.createQuery( "select count(p), p " + "from Product p " + "group by p.id, p.name " ) .setLockOptions( new LockOptions( LockMode.PESSIMISTIC_WRITE ) .setFollowOnLocking( false ) ) .getResultList(); fail( "Should throw exception since Oracle does not support GROUP BY if follow on locking is disabled" ); } catch ( PersistenceException expected ) { assertEquals( SQLGrammarException.class, expected.getCause().getClass() ); } } @Test public void testPessimisticLockWithGroupByWhileExplicitlyEnablingFollowOnLockingThenFollowOnLocking() { final Session session = openSession(); session.beginTransaction(); sqlStatementInterceptor.getSqlQueries().clear(); List<Object[]> products = session.createQuery( "select count(p), p " + "from Product p " + "group by p.id, p.name " ) .setLockOptions( new LockOptions( LockMode.PESSIMISTIC_WRITE ) .setFollowOnLocking( true ) ) .getResultList(); assertEquals( 50, products.size() ); assertEquals( 51, sqlStatementInterceptor.getSqlQueries().size() ); session.getTransaction().commit(); session.close(); } @Test public void testPessimisticLockWithUnionThenFollowOnLocking() { final Session session = openSession(); session.beginTransaction(); sqlStatementInterceptor.getSqlQueries().clear(); List<Vehicle> vehicles = session.createQuery( "select v from Vehicle v" ) .setLockOptions( new LockOptions( LockMode.PESSIMISTIC_WRITE ) ) .getResultList(); assertEquals( 3, vehicles.size() ); assertEquals( 4, sqlStatementInterceptor.getSqlQueries().size() ); session.getTransaction().commit(); session.close(); } @Test public void testPessimisticLockWithUnionWhileExplicitlyDisablingFollowOnLockingThenFails() { final Session session = openSession(); session.beginTransaction(); sqlStatementInterceptor.getSqlQueries().clear(); try { List<Vehicle> vehicles = session.createQuery( "select v from Vehicle v" ) .setLockOptions( new LockOptions( LockMode.PESSIMISTIC_WRITE ).setFollowOnLocking( false ) ) .getResultList(); fail( "Should throw exception since Oracle does not support UNION if follow on locking is disabled" ); } catch ( PersistenceException expected ) { assertEquals( SQLGrammarException.class, expected.getCause().getClass() ); } } @NamedQuery( name = "product_by_name", query = "select p from Product p where p.name is not null", lockMode = LockModeType.PESSIMISTIC_WRITE, hints = @QueryHint(name = QueryHints.FOLLOW_ON_LOCKING, value = "true") ) @Entity(name = "Product") public static class Product { @Id @GeneratedValue private Long id; private String name; } @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) @Entity(name = "Vehicle") public static class Vehicle { @Id @GeneratedValue private Long id; private String name; } @Entity(name = "SportsCar") public static class SportsCar extends Vehicle { private double speed; } @Entity(name = "Truck") public static class Truck extends Vehicle { private double torque; } }