Uruchamiamy aplikację internetową Spring 3.1/Hibernate 4/Java 7/Tomcat 7/MSSQL 2008 R2. Musimy radzić sobie ze starszymi danymi i zarchiwizowanymi danymi. Podczas wyodrębniania danych z archiwum potrzebujemy użyć oryginalnego unikalnego identyfikatora, aby inne (niezarchiwizowane) rekordy zostały poprawnie nawodnione. Te identyfikatory są przechowywane w polu klucz główny/auto increment.Hibernate 3.5 vs 4 IDENTITY_INSERT issues
Przed teraz, kiedy używaliśmy Wiosna 3.0/Hibernate 3.5, następujący kod pracował wstawić wyodrębniony zapis z powrotem do odpowiedniej tabeli (mamy już zmienne session
, entity
i fullTableName
w zakresie):
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 */ }
}
});
Tak jak wspomniałem, wszystko działało poprawnie w Hibernate 3.5, ale po przejściu na Hibernate 4 przestało działać. Czy jest jakaś różnica między Work a IsolatedWork?
W celu rozwiązania tego problemu, i uniknąć wszelkich problemów interfejsu Praca, staraliśmy się, co następuje:
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();
Jednak to nie działało. W szczególności wyjątek, który zostanie rzucony, to java.sql.SQLException: Cannot insert explicit value for identity column in table 'Employee' when IDENTITY_INSERT is set to OFF.
. Jednak powinno być jasne, że przechodzimy przez bóle, aby go włączyć.
Zrobiliśmy ślad programu SQL Server Profiler i znaleźliśmy coś interesującego. W każdej z naszych ciał transakcji jest ustawiona opcja IMPLICIT_TRANSACTIONS. Oto niektóre przykładowe dane wyjściowe od śladu Profiler (mam zastąpić nasz rzeczywisty schemat z <schema>
, a niektóre duże bitów danych o krótszych etykiet):
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
Teraz jesteśmy specjalnie ustawienie IMPLICIT_TRANSACTIONS być wyłączony, poprzez połączenia .setAutoCommit (false) w naszej transakcji (transakcje są zarządzane przez Spring @ Transactional i Hibernate Transaction Manager). Oczywiście, to nie działa, ale jakie są alternatywy oprócz używania setAutoCommit i dlaczego miałoby działać w Spring3.0/Hibernate 3.5, ale nie Spring 3.1/Hibernate 4?
Dzięki za wszelkie przemyślenia lub sugestie - jesteśmy zaskoczeni.
Dziękuję bardzo, na pewno zaoszczędziłem mi dużo czasu. –