We run a Spring 3.1/Hibernate 4/Java 7/Tomcat 7/MSSQL 2008 R2 web application. We must deal with legacy data and archived data. When extracting data from an archive, we have a need to use the original unique identifier so that other (non-archived) records will re-hydrate correctly. These identifiers are stored in the primary key/auto increment field.
Prior to now, when we were using Spring 3.0/Hibernate 3.5, the following code worked to INSERT an extracted record back into its appropriate table (we already have the variables session
, entity
, and fullTableName
in scope):
session.doWork( new Work()
{
@Override
public void execute(Connection connection) throws SQLException
{
PreparedStatement statement = null;
try
{
statement = connection.prepareStatement(String.format("SET IDENTITY_INSERT %s ON", fullTableName));
statement.execute();
session.save(entity);
statement = connection.prepareStatement(String.format("SET IDENTITY_INSERT %s OFF", fullTableName));
statement.execute();
}
finally
{ /* close the statement */ }
}
});
Like I mentioned, this all worked fine in Hibernate 3.5, but now that we've upgraded to Hibernate 4, it has stopped working. Is there something up with the difference between Work and IsolatedWork?
In an effort to solve the problem, and avoid any Work interface issues, we tried the following:
session.createSQLQuery(String.format("SET IDENTITY_INSERT %s ON", fullTableName)).executeUpdate();
session.save(entity);
session.createSQLQuery(String.format("SET IDENTITY_INSERT %s OFF", fullTableName)).executeUpdate();
However, this did not work either. Specifically, the exception that gets thrown is java.sql.SQLException: Cannot insert explicit value for identity column in table 'Employee' when IDENTITY_INSERT is set to OFF.
Yet, it should be clear that we're going through pains to set it ON.
We did a SQL Server Profiler trace of the situation, and found something interesting. Something is setting IMPLICIT_TRANSACTIONS ON in each of our transaction bodies. Here's some sample output from the Profiler trace (I've replaced our actual schema with <schema>
, and some large bits of data with shorter labels):
SET IMPLICIT_TRANSACTIONS ON
go
declare @p1 int
set @p1=55
exec sp_prepare @p1 output,N'',N'SET IDENTITY_INSERT <schema>.Employee ON',1
select @p1
go
exec sp_execute 55
go
declare @p1 int
set @p1=56
exec sp_prepare @p1 output,N'<parameters for the INSERT>',N'insert into <schema>.Employee (<all the column names>) values ( <all the parameters> )',1
select @p1
go
exec sp_execute 56,<the actual values to insert>
go
IF @@TRANCOUNT > 0 ROLLBACK TRAN
go
IF @@TRANCOUNT > 0 COMMIT TRAN
SET IMPLICIT_TRANSACTIONS OFF
go
exec sp_execute 54,N'Error writing EMPLOYEE archive record. ',<an id>,N'1'
go
Now, we are specifically setting IMPLICIT_TRANSACTIONS to be OFF, via Connection.setAutoCommit(false) in our transaction (transactions are being managed via Spring @Transactional and Hibernate Transaction Manager). Obviously, that is not working, but what are the alternatives apart from using setAutoCommit, and why would it work in Spring3.0/Hibernate 3.5 but not Spring 3.1/Hibernate 4?
Thanks for any thoughts or suggestions - we're stumped.