HHH-5985 - Remove TransactionHelper in preference of IsolationDelegate
This commit is contained in:
parent
ddfcc44d76
commit
21cc90fbf4
|
@ -1,74 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2008-2011, 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.engine;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.jdbc.Work;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Allows work to be done outside the current transaction, by suspending it,
|
||||
* and performing work in a new transaction
|
||||
*
|
||||
* @author Emmanuel Bernard
|
||||
*/
|
||||
public abstract class TransactionHelper {
|
||||
|
||||
// todo : remove this and just have subclasses use IsolationDelegate directly...
|
||||
|
||||
/**
|
||||
* The work to be done
|
||||
*/
|
||||
protected abstract Serializable doWorkInCurrentTransaction(Connection conn, String sql) throws SQLException;
|
||||
|
||||
/**
|
||||
* Suspend the current transaction and perform work in a new transaction
|
||||
*/
|
||||
public Serializable doWorkInNewTransaction(final SessionImplementor session) throws HibernateException {
|
||||
class WorkToDo implements Work {
|
||||
Serializable generatedValue;
|
||||
|
||||
@Override
|
||||
public void execute(Connection connection) throws SQLException {
|
||||
String sql = null;
|
||||
try {
|
||||
generatedValue = doWorkInCurrentTransaction( connection, sql );
|
||||
}
|
||||
catch( SQLException e ) {
|
||||
throw session.getFactory().getSQLExceptionHelper().convert(
|
||||
e,
|
||||
"could not get or update next value",
|
||||
sql
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
WorkToDo work = new WorkToDo();
|
||||
session.getTransactionCoordinator().getTransaction().createIsolationDelegate().delegateWork( work, true );
|
||||
return work.generatedValue;
|
||||
}
|
||||
}
|
|
@ -36,6 +36,7 @@ import org.hibernate.engine.transaction.internal.TransactionCoordinatorImpl;
|
|||
import org.hibernate.engine.transaction.spi.TransactionContext;
|
||||
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
|
||||
import org.hibernate.engine.transaction.spi.TransactionEnvironment;
|
||||
import org.hibernate.jdbc.ReturningWork;
|
||||
import org.hibernate.jdbc.Work;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -204,6 +205,29 @@ public class JdbcCoordinatorImpl implements JdbcCoordinator {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T coordinateWork(ReturningWork<T> work) {
|
||||
Connection connection = getLogicalConnection().getDistinctConnectionProxy();
|
||||
try {
|
||||
T result = work.execute( connection );
|
||||
getLogicalConnection().afterStatementExecution();
|
||||
return result;
|
||||
}
|
||||
catch ( SQLException e ) {
|
||||
throw sqlExceptionHelper().convert( e, "error executing work" );
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
if ( ! connection.isClosed() ) {
|
||||
connection.close();
|
||||
}
|
||||
}
|
||||
catch (SQLException e) {
|
||||
log.debug( "Error closing connection proxy", e );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void executeBatch() {
|
||||
if ( currentBatch != null ) {
|
||||
currentBatch.execute();
|
||||
|
|
|
@ -26,6 +26,8 @@ package org.hibernate.engine.jdbc.spi;
|
|||
import org.hibernate.engine.jdbc.batch.spi.Batch;
|
||||
import org.hibernate.engine.jdbc.batch.spi.BatchKey;
|
||||
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
|
||||
import org.hibernate.id.IntegralDataTypeHolder;
|
||||
import org.hibernate.jdbc.ReturningWork;
|
||||
import org.hibernate.jdbc.Work;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
@ -88,9 +90,12 @@ public interface JdbcCoordinator extends Serializable {
|
|||
|
||||
public void coordinateWork(Work work);
|
||||
|
||||
public <T> T coordinateWork(ReturningWork<T> work);
|
||||
|
||||
public void executeBatch();
|
||||
|
||||
public void cancelLastQuery();
|
||||
|
||||
public void setTransactionTimeOut(int timeout);
|
||||
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.hibernate.jdbc.util.FormatStyle;
|
||||
import org.hibernate.jdbc.util.Formatter;
|
||||
|
||||
/**
|
||||
* Centralize logging for SQL statements.
|
||||
|
@ -90,9 +91,13 @@ public class SQLStatementLogger {
|
|||
*/
|
||||
public void logStatement(String statement) {
|
||||
// for now just assume a DML log for formatting
|
||||
logStatement( statement, FormatStyle.BASIC.getFormatter() );
|
||||
}
|
||||
|
||||
public void logStatement(String statement, Formatter formatter) {
|
||||
if ( format ) {
|
||||
if ( logToStdout || log.isDebugEnabled() ) {
|
||||
statement = FormatStyle.BASIC.getFormatter().format( statement );
|
||||
statement = formatter.format( statement );
|
||||
}
|
||||
}
|
||||
log.debug( statement );
|
||||
|
|
|
@ -34,6 +34,7 @@ import org.hibernate.HibernateException;
|
|||
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
|
||||
import org.hibernate.engine.transaction.spi.IsolationDelegate;
|
||||
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
|
||||
import org.hibernate.jdbc.ReturningWork;
|
||||
import org.hibernate.jdbc.Work;
|
||||
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
|
||||
|
||||
|
@ -120,4 +121,68 @@ public class JdbcIsolationDelegate implements IsolationDelegate {
|
|||
throw sqlExceptionHelper().convert( sqle, "unable to obtain isolated JDBC connection" );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T delegateWork(ReturningWork<T> work, boolean transacted) throws HibernateException {
|
||||
boolean wasAutoCommit = false;
|
||||
try {
|
||||
// todo : should we use a connection proxy here?
|
||||
Connection connection = connectionProvider().getConnection();
|
||||
try {
|
||||
if ( transacted ) {
|
||||
if ( connection.getAutoCommit() ) {
|
||||
wasAutoCommit = true;
|
||||
connection.setAutoCommit( false );
|
||||
}
|
||||
}
|
||||
|
||||
T result = work.execute( connection );
|
||||
|
||||
if ( transacted ) {
|
||||
connection.commit();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
try {
|
||||
if ( transacted && !connection.isClosed() ) {
|
||||
connection.rollback();
|
||||
}
|
||||
}
|
||||
catch ( Exception ignore ) {
|
||||
log.info( "unable to rollback connection on exception [" + ignore + "]" );
|
||||
}
|
||||
|
||||
if ( e instanceof HibernateException ) {
|
||||
throw (HibernateException) e;
|
||||
}
|
||||
else if ( e instanceof SQLException ) {
|
||||
throw sqlExceptionHelper().convert( (SQLException) e, "error performing isolated work" );
|
||||
}
|
||||
else {
|
||||
throw new HibernateException( "error performing isolated work", e );
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if ( transacted && wasAutoCommit ) {
|
||||
try {
|
||||
connection.setAutoCommit( true );
|
||||
}
|
||||
catch ( Exception ignore ) {
|
||||
log.trace( "was unable to reset connection back to auto-commit" );
|
||||
}
|
||||
}
|
||||
try {
|
||||
connectionProvider().closeConnection( connection );
|
||||
}
|
||||
catch ( Exception ignore ) {
|
||||
log.info( "Unable to release isolated connection [" + ignore + "]" );
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( SQLException sqle ) {
|
||||
throw sqlExceptionHelper().convert( sqle, "unable to obtain isolated JDBC connection" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ import org.hibernate.HibernateException;
|
|||
import org.hibernate.engine.jdbc.spi.SQLExceptionHelper;
|
||||
import org.hibernate.engine.transaction.spi.IsolationDelegate;
|
||||
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
|
||||
import org.hibernate.jdbc.ReturningWork;
|
||||
import org.hibernate.jdbc.Work;
|
||||
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
|
||||
|
||||
|
@ -181,5 +182,113 @@ public class JtaIsolationDelegate implements IsolationDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T delegateWork(ReturningWork<T> work, boolean transacted) throws HibernateException {
|
||||
TransactionManager transactionManager = transactionManager();
|
||||
|
||||
try {
|
||||
// First we suspend any current JTA transaction
|
||||
Transaction surroundingTransaction = transactionManager.suspend();
|
||||
if ( log.isDebugEnabled() ) {
|
||||
log.debug( "surrounding JTA transaction suspended [" + surroundingTransaction + "]" );
|
||||
}
|
||||
|
||||
boolean hadProblems = false;
|
||||
try {
|
||||
// then perform the requested work
|
||||
if ( transacted ) {
|
||||
return doTheWorkInNewTransaction( work, transactionManager );
|
||||
}
|
||||
else {
|
||||
return doTheWorkInNoTransaction( work );
|
||||
}
|
||||
}
|
||||
catch ( HibernateException e ) {
|
||||
hadProblems = true;
|
||||
throw e;
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
transactionManager.resume( surroundingTransaction );
|
||||
if ( log.isDebugEnabled() ) {
|
||||
log.debug( "surrounding JTA transaction resumed [" + surroundingTransaction + "]" );
|
||||
}
|
||||
}
|
||||
catch( Throwable t ) {
|
||||
// if the actually work had an error use that, otherwise error based on t
|
||||
if ( !hadProblems ) {
|
||||
//noinspection ThrowFromFinallyBlock
|
||||
throw new HibernateException( "Unable to resume previously suspended transaction", t );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( SystemException e ) {
|
||||
throw new HibernateException( "Unable to suspend current JTA transaction", e );
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T doTheWorkInNewTransaction(ReturningWork<T> work, TransactionManager transactionManager) {
|
||||
T result = null;
|
||||
try {
|
||||
// start the new isolated transaction
|
||||
transactionManager.begin();
|
||||
|
||||
try {
|
||||
result = doTheWork( work );
|
||||
// if everything went ok, commit the isolated transaction
|
||||
transactionManager.commit();
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
try {
|
||||
transactionManager.rollback();
|
||||
}
|
||||
catch ( Exception ignore ) {
|
||||
log.info( "Unable to rollback isolated transaction on error [" + e + "] : [" + ignore + "]" );
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( SystemException e ) {
|
||||
throw new HibernateException( "Unable to start isolated transaction", e );
|
||||
}
|
||||
catch ( NotSupportedException e ) {
|
||||
throw new HibernateException( "Unable to start isolated transaction", e );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private <T> T doTheWorkInNoTransaction(ReturningWork<T> work) {
|
||||
return doTheWork( work );
|
||||
}
|
||||
|
||||
private <T> T doTheWork(ReturningWork<T> work) {
|
||||
try {
|
||||
// obtain our isolated connection
|
||||
Connection connection = connectionProvider().getConnection();
|
||||
try {
|
||||
// do the actual work
|
||||
return work.execute( connection );
|
||||
}
|
||||
catch ( HibernateException e ) {
|
||||
throw e;
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
throw new HibernateException( "Unable to perform isolated work", e );
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
// no matter what, release the connection (handle)
|
||||
connectionProvider().closeConnection( connection );
|
||||
}
|
||||
catch ( Throwable ignore ) {
|
||||
log.info( "Unable to release isolated connection [" + ignore + "]" );
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( SQLException e ) {
|
||||
throw sqlExceptionHelper().convert( e, "unable to obtain isolated JDBC connection" );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
package org.hibernate.engine.transaction.spi;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.jdbc.ReturningWork;
|
||||
import org.hibernate.jdbc.Work;
|
||||
|
||||
/**
|
||||
|
@ -41,4 +42,16 @@ public interface IsolationDelegate {
|
|||
* @throws HibernateException Indicates a problem performing the work.
|
||||
*/
|
||||
public void delegateWork(Work work, boolean transacted) throws HibernateException;
|
||||
|
||||
/**
|
||||
* Perform the given work in isolation from current transaction.
|
||||
*
|
||||
* @param work The work to be performed.
|
||||
* @param transacted Should the work itself be done in a (isolated) transaction?
|
||||
*
|
||||
* @return The work result
|
||||
*
|
||||
* @throws HibernateException Indicates a problem performing the work.
|
||||
*/
|
||||
public <T> T delegateWork(ReturningWork<T> work, boolean transacted) throws HibernateException;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,24 @@
|
|||
*/
|
||||
package org.hibernate.id;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.cfg.ObjectNameNormalizer;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.SessionImplementor;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.jdbc.spi.SQLStatementLogger;
|
||||
import org.hibernate.id.enhanced.AccessCallback;
|
||||
import org.hibernate.id.enhanced.OptimizerFactory;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
import org.hibernate.jdbc.ReturningWork;
|
||||
import org.hibernate.jdbc.util.FormatStyle;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.type.Type;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
|
@ -31,22 +49,6 @@ import java.sql.SQLException;
|
|||
import java.sql.Types;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.cfg.ObjectNameNormalizer;
|
||||
import org.hibernate.id.enhanced.AccessCallback;
|
||||
import org.hibernate.id.enhanced.OptimizerFactory;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
import org.hibernate.jdbc.util.FormatStyle;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.SessionImplementor;
|
||||
import org.hibernate.engine.TransactionHelper;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
/**
|
||||
*
|
||||
* A hilo <tt>IdentifierGenerator</tt> that returns a <tt>Long</tt>, constructed using
|
||||
|
@ -78,11 +80,8 @@ import org.hibernate.type.Type;
|
|||
* @author Emmanuel Bernard
|
||||
* @author <a href="mailto:kr@hbt.de">Klaus Richarz</a>.
|
||||
*/
|
||||
public class MultipleHiLoPerTableGenerator
|
||||
extends TransactionHelper
|
||||
implements PersistentIdentifierGenerator, Configurable {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(MultipleHiLoPerTableGenerator.class);
|
||||
public class MultipleHiLoPerTableGenerator implements PersistentIdentifierGenerator, Configurable {
|
||||
private static final Logger log = LoggerFactory.getLogger( MultipleHiLoPerTableGenerator.class );
|
||||
|
||||
public static final String ID_TABLE = "table";
|
||||
public static final String PK_COLUMN_NAME = "primary_key_column";
|
||||
|
@ -146,66 +145,73 @@ public class MultipleHiLoPerTableGenerator
|
|||
return tableName;
|
||||
}
|
||||
|
||||
public Serializable doWorkInCurrentTransaction(Connection conn, String sql) throws SQLException {
|
||||
IntegralDataTypeHolder value = IdentifierGeneratorHelper.getIntegralDataTypeHolder( returnClass );
|
||||
int rows;
|
||||
do {
|
||||
SQL_STATEMENT_LOGGER.logStatement( query, FormatStyle.BASIC );
|
||||
PreparedStatement qps = conn.prepareStatement( query );
|
||||
PreparedStatement ips = null;
|
||||
try {
|
||||
ResultSet rs = qps.executeQuery();
|
||||
boolean isInitialized = rs.next();
|
||||
if ( !isInitialized ) {
|
||||
value.initialize( 0 );
|
||||
SQL_STATEMENT_LOGGER.logStatement( insert, FormatStyle.BASIC );
|
||||
ips = conn.prepareStatement( insert );
|
||||
value.bind( ips, 1 );
|
||||
ips.execute();
|
||||
}
|
||||
else {
|
||||
value.initialize( rs, 0 );
|
||||
}
|
||||
rs.close();
|
||||
}
|
||||
catch (SQLException sqle) {
|
||||
log.error("could not read or init a hi value", sqle);
|
||||
throw sqle;
|
||||
}
|
||||
finally {
|
||||
if (ips != null) {
|
||||
ips.close();
|
||||
}
|
||||
qps.close();
|
||||
}
|
||||
public synchronized Serializable generate(final SessionImplementor session, Object obj) {
|
||||
final ReturningWork<IntegralDataTypeHolder> work = new ReturningWork<IntegralDataTypeHolder>() {
|
||||
@Override
|
||||
public IntegralDataTypeHolder execute(Connection connection) throws SQLException {
|
||||
IntegralDataTypeHolder value = IdentifierGeneratorHelper.getIntegralDataTypeHolder( returnClass );
|
||||
SQLStatementLogger statementLogger = session
|
||||
.getFactory()
|
||||
.getServiceRegistry()
|
||||
.getService( JdbcServices.class )
|
||||
.getSqlStatementLogger();
|
||||
int rows;
|
||||
do {
|
||||
statementLogger.logStatement( query, FormatStyle.BASIC.getFormatter() );
|
||||
PreparedStatement qps = connection.prepareStatement( query );
|
||||
PreparedStatement ips = null;
|
||||
try {
|
||||
ResultSet rs = qps.executeQuery();
|
||||
boolean isInitialized = rs.next();
|
||||
if ( !isInitialized ) {
|
||||
value.initialize( 0 );
|
||||
statementLogger.logStatement( insert, FormatStyle.BASIC.getFormatter() );
|
||||
ips = connection.prepareStatement( insert );
|
||||
value.bind( ips, 1 );
|
||||
ips.execute();
|
||||
}
|
||||
else {
|
||||
value.initialize( rs, 0 );
|
||||
}
|
||||
rs.close();
|
||||
}
|
||||
catch (SQLException sqle) {
|
||||
log.error("could not read or init a hi value", sqle);
|
||||
throw sqle;
|
||||
}
|
||||
finally {
|
||||
if (ips != null) {
|
||||
ips.close();
|
||||
}
|
||||
qps.close();
|
||||
}
|
||||
|
||||
SQL_STATEMENT_LOGGER.logStatement( update, FormatStyle.BASIC );
|
||||
PreparedStatement ups = conn.prepareStatement( update );
|
||||
try {
|
||||
value.copy().increment().bind( ups, 1 );
|
||||
value.bind( ups, 2 );
|
||||
rows = ups.executeUpdate();
|
||||
}
|
||||
catch (SQLException sqle) {
|
||||
log.error("could not update hi value in: " + tableName, sqle);
|
||||
throw sqle;
|
||||
}
|
||||
finally {
|
||||
ups.close();
|
||||
}
|
||||
} while ( rows==0 );
|
||||
statementLogger.logStatement( update, FormatStyle.BASIC.getFormatter() );
|
||||
PreparedStatement ups = connection.prepareStatement( update );
|
||||
try {
|
||||
value.copy().increment().bind( ups, 1 );
|
||||
value.bind( ups, 2 );
|
||||
rows = ups.executeUpdate();
|
||||
}
|
||||
catch (SQLException sqle) {
|
||||
log.error("could not update hi value in: " + tableName, sqle);
|
||||
throw sqle;
|
||||
}
|
||||
finally {
|
||||
ups.close();
|
||||
}
|
||||
} while ( rows==0 );
|
||||
|
||||
return value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
public synchronized Serializable generate(final SessionImplementor session, Object obj)
|
||||
throws HibernateException {
|
||||
// maxLo < 1 indicates a hilo generator with no hilo :?
|
||||
if ( maxLo < 1 ) {
|
||||
//keep the behavior consistent even for boundary usages
|
||||
IntegralDataTypeHolder value = null;
|
||||
while ( value == null || value.lt( 1 ) ) {
|
||||
value = (IntegralDataTypeHolder) doWorkInNewTransaction( session );
|
||||
value = session.getTransactionCoordinator().getTransaction().createIsolationDelegate().delegateWork( work, true );
|
||||
}
|
||||
return value.makeValue();
|
||||
}
|
||||
|
@ -213,7 +219,7 @@ public class MultipleHiLoPerTableGenerator
|
|||
return hiloOptimizer.generate(
|
||||
new AccessCallback() {
|
||||
public IntegralDataTypeHolder getNextValue() {
|
||||
return (IntegralDataTypeHolder) doWorkInNewTransaction( session );
|
||||
return session.getTransactionCoordinator().getTransaction().createIsolationDelegate().delegateWork( work, true );
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
||||
* Copyright (c) 2008-2011, 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 Middleware LLC.
|
||||
* 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
|
||||
|
@ -20,13 +20,11 @@
|
|||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
package org.hibernate.id;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.jdbc.util.SQLStatementLogger;
|
||||
|
||||
/**
|
||||
* An <tt>IdentifierGenerator</tt> that requires creation of database objects.
|
||||
|
@ -99,8 +97,6 @@ public interface PersistentIdentifierGenerator extends IdentifierGenerator {
|
|||
*/
|
||||
public Object generatorKey();
|
||||
|
||||
static final SQLStatementLogger SQL_STATEMENT_LOGGER = new SQLStatementLogger( false, false );
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
||||
* Copyright (c) 2008-2011, 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 Middleware LLC.
|
||||
* 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
|
||||
|
@ -20,10 +20,24 @@
|
|||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
package org.hibernate.id;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.cfg.ObjectNameNormalizer;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.SessionImplementor;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.jdbc.spi.SQLStatementLogger;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
import org.hibernate.jdbc.ReturningWork;
|
||||
import org.hibernate.jdbc.util.FormatStyle;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.type.Type;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
|
@ -32,19 +46,6 @@ import java.sql.SQLException;
|
|||
import java.sql.Types;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.cfg.ObjectNameNormalizer;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
import org.hibernate.jdbc.util.FormatStyle;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.SessionImplementor;
|
||||
import org.hibernate.engine.TransactionHelper;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
/**
|
||||
* An <tt>IdentifierGenerator</tt> that uses a database
|
||||
* table to store the last generated value. It is not
|
||||
|
@ -70,8 +71,7 @@ import org.hibernate.type.Type;
|
|||
* @see TableHiLoGenerator
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class TableGenerator extends TransactionHelper
|
||||
implements PersistentIdentifierGenerator, Configurable {
|
||||
public class TableGenerator implements PersistentIdentifierGenerator, Configurable {
|
||||
/* COLUMN and TABLE should be renamed but it would break the public API */
|
||||
/** The column parameter */
|
||||
public static final String COLUMN = "column";
|
||||
|
@ -139,7 +139,63 @@ public class TableGenerator extends TransactionHelper
|
|||
}
|
||||
|
||||
protected IntegralDataTypeHolder generateHolder(SessionImplementor session) {
|
||||
return (IntegralDataTypeHolder) doWorkInNewTransaction( session );
|
||||
final SQLStatementLogger statementLogger = session
|
||||
.getFactory()
|
||||
.getServiceRegistry()
|
||||
.getService( JdbcServices.class )
|
||||
.getSqlStatementLogger();
|
||||
return session.getTransactionCoordinator().getTransaction().createIsolationDelegate().delegateWork(
|
||||
new ReturningWork<IntegralDataTypeHolder>() {
|
||||
@Override
|
||||
public IntegralDataTypeHolder execute(Connection connection) throws SQLException {
|
||||
IntegralDataTypeHolder value = buildHolder();
|
||||
int rows;
|
||||
do {
|
||||
// The loop ensures atomicity of the
|
||||
// select + update even for no transaction
|
||||
// or read committed isolation level
|
||||
|
||||
statementLogger.logStatement( query, FormatStyle.BASIC.getFormatter() );
|
||||
PreparedStatement qps = connection.prepareStatement( query );
|
||||
try {
|
||||
ResultSet rs = qps.executeQuery();
|
||||
if ( !rs.next() ) {
|
||||
String err = "could not read a hi value - you need to populate the table: " + tableName;
|
||||
log.error(err);
|
||||
throw new IdentifierGenerationException(err);
|
||||
}
|
||||
value.initialize( rs, 1 );
|
||||
rs.close();
|
||||
}
|
||||
catch (SQLException e) {
|
||||
log.error("could not read a hi value", e);
|
||||
throw e;
|
||||
}
|
||||
finally {
|
||||
qps.close();
|
||||
}
|
||||
|
||||
statementLogger.logStatement( update, FormatStyle.BASIC.getFormatter() );
|
||||
PreparedStatement ups = connection.prepareStatement(update);
|
||||
try {
|
||||
value.copy().increment().bind( ups, 1 );
|
||||
value.bind( ups, 2 );
|
||||
rows = ups.executeUpdate();
|
||||
}
|
||||
catch (SQLException sqle) {
|
||||
log.error("could not update hi value in: " + tableName, sqle);
|
||||
throw sqle;
|
||||
}
|
||||
finally {
|
||||
ups.close();
|
||||
}
|
||||
}
|
||||
while (rows==0);
|
||||
return value;
|
||||
}
|
||||
},
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
public String[] sqlCreateStrings(Dialect dialect) throws HibernateException {
|
||||
|
@ -165,66 +221,6 @@ public class TableGenerator extends TransactionHelper
|
|||
return tableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next value.
|
||||
*
|
||||
* @param conn The sql connection to use.
|
||||
* @param sql n/a
|
||||
*
|
||||
* @return Prior to 3.5 this method returned an {@link Integer}. Since 3.5 it now
|
||||
* returns a {@link IntegralDataTypeHolder}
|
||||
*
|
||||
* @throws SQLException
|
||||
*/
|
||||
public Serializable doWorkInCurrentTransaction(Connection conn, String sql) throws SQLException {
|
||||
IntegralDataTypeHolder value = buildHolder();
|
||||
int rows;
|
||||
do {
|
||||
// The loop ensures atomicity of the
|
||||
// select + update even for no transaction
|
||||
// or read committed isolation level
|
||||
|
||||
sql = query;
|
||||
SQL_STATEMENT_LOGGER.logStatement( sql, FormatStyle.BASIC );
|
||||
PreparedStatement qps = conn.prepareStatement(query);
|
||||
try {
|
||||
ResultSet rs = qps.executeQuery();
|
||||
if ( !rs.next() ) {
|
||||
String err = "could not read a hi value - you need to populate the table: " + tableName;
|
||||
log.error(err);
|
||||
throw new IdentifierGenerationException(err);
|
||||
}
|
||||
value.initialize( rs, 1 );
|
||||
rs.close();
|
||||
}
|
||||
catch (SQLException sqle) {
|
||||
log.error("could not read a hi value", sqle);
|
||||
throw sqle;
|
||||
}
|
||||
finally {
|
||||
qps.close();
|
||||
}
|
||||
|
||||
sql = update;
|
||||
SQL_STATEMENT_LOGGER.logStatement( sql, FormatStyle.BASIC );
|
||||
PreparedStatement ups = conn.prepareStatement(update);
|
||||
try {
|
||||
value.copy().increment().bind( ups, 1 );
|
||||
value.bind( ups, 2 );
|
||||
rows = ups.executeUpdate();
|
||||
}
|
||||
catch (SQLException sqle) {
|
||||
log.error("could not update hi value in: " + tableName, sqle);
|
||||
throw sqle;
|
||||
}
|
||||
finally {
|
||||
ups.close();
|
||||
}
|
||||
}
|
||||
while (rows==0);
|
||||
return value;
|
||||
}
|
||||
|
||||
protected IntegralDataTypeHolder buildHolder() {
|
||||
return IdentifierGeneratorHelper.getIntegralDataTypeHolder( identifierType.getReturnedClass() );
|
||||
}
|
||||
|
|
|
@ -23,37 +23,38 @@
|
|||
*/
|
||||
package org.hibernate.id.enhanced;
|
||||
|
||||
import java.sql.Types;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.util.Properties;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.engine.TransactionHelper;
|
||||
import org.hibernate.cfg.ObjectNameNormalizer;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.SessionImplementor;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.jdbc.spi.SQLStatementLogger;
|
||||
import org.hibernate.id.Configurable;
|
||||
import org.hibernate.id.IdentifierGeneratorHelper;
|
||||
import org.hibernate.id.IntegralDataTypeHolder;
|
||||
import org.hibernate.id.PersistentIdentifierGenerator;
|
||||
import org.hibernate.id.Configurable;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
import org.hibernate.type.Type;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.cfg.ObjectNameNormalizer;
|
||||
import org.hibernate.jdbc.ReturningWork;
|
||||
import org.hibernate.jdbc.util.FormatStyle;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.type.Type;
|
||||
import org.hibernate.util.StringHelper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* An enhanced version of table-based id generation.
|
||||
|
@ -128,7 +129,7 @@ import org.hibernate.util.StringHelper;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class TableGenerator extends TransactionHelper implements PersistentIdentifierGenerator, Configurable {
|
||||
public class TableGenerator implements PersistentIdentifierGenerator, Configurable {
|
||||
private static final Logger log = LoggerFactory.getLogger( TableGenerator.class );
|
||||
|
||||
public static final String CONFIG_PREFER_SEGMENT_PER_ENTITY = "prefer_entity_table_as_segment_value";
|
||||
|
@ -176,9 +177,7 @@ public class TableGenerator extends TransactionHelper implements PersistentIdent
|
|||
private Optimizer optimizer;
|
||||
private long accessCount = 0;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Object generatorKey() {
|
||||
return tableName;
|
||||
}
|
||||
|
@ -283,9 +282,7 @@ public class TableGenerator extends TransactionHelper implements PersistentIdent
|
|||
return accessCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void configure(Type type, Properties params, Dialect dialect) throws MappingException {
|
||||
identifierType = type;
|
||||
|
||||
|
@ -456,93 +453,96 @@ public class TableGenerator extends TransactionHelper implements PersistentIdent
|
|||
return "insert into " + tableName + " (" + segmentColumnName + ", " + valueColumnName + ") " + " values (?,?)";
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public synchronized Serializable generate(final SessionImplementor session, Object obj) {
|
||||
final SQLStatementLogger statementLogger = session
|
||||
.getFactory()
|
||||
.getServiceRegistry()
|
||||
.getService( JdbcServices.class )
|
||||
.getSqlStatementLogger();
|
||||
return optimizer.generate(
|
||||
new AccessCallback() {
|
||||
@Override
|
||||
public IntegralDataTypeHolder getNextValue() {
|
||||
return ( IntegralDataTypeHolder ) doWorkInNewTransaction( session );
|
||||
return session.getTransactionCoordinator().getTransaction().createIsolationDelegate().delegateWork(
|
||||
new ReturningWork<IntegralDataTypeHolder>() {
|
||||
@Override
|
||||
public IntegralDataTypeHolder execute(Connection connection) throws SQLException {
|
||||
IntegralDataTypeHolder value = IdentifierGeneratorHelper.getIntegralDataTypeHolder( identifierType.getReturnedClass() );
|
||||
int rows;
|
||||
do {
|
||||
statementLogger.logStatement( selectQuery, FormatStyle.BASIC.getFormatter() );
|
||||
PreparedStatement selectPS = connection.prepareStatement( selectQuery );
|
||||
try {
|
||||
selectPS.setString( 1, segmentValue );
|
||||
ResultSet selectRS = selectPS.executeQuery();
|
||||
if ( !selectRS.next() ) {
|
||||
value.initialize( initialValue );
|
||||
PreparedStatement insertPS = null;
|
||||
try {
|
||||
statementLogger.logStatement( insertQuery, FormatStyle.BASIC.getFormatter() );
|
||||
insertPS = connection.prepareStatement( insertQuery );
|
||||
insertPS.setString( 1, segmentValue );
|
||||
value.bind( insertPS, 2 );
|
||||
insertPS.execute();
|
||||
}
|
||||
finally {
|
||||
if ( insertPS != null ) {
|
||||
insertPS.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
value.initialize( selectRS, 1 );
|
||||
}
|
||||
selectRS.close();
|
||||
}
|
||||
catch ( SQLException e ) {
|
||||
log.error( "could not read or init a hi value", e );
|
||||
throw e;
|
||||
}
|
||||
finally {
|
||||
selectPS.close();
|
||||
}
|
||||
|
||||
statementLogger.logStatement( updateQuery, FormatStyle.BASIC.getFormatter() );
|
||||
PreparedStatement updatePS = connection.prepareStatement( updateQuery );
|
||||
try {
|
||||
final IntegralDataTypeHolder updateValue = value.copy();
|
||||
if ( optimizer.applyIncrementSizeToSourceValues() ) {
|
||||
updateValue.add( incrementSize );
|
||||
}
|
||||
else {
|
||||
updateValue.increment();
|
||||
}
|
||||
updateValue.bind( updatePS, 1 );
|
||||
value.bind( updatePS, 2 );
|
||||
updatePS.setString( 3, segmentValue );
|
||||
rows = updatePS.executeUpdate();
|
||||
}
|
||||
catch ( SQLException e ) {
|
||||
log.error( "could not updateQuery hi value in: " + tableName, e );
|
||||
throw e;
|
||||
}
|
||||
finally {
|
||||
updatePS.close();
|
||||
}
|
||||
}
|
||||
while ( rows == 0 );
|
||||
|
||||
accessCount++;
|
||||
|
||||
return value;
|
||||
}
|
||||
},
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Serializable doWorkInCurrentTransaction(Connection conn, String sql) throws SQLException {
|
||||
IntegralDataTypeHolder value = IdentifierGeneratorHelper.getIntegralDataTypeHolder( identifierType.getReturnedClass() );
|
||||
int rows;
|
||||
do {
|
||||
SQL_STATEMENT_LOGGER.logStatement( selectQuery, FormatStyle.BASIC );
|
||||
PreparedStatement selectPS = conn.prepareStatement( selectQuery );
|
||||
try {
|
||||
selectPS.setString( 1, segmentValue );
|
||||
ResultSet selectRS = selectPS.executeQuery();
|
||||
if ( !selectRS.next() ) {
|
||||
value.initialize( initialValue );
|
||||
PreparedStatement insertPS = null;
|
||||
try {
|
||||
SQL_STATEMENT_LOGGER.logStatement( insertQuery, FormatStyle.BASIC );
|
||||
insertPS = conn.prepareStatement( insertQuery );
|
||||
insertPS.setString( 1, segmentValue );
|
||||
value.bind( insertPS, 2 );
|
||||
insertPS.execute();
|
||||
}
|
||||
finally {
|
||||
if ( insertPS != null ) {
|
||||
insertPS.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
value.initialize( selectRS, 1 );
|
||||
}
|
||||
selectRS.close();
|
||||
}
|
||||
catch ( SQLException sqle ) {
|
||||
log.error( "could not read or init a hi value", sqle );
|
||||
throw sqle;
|
||||
}
|
||||
finally {
|
||||
selectPS.close();
|
||||
}
|
||||
|
||||
SQL_STATEMENT_LOGGER.logStatement( updateQuery, FormatStyle.BASIC );
|
||||
PreparedStatement updatePS = conn.prepareStatement( updateQuery );
|
||||
try {
|
||||
final IntegralDataTypeHolder updateValue = value.copy();
|
||||
if ( optimizer.applyIncrementSizeToSourceValues() ) {
|
||||
updateValue.add( incrementSize );
|
||||
}
|
||||
else {
|
||||
updateValue.increment();
|
||||
}
|
||||
updateValue.bind( updatePS, 1 );
|
||||
value.bind( updatePS, 2 );
|
||||
updatePS.setString( 3, segmentValue );
|
||||
rows = updatePS.executeUpdate();
|
||||
}
|
||||
catch ( SQLException sqle ) {
|
||||
log.error( "could not updateQuery hi value in: " + tableName, sqle );
|
||||
throw sqle;
|
||||
}
|
||||
finally {
|
||||
updatePS.close();
|
||||
}
|
||||
}
|
||||
while ( rows == 0 );
|
||||
|
||||
accessCount++;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String[] sqlCreateStrings(Dialect dialect) throws HibernateException {
|
||||
return new String[] {
|
||||
new StringBuffer()
|
||||
|
@ -565,9 +565,7 @@ public class TableGenerator extends TransactionHelper implements PersistentIdent
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String[] sqlDropStrings(Dialect dialect) throws HibernateException {
|
||||
StringBuffer sqlDropString = new StringBuffer().append( "drop table " );
|
||||
if ( dialect.supportsIfExistsBeforeTableName() ) {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
||||
* Copyright (c) 2008-2011, 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 Middleware LLC.
|
||||
* 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
|
||||
|
@ -20,39 +20,36 @@
|
|||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
package org.hibernate.id.enhanced;
|
||||
|
||||
import java.io.Serializable;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.SessionImplementor;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.jdbc.spi.SQLStatementLogger;
|
||||
import org.hibernate.id.IdentifierGenerationException;
|
||||
import org.hibernate.id.IdentifierGeneratorHelper;
|
||||
import org.hibernate.id.IntegralDataTypeHolder;
|
||||
import org.hibernate.jdbc.ReturningWork;
|
||||
import org.hibernate.jdbc.util.FormatStyle;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.SessionImplementor;
|
||||
import org.hibernate.engine.TransactionHelper;
|
||||
import org.hibernate.id.IdentifierGenerationException;
|
||||
import org.hibernate.id.IdentifierGeneratorHelper;
|
||||
import org.hibernate.id.IntegralDataTypeHolder;
|
||||
import org.hibernate.jdbc.util.FormatStyle;
|
||||
import org.hibernate.jdbc.util.SQLStatementLogger;
|
||||
|
||||
/**
|
||||
* Describes a table used to mimic sequence behavior
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class TableStructure extends TransactionHelper implements DatabaseStructure {
|
||||
public class TableStructure implements DatabaseStructure {
|
||||
private static final Logger log = LoggerFactory.getLogger( TableStructure.class );
|
||||
private static final SQLStatementLogger SQL_STATEMENT_LOGGER = new SQLStatementLogger( false, false );
|
||||
|
||||
private final String tableName;
|
||||
private final String valueColumnName;
|
||||
|
@ -87,55 +84,98 @@ public class TableStructure extends TransactionHelper implements DatabaseStructu
|
|||
" where " + valueColumnName + "=?";
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return tableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int getInitialValue() {
|
||||
return initialValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int getIncrementSize() {
|
||||
return incrementSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int getTimesAccessed() {
|
||||
return accessCounter;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void prepare(Optimizer optimizer) {
|
||||
applyIncrementSizeToSourceValues = optimizer.applyIncrementSizeToSourceValues();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public AccessCallback buildCallback(final SessionImplementor session) {
|
||||
return new AccessCallback() {
|
||||
@Override
|
||||
public IntegralDataTypeHolder getNextValue() {
|
||||
return ( IntegralDataTypeHolder ) doWorkInNewTransaction( session );
|
||||
return session.getTransactionCoordinator().getTransaction().createIsolationDelegate().delegateWork(
|
||||
new ReturningWork<IntegralDataTypeHolder>() {
|
||||
@Override
|
||||
public IntegralDataTypeHolder execute(Connection connection) throws SQLException {
|
||||
final SQLStatementLogger statementLogger = session
|
||||
.getFactory()
|
||||
.getServiceRegistry()
|
||||
.getService( JdbcServices.class )
|
||||
.getSqlStatementLogger();
|
||||
IntegralDataTypeHolder value = IdentifierGeneratorHelper.getIntegralDataTypeHolder( numberType );
|
||||
int rows;
|
||||
do {
|
||||
statementLogger.logStatement( selectQuery, FormatStyle.BASIC.getFormatter() );
|
||||
PreparedStatement selectStatement = connection.prepareStatement( selectQuery );
|
||||
try {
|
||||
ResultSet selectRS = selectStatement.executeQuery();
|
||||
if ( !selectRS.next() ) {
|
||||
String err = "could not read a hi value - you need to populate the table: " + tableName;
|
||||
log.error( err );
|
||||
throw new IdentifierGenerationException( err );
|
||||
}
|
||||
value.initialize( selectRS, 1 );
|
||||
selectRS.close();
|
||||
}
|
||||
catch ( SQLException sqle ) {
|
||||
log.error( "could not read a hi value", sqle );
|
||||
throw sqle;
|
||||
}
|
||||
finally {
|
||||
selectStatement.close();
|
||||
}
|
||||
|
||||
statementLogger.logStatement( updateQuery, FormatStyle.BASIC.getFormatter() );
|
||||
PreparedStatement updatePS = connection.prepareStatement( updateQuery );
|
||||
try {
|
||||
final int increment = applyIncrementSizeToSourceValues ? incrementSize : 1;
|
||||
final IntegralDataTypeHolder updateValue = value.copy().add( increment );
|
||||
updateValue.bind( updatePS, 1 );
|
||||
value.bind( updatePS, 2 );
|
||||
rows = updatePS.executeUpdate();
|
||||
}
|
||||
catch ( SQLException e ) {
|
||||
log.error( "could not updateQuery hi value in: " + tableName, e );
|
||||
throw e;
|
||||
}
|
||||
finally {
|
||||
updatePS.close();
|
||||
}
|
||||
} while ( rows == 0 );
|
||||
|
||||
accessCounter++;
|
||||
|
||||
return value;
|
||||
}
|
||||
},
|
||||
true
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String[] sqlCreateStrings(Dialect dialect) throws HibernateException {
|
||||
return new String[] {
|
||||
dialect.getCreateTableString() + " " + tableName + " ( " + valueColumnName + " " + dialect.getTypeName( Types.BIGINT ) + " )",
|
||||
|
@ -143,9 +183,7 @@ public class TableStructure extends TransactionHelper implements DatabaseStructu
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String[] sqlDropStrings(Dialect dialect) throws HibernateException {
|
||||
StringBuffer sqlDropString = new StringBuffer().append( "drop table " );
|
||||
if ( dialect.supportsIfExistsBeforeTableName() ) {
|
||||
|
@ -157,55 +195,4 @@ public class TableStructure extends TransactionHelper implements DatabaseStructu
|
|||
}
|
||||
return new String[] { sqlDropString.toString() };
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected Serializable doWorkInCurrentTransaction(Connection conn, String sql) throws SQLException {
|
||||
IntegralDataTypeHolder value = IdentifierGeneratorHelper.getIntegralDataTypeHolder( numberType );
|
||||
int rows;
|
||||
do {
|
||||
SQL_STATEMENT_LOGGER.logStatement( selectQuery, FormatStyle.BASIC );
|
||||
PreparedStatement selectPS = conn.prepareStatement( selectQuery );
|
||||
try {
|
||||
ResultSet selectRS = selectPS.executeQuery();
|
||||
if ( !selectRS.next() ) {
|
||||
String err = "could not read a hi value - you need to populate the table: " + tableName;
|
||||
log.error( err );
|
||||
throw new IdentifierGenerationException( err );
|
||||
}
|
||||
value.initialize( selectRS, 1 );
|
||||
selectRS.close();
|
||||
}
|
||||
catch ( SQLException sqle ) {
|
||||
log.error( "could not read a hi value", sqle );
|
||||
throw sqle;
|
||||
}
|
||||
finally {
|
||||
selectPS.close();
|
||||
}
|
||||
|
||||
SQL_STATEMENT_LOGGER.logStatement( updateQuery, FormatStyle.BASIC );
|
||||
PreparedStatement updatePS = conn.prepareStatement( updateQuery );
|
||||
try {
|
||||
final int increment = applyIncrementSizeToSourceValues ? incrementSize : 1;
|
||||
final IntegralDataTypeHolder updateValue = value.copy().add( increment );
|
||||
updateValue.bind( updatePS, 1 );
|
||||
value.bind( updatePS, 2 );
|
||||
rows = updatePS.executeUpdate();
|
||||
}
|
||||
catch ( SQLException sqle ) {
|
||||
log.error( "could not updateQuery hi value in: " + tableName, sqle );
|
||||
throw sqle;
|
||||
}
|
||||
finally {
|
||||
updatePS.close();
|
||||
}
|
||||
} while ( rows == 0 );
|
||||
|
||||
accessCounter++;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2011, 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.jdbc;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* A discrete piece of work following the lines of {@link Work} but returning a result.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface ReturningWork<T> {
|
||||
/**
|
||||
* Execute the discrete work encapsulated by this work instance using the supplied connection.
|
||||
*
|
||||
* @param connection The connection on which to perform the work.
|
||||
*
|
||||
* @return The work result
|
||||
*
|
||||
* @throws SQLException Thrown during execution of the underlying JDBC interaction.
|
||||
* @throws org.hibernate.HibernateException Generally indicates a wrapped SQLException.
|
||||
*/
|
||||
public T execute(Connection connection) throws SQLException;
|
||||
}
|
Loading…
Reference in New Issue