1 package org.hibernate.id; 3 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 ; 9 import java.sql.Types ; 10 import java.util.Properties ; 11 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.MappingException; 17 import org.hibernate.dialect.Dialect; 18 import org.hibernate.engine.SessionImplementor; 19 import org.hibernate.engine.TransactionHelper; 20 import org.hibernate.mapping.Table; 21 import org.hibernate.type.Type; 22 import org.hibernate.util.PropertiesHelper; 23 24 54 public class MultipleHiLoPerTableGenerator 55 extends TransactionHelper 56 implements PersistentIdentifierGenerator, Configurable { 57 58 private static final Log log = LogFactory.getLog(MultipleHiLoPerTableGenerator.class); 59 60 public static final String ID_TABLE = "table"; 61 public static final String PK_COLUMN_NAME = "primary_key_column"; 62 public static final String PK_VALUE_NAME = "primary_key_value"; 63 public static final String VALUE_COLUMN_NAME = "value_column"; 64 public static final String PK_LENGTH_NAME = "primary_key_length"; 65 66 private static final int DEFAULT_PK_LENGTH = 255; 67 public static final String DEFAULT_TABLE = "hibernate_sequences"; 68 private static final String DEFAULT_PK_COLUMN = "sequence_name"; 69 private static final String DEFAULT_VALUE_COLUMN = "sequence_next_hi_value"; 70 71 private String tableName; 72 private String pkColumnName; 73 private String valueColumnName; 74 private String query; 75 private String insert; 76 private String update; 77 78 public static final String MAX_LO = "max_lo"; 80 81 private long hi; 82 private int lo; 83 private int maxLo; 84 private Class returnClass; 85 private int keySize; 86 87 88 public String [] sqlCreateStrings(Dialect dialect) throws HibernateException { 89 return new String [] { 90 new StringBuffer () 91 .append("create table ") 92 .append(tableName) 93 .append(" ( ") 94 .append(pkColumnName) 95 .append(" ") 96 .append( dialect.getTypeName(Types.VARCHAR, keySize, 0, 0) ) 97 .append(", ") 98 .append(valueColumnName) 99 .append(" ") 100 .append( dialect.getTypeName(Types.INTEGER) ) 101 .append(" ) ") 102 .toString() 103 }; 104 } 105 106 public String [] sqlDropStrings(Dialect dialect) throws HibernateException { 107 StringBuffer sqlDropString = new StringBuffer () 108 .append("drop table "); 109 if ( dialect.supportsIfExistsBeforeTableName() ) sqlDropString.append("if exists "); 110 sqlDropString.append(tableName) 111 .append( dialect.getCascadeConstraintsString() ); 112 if ( dialect.supportsIfExistsAfterTableName() ) sqlDropString.append(" if exists"); 113 return new String [] { sqlDropString.toString() }; 114 } 115 116 public Object generatorKey() { 117 return tableName; 118 } 119 120 public Serializable doWorkInCurrentTransaction(Connection conn, String sql) throws SQLException { 121 int result; 122 int rows; 123 do { 124 128 SQL.debug(query); 130 PreparedStatement qps = conn.prepareStatement(query); 131 PreparedStatement ips = null; 132 try { 133 ResultSet rs = qps.executeQuery(); 135 boolean isInitialized = rs.next(); 136 if ( !isInitialized ) { 137 result = 0; 138 ips = conn.prepareStatement(insert); 139 ips.setInt(1, result); 141 ips.execute(); 142 } 143 else { 144 result = rs.getInt(1); 145 } 146 rs.close(); 147 } 148 catch (SQLException sqle) { 149 log.error("could not read or init a hi value", sqle); 150 throw sqle; 151 } 152 finally { 153 if (ips != null) { 154 ips.close(); 155 } 156 qps.close(); 157 } 158 159 PreparedStatement ups = conn.prepareStatement(update); 161 try { 162 ups.setInt( 1, result + 1 ); 163 ups.setInt( 2, result ); 164 rows = ups.executeUpdate(); 166 } 167 catch (SQLException sqle) { 168 log.error("could not update hi value in: " + tableName, sqle); 169 throw sqle; 170 } 171 finally { 172 ups.close(); 173 } 174 } 175 while (rows==0); 176 return new Integer (result); 177 } 178 179 public synchronized Serializable generate(SessionImplementor session, Object obj) 180 throws HibernateException { 181 if (lo>maxLo) { 182 int hival = ( (Integer ) doWorkInNewTransaction(session) ).intValue(); 183 lo = (hival == 0) ? 1 : 0; 184 hi = hival * (maxLo+1); 185 log.debug("new hi value: " + hival); 186 } 187 188 return IdentifierGeneratorFactory.createNumber( hi + lo++, returnClass ); 189 } 190 191 public void configure(Type type, Properties params, Dialect dialect) throws MappingException { 192 this.tableName = PropertiesHelper.getString(ID_TABLE, params, DEFAULT_TABLE); 193 this.pkColumnName = PropertiesHelper.getString(PK_COLUMN_NAME, params, DEFAULT_PK_COLUMN); 194 this.valueColumnName = PropertiesHelper.getString(VALUE_COLUMN_NAME, params, DEFAULT_VALUE_COLUMN); 195 String schemaName = params.getProperty(SCHEMA); 196 String catalogName = params.getProperty(CATALOG); 197 this.keySize = PropertiesHelper.getInt(PK_LENGTH_NAME, params, DEFAULT_PK_LENGTH); 198 String keyValue = PropertiesHelper.getString(PK_VALUE_NAME, params, params.getProperty(TABLE) ); 199 200 if ( tableName.indexOf( dialect.getSchemaSeparator() )<0 ) { 201 tableName = Table.qualify( catalogName, schemaName, tableName, dialect.getSchemaSeparator() ); 202 } 203 204 query = "select " + 205 valueColumnName + 206 " from " + 207 dialect.appendLockHint(LockMode.UPGRADE, tableName) + 208 " where " + pkColumnName + " = '" + keyValue + "'" + 209 dialect.getForUpdateString(); 210 211 update = "update " + 212 tableName + 213 " set " + 214 valueColumnName + 215 " = ? where " + 216 valueColumnName + 217 " = ? and " + 218 pkColumnName + 219 " = '" + 220 keyValue 221 + "'"; 222 223 insert = "insert into " + tableName + 224 "(" + pkColumnName + ", " + valueColumnName + ") " + 225 "values('"+ keyValue +"', ?)"; 226 227 228 maxLo = PropertiesHelper.getInt(MAX_LO, params, Short.MAX_VALUE); 230 lo = maxLo + 1; returnClass = type.getReturnedClass(); 232 } 233 } 234 | Popular Tags |