1
//$Id: TableGenerator.java 11304 2007-03-19 22:06:45Z steve.ebersole@jboss.com $
2
package org.hibernate.id;
4
import java.io.Serializable;
5
import java.sql.Connection;
6
import java.sql.PreparedStatement;
7
import java.sql.ResultSet;
8
import java.sql.SQLException;
10
import java.util.Properties;
12
import org.apache.commons.logging.Log;
13
import org.apache.commons.logging.LogFactory;
14
import org.hibernate.HibernateException;
15
import org.hibernate.LockMode;
16
import org.hibernate.dialect.Dialect;
17
import org.hibernate.engine.SessionImplementor;
18
import org.hibernate.engine.TransactionHelper;
19
import org.hibernate.mapping.Table;
20
import org.hibernate.type.Type;
21
import org.hibernate.util.PropertiesHelper;
24
* An <tt>IdentifierGenerator</tt> that uses a database
25
* table to store the last generated value. It is not
26
* intended that applications use this strategy directly.
27
* However, it may be used to build other (efficient)
28
* strategies. The returned type is <tt>Integer</tt>.<br>
30
* The hi value MUST be fetched in a seperate transaction
31
* to the <tt>Session</tt> transaction so the generator must
32
* be able to obtain a new connection and commit it. Hence
33
* this implementation may not be used when Hibernate is
34
* fetching connections when the user is supplying
37
* The returned value is of type <tt>integer</tt>.<br>
39
* Mapping parameters supported: table, column
41
* @see TableHiLoGenerator
44
public class TableGenerator extends TransactionHelper
45
implements PersistentIdentifierGenerator, Configurable {
46
/* COLUMN and TABLE should be renamed but it would break the public API */
47
/** The column parameter */
48
public static final String COLUMN = "column";
50
/** Default column name */
51
public static final String DEFAULT_COLUMN_NAME = "next_hi";
53
/** The table parameter */
54
public static final String TABLE = "table";
56
/** Default table name */
57
public static final String DEFAULT_TABLE_NAME = "hibernate_unique_key";
59
private static final Log log = LogFactory.getLog(TableGenerator.class);
61
private String tableName;
62
private String columnName;
64
private String update;
66
public void configure(Type type, Properties params, Dialect dialect) {
68
tableName = PropertiesHelper.getString(TABLE, params, DEFAULT_TABLE_NAME);
69
columnName = PropertiesHelper.getString(COLUMN, params, DEFAULT_COLUMN_NAME);
70
String schemaName = params.getProperty(SCHEMA);
71
String catalogName = params.getProperty(CATALOG);
73
if ( tableName.indexOf( '.' )<0 ) {
74
tableName = Table.qualify( catalogName, schemaName, tableName );
80
dialect.appendLockHint(LockMode.UPGRADE, tableName) +
81
dialect.getForUpdateString();
92
public synchronized Serializable generate(SessionImplementor session, Object object)
93
throws HibernateException {
94
int result = ( (Integer) doWorkInNewTransaction(session) ).intValue();
95
return new Integer(result);
99
public String[] sqlCreateStrings(Dialect dialect) {
100
return new String[] {
101
dialect.getCreateTableString() + " " + tableName + " ( " + columnName + " " + dialect.getTypeName(Types.INTEGER) + " )",
102
"insert into " + tableName + " values ( 0 )"
106
public String[] sqlDropStrings(Dialect dialect) {
107
StringBuffer sqlDropString = new StringBuffer( "drop table " );
108
if ( dialect.supportsIfExistsBeforeTableName() ) {
109
sqlDropString.append( "if exists " );
111
sqlDropString.append( tableName ).append( dialect.getCascadeConstraintsString() );
112
if ( dialect.supportsIfExistsAfterTableName() ) {
113
sqlDropString.append( " if exists" );
115
return new String[] { sqlDropString.toString() };
118
public Object generatorKey() {
122
public Serializable doWorkInCurrentTransaction(Connection conn, String sql) throws SQLException {
126
// The loop ensures atomicity of the
127
// select + update even for no transaction
128
// or read committed isolation level
132
PreparedStatement qps = conn.prepareStatement(query);
134
ResultSet rs = qps.executeQuery();
136
String err = "could not read a hi value - you need to populate the table: " + tableName;
138
throw new IdentifierGenerationException(err);
140
result = rs.getInt(1);
143
catch (SQLException sqle) {
144
log.error("could not read a hi value", sqle);
153
PreparedStatement ups = conn.prepareStatement(update);
155
ups.setInt( 1, result + 1 );
156
ups.setInt( 2, result );
157
rows = ups.executeUpdate();
159
catch (SQLException sqle) {
160
log.error("could not update hi value in: " + tableName, sqle);
168
return new Integer(result);