package org.hibernate.test.locking;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.Session;
import org.hibernate.dialect.Oracle8iDialect;
import org.hibernate.dialect.PostgreSQL95Dialect;
import org.hibernate.dialect.SQLServer2005Dialect;
import org.hibernate.query.Query;
import org.hibernate.testing.RequiresDialect;
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
import org.junit.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* @author Vlad Mihalcea
*/
public abstract class AbstractSkipLockedTest
extends BaseNonConfigCoreFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] { A.class, BatchJob.class };
}
@Test
@RequiresDialect({ SQLServer2005Dialect.class })
public void testSQLServerSkipLocked() {
doInHibernate( this::sessionFactory, session -> {
for ( long i = 1; i <= 10; i++ ) {
BatchJob batchJob = new BatchJob();
batchJob.setId( i );
session.persist( batchJob );
}
} );
doInHibernate( this::sessionFactory, session -> {
List<BatchJob> firstFive = nextFiveBatchJobs( session );
assertEquals( 5, firstFive.size() );
assertTrue( firstFive.stream().map( BatchJob::getId ).collect( Collectors.toList() )
.containsAll( Arrays.asList( 1L, 2L, 3L, 4L, 5L ) ) );
executeSync( () -> {
doInHibernate( this::sessionFactory, _session -> {
List<BatchJob> nextFive = nextFiveBatchJobs( _session );
assertEquals( 5, nextFive.size() );
assertTrue( nextFive.stream().map( BatchJob::getId ).collect( Collectors.toList() )
.containsAll( Arrays.asList( 6L, 7L, 8L, 9L, 10L ) ) );
} );
} );
} );
}
@Test
@RequiresDialect({ PostgreSQL95Dialect.class })
public void testPostgreSQLSkipLocked() {
doInHibernate( this::sessionFactory, session -> {
for ( long i = 1; i <= 10; i++ ) {
BatchJob batchJob = new BatchJob();
batchJob.setId( i );
session.persist( batchJob );
}
} );
doInHibernate( this::sessionFactory, session -> {
List<BatchJob> firstFive = nextFiveBatchJobs( session );
assertEquals( 5, firstFive.size() );
assertTrue( firstFive.stream().map( BatchJob::getId ).collect( Collectors.toList() )
.containsAll( Arrays.asList( 1L, 2L, 3L, 4L, 5L ) ) );
executeSync( () -> {
doInHibernate( this::sessionFactory, _session -> {
List<BatchJob> nextFive = nextFiveBatchJobs( _session );
assertEquals( 5, nextFive.size() );
if ( lockMode() == LockMode.PESSIMISTIC_READ ) {
assertTrue( nextFive.stream().map( BatchJob::getId ).collect( Collectors.toList() )
.containsAll( Arrays.asList( 1L, 2L, 3L, 4L, 5L ) ) );
}
else {
assertTrue( nextFive.stream().map( BatchJob::getId ).collect( Collectors.toList() )
.containsAll( Arrays.asList( 6L, 7L, 8L, 9L, 10L ) ) );
}
} );
} );
} );
}
@Test
@RequiresDialect({ Oracle8iDialect.class })
public void testOracleSkipLocked() {
doInHibernate( this::sessionFactory, session -> {
for ( long i = 1; i <= 10; i++ ) {
BatchJob batchJob = new BatchJob();
batchJob.setId( i );
session.persist( batchJob );
}
} );
doInHibernate( this::sessionFactory, session -> {
List<BatchJob> firstFive = nextFiveBatchJobs( session );
assertEquals( 5, firstFive.size() );
assertTrue( firstFive.stream().map( BatchJob::getId ).collect( Collectors.toList() )
.containsAll( Arrays.asList( 1L, 2L, 3L, 4L, 5L ) ) );
executeSync( () -> {
doInHibernate( this::sessionFactory, _session -> {
List<BatchJob> nextFive = nextFiveBatchJobs( _session );
assertEquals( 0, nextFive.size() );
nextFive = nextFiveBatchJobs( _session, 10 );
assertTrue( nextFive.stream().map( BatchJob::getId ).collect( Collectors.toList() )
.containsAll( Arrays.asList( 6L, 7L, 8L, 9L, 10L ) ) );
} );
} );
} );
}
private List<BatchJob> nextFiveBatchJobs(Session session) {
return nextFiveBatchJobs( session, 5 );
}
@SuppressWarnings("unchecked")
private List<BatchJob> nextFiveBatchJobs(Session session, Integer maxResult) {
Query query = session.createQuery(
"select j from BatchJob j", BatchJob.class )
.setMaxResults( maxResult )
.unwrap( Query.class );
applySkipLocked(query);
return query.list();
}
protected void applySkipLocked(Query query) {
query.setLockOptions(
new LockOptions( lockMode() )
.setTimeOut( LockOptions.SKIP_LOCKED )
);
}
protected abstract LockMode lockMode();
@Entity(name = "BatchJob")
public static class BatchJob {
@Id
private Long id;
private boolean processed;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public boolean isProcessed() {
return processed;
}
public void setProcessed(boolean processed) {
this.processed = processed;
}
}
}