Source code: org/hibernate/dialect/lock/UpdateLockingStrategy.java
1 package org.hibernate.dialect.lock;
2
3 import org.hibernate.persister.entity.Lockable;
4 import org.hibernate.LockMode;
5 import org.hibernate.HibernateException;
6 import org.hibernate.StaleObjectStateException;
7 import org.hibernate.JDBCException;
8 import org.hibernate.pretty.MessageHelper;
9 import org.hibernate.exception.JDBCExceptionHelper;
10 import org.hibernate.sql.Update;
11 import org.hibernate.engine.SessionImplementor;
12 import org.hibernate.engine.SessionFactoryImplementor;
13 import org.apache.commons.logging.Log;
14 import org.apache.commons.logging.LogFactory;
15
16 import java.io.Serializable;
17 import java.sql.PreparedStatement;
18 import java.sql.SQLException;
19
20 /**
21 * A locking strategy where the locks are obtained through update statements.
22 * <p/>
23 * This strategy is not valid for read style locks.
24 *
25 * @since 3.2
26 *
27 * @author Steve Ebersole
28 */
29 public class UpdateLockingStrategy implements LockingStrategy {
30 private static final Log log = LogFactory.getLog( UpdateLockingStrategy.class );
31
32 private final Lockable lockable;
33 private final LockMode lockMode;
34 private final String sql;
35
36 /**
37 * Construct a locking strategy based on SQL UPDATE statements.
38 *
39 * @param lockable The metadata for the entity to be locked.
40 * @param lockMode Indictates the type of lock to be acquired. Note that
41 * read-locks are not valid for this strategy.
42 */
43 public UpdateLockingStrategy(Lockable lockable, LockMode lockMode) {
44 this.lockable = lockable;
45 this.lockMode = lockMode;
46 if ( lockMode.lessThan( LockMode.UPGRADE ) ) {
47 throw new HibernateException( "[" + lockMode + "] not valid for update statement" );
48 }
49 if ( !lockable.isVersioned() ) {
50 log.warn( "write locks via update not supported for non-versioned entities [" + lockable.getEntityName() + "]" );
51 this.sql = null;
52 }
53 else {
54 this.sql = generateLockString();
55 }
56 }
57
58 /**
59 * @see LockingStrategy#lock
60 */
61 public void lock(
62 Serializable id,
63 Object version,
64 Object object,
65 SessionImplementor session) throws StaleObjectStateException, JDBCException {
66 if ( !lockable.isVersioned() ) {
67 throw new HibernateException( "write locks via update not supported for non-versioned entities [" + lockable.getEntityName() + "]" );
68 }
69 // todo : should we additionally check the current isolation mode explicitly?
70 SessionFactoryImplementor factory = session.getFactory();
71 try {
72 PreparedStatement st = session.getBatcher().prepareSelectStatement( sql );
73 try {
74 lockable.getVersionType().nullSafeSet( st, version, 1, session );
75 int offset = 2;
76
77 lockable.getIdentifierType().nullSafeSet( st, id, offset, session );
78 offset += lockable.getIdentifierType().getColumnSpan( factory );
79
80 if ( lockable.isVersioned() ) {
81 lockable.getVersionType().nullSafeSet( st, version, offset, session );
82 }
83
84 int affected = st.executeUpdate();
85 if ( affected < 0 ) {
86 factory.getStatisticsImplementor().optimisticFailure( lockable.getEntityName() );
87 throw new StaleObjectStateException( lockable.getEntityName(), id );
88 }
89
90 }
91 finally {
92 session.getBatcher().closeStatement( st );
93 }
94
95 }
96 catch ( SQLException sqle ) {
97 throw JDBCExceptionHelper.convert(
98 session.getFactory().getSQLExceptionConverter(),
99 sqle,
100 "could not lock: " + MessageHelper.infoString( lockable, id, session.getFactory() ),
101 sql
102 );
103 }
104 }
105
106 protected String generateLockString() {
107 SessionFactoryImplementor factory = lockable.getFactory();
108 Update update = new Update( factory.getDialect() );
109 update.setTableName( lockable.getRootTableName() );
110 update.setPrimaryKeyColumnNames( lockable.getRootTableIdentifierColumnNames() );
111 update.setVersionColumnName( lockable.getVersionColumnName() );
112 update.addColumn( lockable.getVersionColumnName() );
113 if ( factory.getSettings().isCommentsEnabled() ) {
114 update.setComment( lockMode + " lock " + lockable.getEntityName() );
115 }
116 return update.toStatementString();
117 }
118
119 protected LockMode getLockMode() {
120 return lockMode;
121 }
122 }