/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.test.optlock;
import org.hibernate.JDBCException;
import org.hibernate.Session;
import org.hibernate.StaleObjectStateException;
import org.hibernate.StaleStateException;
import org.hibernate.dialect.SQLServerDialect;
import org.junit.Test;
import org.hibernate.testing.DialectChecks;
import org.hibernate.testing.RequiresDialectFeature;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import static org.junit.Assert.fail;
/**
* Tests relating to the optimistic-lock mapping option.
*
* @author Gavin King
* @author Steve Ebersole
*/
@RequiresDialectFeature(
value = DialectChecks.DoesRepeatableReadNotCauseReadersToBlockWritersCheck.class,
comment = "potential deadlock"
)
public class OptimisticLockTest extends BaseCoreFunctionalTestCase {
@Override
public String[] getMappings() {
return new String[] { "optlock/Document.hbm.xml" };
}
@Test
public void testOptimisticLockDirty() {
testUpdateOptimisticLockFailure( "LockDirty" );
}
@Test
public void testOptimisticLockAll() {
testUpdateOptimisticLockFailure( "LockAll" );
}
@Test
public void testOptimisticLockDirtyDelete() {
testDeleteOptimisticLockFailure( "LockDirty" );
}
@Test
public void testOptimisticLockAllDelete() {
testDeleteOptimisticLockFailure( "LockAll" );
}
private void testUpdateOptimisticLockFailure(String entityName) {
Session mainSession = openSession();
mainSession.beginTransaction();
Document doc = new Document();
doc.setTitle( "Hibernate in Action" );
doc.setAuthor( "Bauer et al" );
doc.setSummary( "Very boring book about persistence" );
doc.setText( "blah blah yada yada yada" );
doc.setPubDate( new PublicationDate( 2004 ) );
mainSession.save( entityName, doc );
mainSession.getTransaction().commit();
mainSession.close();
mainSession = openSession();
mainSession.beginTransaction();
doc = ( Document ) mainSession.get( entityName, doc.getId() );
Session otherSession = sessionFactory().openSession();
otherSession.beginTransaction();
Document otherDoc = ( Document ) otherSession.get( entityName, doc.getId() );
otherDoc.setSummary( "A modern classic" );
otherSession.getTransaction().commit();
otherSession.close();
try {
doc.setSummary( "A machiavellian achievement of epic proportions" );
mainSession.flush();
fail( "expecting opt lock failure" );
}
catch ( StaleObjectStateException expected ) {
// expected result...
}
catch( StaleStateException expected ) {
// expected result (if using versioned batching)...
}
catch( JDBCException e ) {
// SQLServer will report this condition via a SQLException
// when using its SNAPSHOT transaction isolation...
if ( ! ( getDialect() instanceof SQLServerDialect && e.getErrorCode() == 3960 ) ) {
throw e;
}
else {
// it seems to "lose track" of the transaction as well...
mainSession.getTransaction().rollback();
mainSession.beginTransaction();
}
}
mainSession.clear();
mainSession.getTransaction().commit();
mainSession.close();
mainSession = openSession();
mainSession.beginTransaction();
doc = ( Document ) mainSession.load( entityName, doc.getId() );
mainSession.delete( entityName, doc );
mainSession.getTransaction().commit();
mainSession.close();
}
@SuppressWarnings({ "UnnecessaryBoxing" })
private void testDeleteOptimisticLockFailure(String entityName) {
Session mainSession = openSession();
mainSession.beginTransaction();
Document doc = new Document();
doc.setTitle( "Hibernate in Action" );
doc.setAuthor( "Bauer et al" );
doc.setSummary( "Very boring book about persistence" );
doc.setText( "blah blah yada yada yada" );
doc.setPubDate( new PublicationDate( 2004 ) );
mainSession.save( entityName, doc );
mainSession.flush();
doc.setSummary( "A modern classic" );
mainSession.flush();
doc.getPubDate().setMonth( Integer.valueOf( 3 ) );
mainSession.flush();
mainSession.getTransaction().commit();
mainSession.close();
mainSession = openSession();
mainSession.beginTransaction();
doc = ( Document ) mainSession.get( entityName, doc.getId() );
Session otherSession = openSession();
otherSession.beginTransaction();
Document otherDoc = ( Document ) otherSession.get( entityName, doc.getId() );
otherDoc.setSummary( "my other summary" );
otherSession.flush();
otherSession.getTransaction().commit();
otherSession.close();
try {
mainSession.delete( doc );
mainSession.flush();
fail( "expecting opt lock failure" );
}
catch ( StaleObjectStateException e ) {
// expected
}
catch( StaleStateException expected ) {
// expected result (if using versioned batching)...
}
catch( JDBCException e ) {
// SQLServer will report this condition via a SQLException
// when using its SNAPSHOT transaction isolation...
if ( ! ( getDialect() instanceof SQLServerDialect && e.getErrorCode() == 3960 ) ) {
throw e;
}
else {
// it seems to "lose track" of the transaction as well...
mainSession.getTransaction().rollback();
mainSession.beginTransaction();
}
}
mainSession.clear();
mainSession.getTransaction().commit();
mainSession.close();
mainSession = openSession();
mainSession.beginTransaction();
doc = ( Document ) mainSession.load( entityName, doc.getId() );
mainSession.delete( entityName, doc );
mainSession.getTransaction().commit();
mainSession.close();
}
}