2
* Hibernate, Relational Persistence for Idiomatic Java
4
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
5
* indicated by the @author tags or express copyright attribution
6
* statements applied by the authors. All third-party contributions are
7
* distributed under license by Red Hat Middleware LLC.
9
* This copyrighted material is made available to anyone wishing to use, modify,
10
* copy, or redistribute it subject to the terms and conditions of the GNU
11
* Lesser General Public License, as published by the Free Software Foundation.
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
18
* You should have received a copy of the GNU Lesser General Public License
19
* along with this distribution; if not, write to:
20
* Free Software Foundation, Inc.
21
* 51 Franklin Street, Fifth Floor
22
* Boston, MA 02110-1301 USA
25
package org.hibernate.dialect.lock;
27
import org.hibernate.persister.entity.Lockable;
28
import org.hibernate.LockMode;
29
import org.hibernate.HibernateException;
30
import org.hibernate.StaleObjectStateException;
31
import org.hibernate.JDBCException;
32
import org.hibernate.pretty.MessageHelper;
33
import org.hibernate.exception.JDBCExceptionHelper;
34
import org.hibernate.sql.Update;
35
import org.hibernate.engine.SessionImplementor;
36
import org.hibernate.engine.SessionFactoryImplementor;
37
import org.slf4j.Logger;
38
import org.slf4j.LoggerFactory;
40
import java.io.Serializable;
41
import java.sql.PreparedStatement;
42
import java.sql.SQLException;
45
* A locking strategy where the locks are obtained through update statements.
47
* This strategy is not valid for read style locks.
51
* @author Steve Ebersole
53
public class UpdateLockingStrategy implements LockingStrategy {
54
private static final Logger log = LoggerFactory.getLogger( UpdateLockingStrategy.class );
56
private final Lockable lockable;
57
private final LockMode lockMode;
58
private final String sql;
61
* Construct a locking strategy based on SQL UPDATE statements.
63
* @param lockable The metadata for the entity to be locked.
64
* @param lockMode Indictates the type of lock to be acquired. Note that
65
* read-locks are not valid for this strategy.
67
public UpdateLockingStrategy(Lockable lockable, LockMode lockMode) {
68
this.lockable = lockable;
69
this.lockMode = lockMode;
70
if ( lockMode.lessThan( LockMode.UPGRADE ) ) {
71
throw new HibernateException( "[" + lockMode + "] not valid for update statement" );
73
if ( !lockable.isVersioned() ) {
74
log.warn( "write locks via update not supported for non-versioned entities [" + lockable.getEntityName() + "]" );
78
this.sql = generateLockString();
83
* @see LockingStrategy#lock
89
SessionImplementor session) throws StaleObjectStateException, JDBCException {
90
if ( !lockable.isVersioned() ) {
91
throw new HibernateException( "write locks via update not supported for non-versioned entities [" + lockable.getEntityName() + "]" );
93
// todo : should we additionally check the current isolation mode explicitly?
94
SessionFactoryImplementor factory = session.getFactory();
96
PreparedStatement st = session.getBatcher().prepareSelectStatement( sql );
98
lockable.getVersionType().nullSafeSet( st, version, 1, session );
101
lockable.getIdentifierType().nullSafeSet( st, id, offset, session );
102
offset += lockable.getIdentifierType().getColumnSpan( factory );
104
if ( lockable.isVersioned() ) {
105
lockable.getVersionType().nullSafeSet( st, version, offset, session );
108
int affected = st.executeUpdate();
109
if ( affected < 0 ) {
110
factory.getStatisticsImplementor().optimisticFailure( lockable.getEntityName() );
111
throw new StaleObjectStateException( lockable.getEntityName(), id );
116
session.getBatcher().closeStatement( st );
120
catch ( SQLException sqle ) {
121
throw JDBCExceptionHelper.convert(
122
session.getFactory().getSQLExceptionConverter(),
124
"could not lock: " + MessageHelper.infoString( lockable, id, session.getFactory() ),
130
protected String generateLockString() {
131
SessionFactoryImplementor factory = lockable.getFactory();
132
Update update = new Update( factory.getDialect() );
133
update.setTableName( lockable.getRootTableName() );
134
update.setPrimaryKeyColumnNames( lockable.getRootTableIdentifierColumnNames() );
135
update.setVersionColumnName( lockable.getVersionColumnName() );
136
update.addColumn( lockable.getVersionColumnName() );
137
if ( factory.getSettings().isCommentsEnabled() ) {
138
update.setComment( lockMode + " lock " + lockable.getEntityName() );
140
return update.toStatementString();
143
protected LockMode getLockMode() {