Hi there, due to our legacy database, we needed to create our own id generator to use a stored procedure that updates a row from a sequence number table.
We wanted this generator to have its own datasource and start its own transaction:
Code:
begin tran
execute stored procedure:
select next id from sequence number table
increment next id field in sequence number table
commit tran
We've run into cases before where our application takes too long to process requests that any other requests to this sequence number table is blocked because of it. We've previously solved it by creating our own id allocator class, but this time we wanted to try to use Hibernate's generator tag and specify our own class in the mapping file.
Does anyone know if the generator tag for the HBM file has attributes or any way of passing in a bean definition or parameters to set up the separate transaction and datasource ? (see payment.hbm.xml below).
I've attached the code chunks below for our ID generator.
We currently use the SingleConnectionDataSource datasource for this generator which isn't correct either as it's meant to only be used in testing :)
Hibernate version: 3.2.1 Spring version: 2.0 Name and version of the database you are using: Sybase ASE 12.5.3Mapping documents: Payment.hbm.xml Code:
...
<id name="productionRunId" column="production_run_id" unsaved-value="0" length="19">
<generator class="com.application.domainpersist.StoredProcedureGenerator">
<param name="sequenceId">payment_id</param>
</generator>
</id>
...
Generator code: StoredProcedureGenerator Code:
package com.application.domain.persist;
import java.io.Serializable;
import java.util.Properties;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.id.Configurable;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.type.Type;
import org.springframework.jdbc.datasource.SingleConnectionDataSource;
public class StoredProcedureGenerator implements IdentifierGenerator, Configurable {
protected static final String SEQUENCE_ID_PARAM = "sequenceId";
private Integer _sequenceId;
public Serializable generate(SessionImplementor session, Object object) throws HibernateException {
SequenceStoredProcedure storedProcedure = new SequenceStoredProcedure(
_sequenceId,
new SingleConnectionDataSource(session.connection(), true));
return storedProcedure.getNextSequenceNumber();
}
public void configure(Type type, Properties params, Dialect dialect) throws MappingException {
_sequenceId = (Integer) params.get(SEQUENCE_ID_PARAM);
if (_sequenceId == null) {
throw new MappingException("Missing required " + SEQUENCE_ID_PARAM + " parameter");
}
Class returnedClass = type.getReturnedClass();
if (!Integer.class.equals(returnedClass)) {
throw new MappingException("Cannot currently generate identifiers of type: " + returnedClass);
}
}
}
Generator code: SequenceStoredProcedure Code:
package com.application.domain.persist;
import java.io.Serializable;
import java.sql.Types;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.jdbc.core.SqlOutParameter;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.object.StoredProcedure;
public class SequenceStoredProcedure extends StoredProcedure {
private static final String GENERATE_SEQUENCE_STORED_PROC = "st_increment_sequence_number";
private static final String SEQUENCE_ID_PARAM = "p_sequence_id";
private static final String SEQUENCE_NUMBER_RANGE_PARAM = "p_sequence_num_range";
private static final String SEQUENCE_NUMBER_START = "p_sequence_number_start";
private static final String SEQUENCE_NUMBER_END = "p_sequence_number_end";
private Integer _sequenceId;
public SequenceStoredProcedure(Integer sequenceId, DataSource datasource) {
super(datasource, GENERATE_SEQUENCE_STORED_PROC);
_sequenceId = sequenceId;
declareParameter(new SqlParameter(SEQUENCE_ID_PARAM, Types.INTEGER));
declareParameter(new SqlParameter(SEQUENCE_NUMBER_RANGE_PARAM, Types.INTEGER));
declareParameter(new SqlOutParameter(SEQUENCE_NUMBER_START, Types.INTEGER));
declareParameter(new SqlOutParameter(SEQUENCE_NUMBER_END, Types.INTEGER));
}
public Serializable getNextSequenceNumber() {
ArrayList<Integer> sequenceNumbers = (ArrayList<Integer>) getNextRangeOfSequenceNumbers(1);
return new Integer(sequenceNumbers.get(1));
}
public Serializable getNextRangeOfSequenceNumbers(Integer range) {
Map<String, Integer> inParams = new HashMap<String, Integer>();
inParams.put(SEQUENCE_ID_PARAM, _sequenceId);
inParams.put(SEQUENCE_NUMBER_RANGE_PARAM, range);
Map resultSet = execute(inParams);
Integer sequenceNumberStart = (Integer) resultSet.get(SEQUENCE_NUMBER_START);
Integer sequenceNumberEnd = (Integer) resultSet.get(SEQUENCE_NUMBER_END);
ArrayList<Integer> numbers = new ArrayList<Integer>();
numbers.add(new Integer(sequenceNumberStart));
numbers.add(new Integer(sequenceNumberEnd));
return numbers;
}
}
[/code]