下面列出了org.hibernate.Session#lock ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
public void testLockingJoinedSubclass() {
Session s = openSession();
Transaction t = s.beginTransaction();
Person p = new Person();
p.setName("Emmanuel");
p.setSex('M');
s.persist(p);
Employee q = new Employee();
q.setName("Steve");
q.setSex('M');
q.setTitle("Mr");
q.setSalary( new BigDecimal(1000) );
s.persist(q);
t.commit();
s.close();
s = openSession();
t = s.beginTransaction();
s.lock( p, LockMode.UPGRADE );
s.lock( q, LockMode.UPGRADE );
s.delete( p );
s.delete( q );
t.commit();
s.close();
}
/**
* This returns the internal id. Do not confuse this with the pageId.
* @return Returns the internal id.
*/
/*
* Note well:
* Access is limited to package-private here intentionally, as the database ID is considered framework-internal use.
*/
long __getId() {
Session session = this.wiki.__getHibernateSession();
session.beginTransaction();
session.lock(hibernateCategory, LockMode.NONE);
long id = hibernateCategory.getId();
session.getTransaction().commit();
return id;
}
/**
* @return A unique page id.
*/
public int getPageId() {
Session session = this.wiki.__getHibernateSession();
session.beginTransaction();
session.lock(hibernateCategory, LockMode.NONE);
int pageID = hibernateCategory.getPageId();
session.getTransaction().commit();
return pageID;
}
/**
* @return A set containing parents (supercategories) of this category.
*/
public Set<Category> getParents() {
Session session = this.wiki.__getHibernateSession();
session.beginTransaction();
session.lock(hibernateCategory, LockMode.NONE);
Set<Integer> tmpSet = new HashSet<Integer>(hibernateCategory.getInLinks());
session.getTransaction().commit();
Set<Category> categories = new HashSet<Category>();
for (int pageID : tmpSet) {
categories.add(this.wiki.getCategory(pageID));
}
return categories;
}
/**
* @return A set containing the children (subcategories) of this category.
*/
public Set<Category> getChildren() {
Session session = this.wiki.__getHibernateSession();
session.beginTransaction();
session.lock(hibernateCategory, LockMode.NONE);
Set<Integer> tmpSet = new HashSet<Integer>(hibernateCategory.getOutLinks());
session.getTransaction().commit();
Set<Category> categories = new HashSet<Category>();
for (int pageID : tmpSet) {
categories.add(this.wiki.getCategory(pageID));
}
return categories;
}
/**
* Demonstrates transitive persistence with detached object support
*/
public void bidOnAuction(User bidder, AuctionItem item, float amount) throws Exception {
System.out.println("Creating a new bid for auction item: " + item.getId() + " by user: " + bidder.getId() );
Session s = factory.openSession();
Transaction tx=null;
try {
tx = s.beginTransaction();
s.lock(item, LockMode.NONE);
s.lock(bidder, LockMode.NONE);
Bid bid = new Bid();
bid.setBidder(bidder);
bid.setDatetime( new Date() );
bid.setAmount(amount);
bid.setItem(item);
bidder.getBids().add(bid);
item.getBids().add(bid);
tx.commit();
}
catch (Exception e) {
if (tx!=null) tx.rollback();
throw e;
}
finally {
s.close();
}
}
/**
* @return The title of the category.
* @throws WikiTitleParsingException
*/
public Title getTitle() throws WikiTitleParsingException {
Session session = this.wiki.__getHibernateSession();
session.beginTransaction();
session.lock(hibernateCategory, LockMode.NONE);
String name = hibernateCategory.getName();
session.getTransaction().commit();
Title title = new Title(name);
return title;
}
/**
* @return The set of article ids that are categorized under this category.
*/
public Set<Integer> getArticleIds() {
Session session = this.wiki.__getHibernateSession();
session.beginTransaction();
session.lock(hibernateCategory, LockMode.NONE);
Set<Integer> tmpSet = new HashSet<Integer>(hibernateCategory.getPages());
session.getTransaction().commit();
return tmpSet;
}
/**
* @return The id of the {@link MetaData} object.
*/
/*
* Note well:
* Access is limited to package-private here intentionally, as the database ID is considered framework-internal use.
*/
long getId()
{
Session session = this.wiki.__getHibernateSession();
session.beginTransaction();
session.lock(hibernateMetaData, LockMode.NONE);
long id = hibernateMetaData.getId();
session.getTransaction().commit();
return id;
}
/**
* @return The number of pages in the current Wikipedia.
*/
public long getNumberOfPages()
{
Session session = this.wiki.__getHibernateSession();
session.beginTransaction();
session.lock(hibernateMetaData, LockMode.NONE);
long nrofPages = hibernateMetaData.getNrofPages();
session.getTransaction().commit();
return nrofPages;
}
/**
* @return The number of disambiguation pages in the current Wikipedia.
*/
public long getNumberOfDisambiguationPages()
{
Session session = this.wiki.__getHibernateSession();
session.beginTransaction();
session.lock(hibernateMetaData, LockMode.NONE);
long nrofDisambPages = hibernateMetaData.getNrofDisambiguationPages();
session.getTransaction().commit();
return nrofDisambPages;
}
/**
* @return The number of redirects in the current Wikipedia.
*/
public long getNumberOfRedirectPages()
{
Session session = this.wiki.__getHibernateSession();
session.beginTransaction();
session.lock(hibernateMetaData, LockMode.NONE);
long nrofRedirects = hibernateMetaData.getNrofRedirects();
session.getTransaction().commit();
return nrofRedirects;
}
/**
* @return The disambiguation {@link Category}.
* @throws WikiApiException Thrown if errors occurred fetching the information.
*/
public Category getDisambiguationCategory() throws WikiApiException
{
Session session = this.wiki.__getHibernateSession();
session.beginTransaction();
session.lock(hibernateMetaData, LockMode.NONE);
String disambCategoryTitle = hibernateMetaData.getDisambiguationCategory();
session.getTransaction().commit();
return wiki.getCategory(disambCategoryTitle);
}
/**
* @return The name of the main/root {@link Category}.
* @throws WikiApiException Thrown if errors occurred fetching the information.
*/
public Category getMainCategory() throws WikiApiException
{
Session session = this.wiki.__getHibernateSession();
session.beginTransaction();
session.lock(hibernateMetaData, LockMode.NONE);
String mainCategoryTitle = hibernateMetaData.getMainCategory();
session.getTransaction().commit();
return wiki.getCategory(mainCategoryTitle);
}
/**
* @return The version of the wikipedia data.
* @throws WikiApiException Thrown if errors occurred fetching the information.
*/
public String getVersion() throws WikiApiException
{
Session session = this.wiki.__getHibernateSession();
session.beginTransaction();
session.lock(hibernateMetaData, LockMode.NONE);
String version = hibernateMetaData.getVersion();
session.getTransaction().commit();
return version;
}
public void testOrphanDeleteAfterLock() {
Session session = openSession();
Transaction t = session.beginTransaction();
Product prod = new Product();
prod.setName("Widget");
Part part = new Part();
part.setName("Widge");
part.setDescription("part if a Widget");
prod.getParts().add(part);
Part part2 = new Part();
part2.setName("Get");
part2.setDescription("another part if a Widget");
prod.getParts().add(part2);
session.persist(prod);
t.commit();
session.close();
session = openSession();
t = session.beginTransaction();
session.lock(prod, LockMode.READ);
prod.getParts().remove(part);
t.commit();
session.close();
session = openSession();
t = session.beginTransaction();
assertNull( session.get(Part.class, "Widge") );
assertNotNull( session.get(Part.class, "Get") );
session.delete( session.get(Product.class, "Widget") );
t.commit();
session.close();
}
/**
* Test the equivalent of EJB3 LockModeType.READ
* <p/>
* From the spec:
* <p/>
* If transaction T1 calls lock(entity, LockModeType.READ) on a versioned object, the entity
* manager must ensure that neither of the following phenomena can occur:<ul>
* <li>P1 (Dirty read): Transaction T1 modifies a row. Another transaction T2 then reads that row and
* obtains the modified value, before T1 has committed or rolled back. Transaction T2 eventually
* commits successfully; it does not matter whether T1 commits or rolls back and whether it does
* so before or after T2 commits.
* <li>P2 (Non-repeatable read): Transaction T1 reads a row. Another transaction T2 then modifies or
* deletes that row, before T1 has committed. Both transactions eventually commit successfully.
* <p/>
* This will generally be achieved by the entity manager acquiring a lock on the underlying database row.
* Any such lock may be obtained immediately (so long as it is retained until commit completes), or the
* lock may be deferred until commit time (although even then it must be retained until the commit completes).
* Any implementation that supports repeatable reads in a way that prevents the above phenomena
* is permissible.
* <p/>
* The persistence implementation is not required to support calling lock(entity, LockMode-Type.READ)
* on a non-versioned object. When it cannot support such a lock call, it must throw the
* PersistenceException. When supported, whether for versioned or non-versioned objects, LockMode-Type.READ
* must always prevent the phenomena P1 and P2. Applications that call lock(entity, LockModeType.READ)
* on non-versioned objects will not be portable.
* <p/>
* Odd as it may sound, EJB3 LockModeType.READ actually maps to the Hibernate LockMode.UPGRADE
*/
public void testLockModeTypeRead() {
if ( ! readCommittedIsolationMaintained( "ejb3 lock tests" ) ) {
return;
}
if ( getDialect().doesReadCommittedCauseWritersToBlockReaders() ) {
reportSkip( "write locks block readers", "jpa read locking" );
return;
}
final String initialName = "lock test";
// set up some test data
Session s1 = getSessions().openSession();
Transaction t1 = s1.beginTransaction();
Item item = new Item();
item.setName( initialName );
s1.save( item );
t1.commit();
s1.close();
Long itemId = item.getId();
// perform the isolated update
s1 = getSessions().openSession();
t1 = s1.beginTransaction();
item = ( Item ) s1.get( Item.class, itemId );
s1.lock( item, LockMode.UPGRADE );
item.setName( "updated" );
s1.flush();
Session s2 = getSessions().openSession();
Transaction t2 = s2.beginTransaction();
Item item2 = ( Item ) s2.get( Item.class, itemId );
assertEquals( "isolation not maintained", initialName, item2.getName() );
t1.commit();
s1.close();
item2 = ( Item ) s2.get( Item.class, itemId );
assertEquals( "repeatable read not maintained", initialName, item2.getName() );
t2.commit();
s2.close();
s1 = getSessions().openSession();
t1 = s1.beginTransaction();
s1.delete( item );
t1.commit();
s1.close();
}
/**
* Test the equivalent of EJB3 LockModeType.WRITE
* <p/>
* From the spec:
* <p/>
* If transaction T1 calls lock(entity, LockModeType.WRITE) on a versioned object, the entity
* manager must avoid the phenomena P1 and P2 (as with LockModeType.READ) and must also force
* an update (increment) to the entity's version column. A forced version update may be performed immediately,
* or may be deferred until a flush or commit. If an entity is removed before a deferred version
* update was to have been applied, the forced version update is omitted, since the underlying database
* row no longer exists.
* <p/>
* The persistence implementation is not required to support calling lock(entity, LockMode-Type.WRITE)
* on a non-versioned object. When it cannot support a such lock call, it must throw the
* PersistenceException. When supported, whether for versioned or non-versioned objects, LockMode-Type.WRITE
* must always prevent the phenomena P1 and P2. For non-versioned objects, whether or
* not LockModeType.WRITE has any additional behaviour is vendor-specific. Applications that call
* lock(entity, LockModeType.WRITE) on non-versioned objects will not be portable.
* <p/>
* Due to the requirement that LockModeType.WRITE needs to force a version increment,
* a new Hibernate LockMode was added to support this behavior: {@link org.hibernate.LockMode#FORCE}.
*/
public void testLockModeTypeWrite() {
if ( ! readCommittedIsolationMaintained( "ejb3 lock tests" ) ) {
return;
}
if ( getDialect().doesReadCommittedCauseWritersToBlockReaders() ) {
reportSkip( "write locks block readers", "jpa read locking" );
return;
}
final String initialName = "lock test";
// set up some test data
Session s1 = getSessions().openSession();
Transaction t1 = s1.beginTransaction();
Item item = new Item();
item.setName( initialName );
s1.save( item );
MyEntity myEntity = new MyEntity();
myEntity.setName( "Test" );
s1.save( myEntity );
t1.commit();
s1.close();
Long itemId = item.getId();
long initialVersion = item.getVersion();
s1 = getSessions().openSession();
t1 = s1.beginTransaction();
item = ( Item ) s1.get( Item.class, itemId );
s1.lock( item, LockMode.FORCE );
assertEquals( "no forced version increment", initialVersion + 1, item.getVersion() );
myEntity = (MyEntity) s1.get( MyEntity.class, myEntity.getId() );
s1.lock( myEntity, LockMode.FORCE );
assertTrue( "LockMode.FORCE on a unversioned entity should degrade nicely to UPGRADE", true );
s1.lock( item, LockMode.FORCE );
assertEquals( "subsequent LockMode.FORCE did not no-op", initialVersion + 1, item.getVersion() );
Session s2 = getSessions().openSession();
Transaction t2 = s2.beginTransaction();
Item item2 = ( Item ) s2.get( Item.class, itemId );
assertEquals( "isolation not maintained", initialName, item2.getName() );
item.setName( "updated-1" );
s1.flush();
// currently an unfortunate side effect...
assertEquals( initialVersion + 2, item.getVersion() );
t1.commit();
s1.close();
item2.setName( "updated" );
try {
t2.commit();
fail( "optimisitc lock should have failed" );
}
catch( Throwable ignore ) {
// expected behavior
t2.rollback();
}
finally {
s2.close();
}
s1 = getSessions().openSession();
t1 = s1.beginTransaction();
s1.delete( item );
s1.delete( myEntity );
t1.commit();
s1.close();
}
public void testStaleVersionedInstanceFoundOnLock() {
if ( ! readCommittedIsolationMaintained( "repeatable read tests" ) ) {
return;
}
if ( getDialect().doesReadCommittedCauseWritersToBlockReaders()) {
reportSkip( "lock blocking", "stale versioned instance" );
return;
}
String check = "EJB3 Specification";
Session s1 = getSessions().openSession();
Transaction t1 = s1.beginTransaction();
Item item = new Item( check );
s1.save( item );
t1.commit();
s1.close();
Long itemId = item.getId();
long initialVersion = item.getVersion();
// Now, open a new Session and re-load the item...
s1 = getSessions().openSession();
t1 = s1.beginTransaction();
item = ( Item ) s1.get( Item.class, itemId );
// now that the item is associated with the persistence-context of that session,
// open a new session and modify it "behind the back" of the first session
Session s2 = getSessions().openSession();
Transaction t2 = s2.beginTransaction();
Item item2 = ( Item ) s2.get( Item.class, itemId );
item2.setName( "EJB3 Persistence Spec" );
t2.commit();
s2.close();
// at this point, s1 now contains stale data, so acquire a READ lock
// and make sure we get the already associated state (i.e., the old
// name and the old version)
s1.lock( item, LockMode.READ );
item2 = ( Item ) s1.get( Item.class, itemId );
assertTrue( item == item2 );
assertEquals( "encountered non-repeatable read", check, item2.getName() );
assertEquals( "encountered non-repeatable read", initialVersion, item2.getVersion() );
// attempt to acquire an UPGRADE lock; this should fail
try {
s1.lock( item, LockMode.UPGRADE );
fail( "expected UPGRADE lock failure" );
}
catch( StaleObjectStateException expected ) {
// this is the expected behavior
}
catch( SQLGrammarException t ) {
if ( getDialect() instanceof SQLServerDialect ) {
// sql-server (using snapshot isolation) reports this as a grammar exception /:)
//
// not to mention that it seems to "lose track" of the transaction in this scenario...
t1.rollback();
t1 = s1.beginTransaction();
}
else {
throw t;
}
}
t1.commit();
s1.close();
// clean up
s1 = getSessions().openSession();
t1 = s1.beginTransaction();
s1.createQuery( "delete Item" ).executeUpdate();
t1.commit();
s1.close();
}
public void testStaleNonVersionedInstanceFoundOnLock() {
if ( ! readCommittedIsolationMaintained( "repeatable read tests" ) ) {
return;
}
if ( getDialect().doesReadCommittedCauseWritersToBlockReaders()) {
reportSkip( "lock blocking", "stale versioned instance" );
return;
}
String check = "Lock Modes";
Session s1 = getSessions().openSession();
Transaction t1 = s1.beginTransaction();
Part part = new Part( new Item( "EJB3 Specification" ), check, "3.3.5.3", new BigDecimal( 0.0 ) );
s1.save( part );
t1.commit();
s1.close();
Long partId = part.getId();
// Now, open a new Session and re-load the part...
s1 = getSessions().openSession();
t1 = s1.beginTransaction();
part = ( Part ) s1.get( Part.class, partId );
// now that the item is associated with the persistence-context of that session,
// open a new session and modify it "behind the back" of the first session
Session s2 = getSessions().openSession();
Transaction t2 = s2.beginTransaction();
Part part2 = ( Part ) s2.get( Part.class, partId );
part2.setName( "Lock Mode Types" );
t2.commit();
s2.close();
// at this point, s1 now contains stale data, so acquire a READ lock
// and make sure we get the already associated state (i.e., the old
// name and the old version)
s1.lock( part, LockMode.READ );
part2 = ( Part ) s1.get( Part.class, partId );
assertTrue( part == part2 );
assertEquals( "encountered non-repeatable read", check, part2.getName() );
// then acquire an UPGRADE lock; this should fail
try {
s1.lock( part, LockMode.UPGRADE );
}
catch( Throwable t ) {
// SQLServer, for example, immediately throws an exception here...
t1.rollback();
t1 = s1.beginTransaction();
}
part2 = ( Part ) s1.get( Part.class, partId );
assertTrue( part == part2 );
assertEquals( "encountered non-repeatable read", check, part2.getName() );
t1.commit();
s1.close();
// clean up
s1 = getSessions().openSession();
t1 = s1.beginTransaction();
s1.delete( part );
s1.delete( part.getItem() );
t1.commit();
s1.close();
}