2012-10-16 13 views
7

Wir betreiben eine Spring 3.1/Hibernate 4/Java 7/Tomcat 7/MSSQL 2008 R2 Webanwendung. Wir müssen mit Altdaten und archivierten Daten umgehen. Beim Extrahieren von Daten aus einem Archiv müssen wir den ursprünglichen eindeutigen Bezeichner verwenden, damit andere (nicht archivierte) Datensätze richtig hydriert werden. Diese Bezeichner werden im Feld Primärschlüssel/Autoinkrement gespeichert.Hibernate 3.5 vs 4 IDENTITY_INSERT Probleme

Vor jetzt, wo wir Frühling mit wurden 3.0/3.5 Hibernate, der folgende Code verarbeitet, um einen extrahierten Datensatz wieder in die entsprechende Tabelle einzufügen (wir haben bereits die Variablen session, entity und fullTableName in scope):

Wie schon erwähnt, hat dies alles in Hibernate 3.5 funktioniert, aber jetzt, wo wir auf Hibernate 4 aktualisiert haben, funktioniert es nicht mehr. Gibt es etwas mit dem Unterschied zwischen Work und IsolatedWork?

In dem Bemühen, das Problem zu lösen, und alle Arbeits Schnittstelle Probleme zu vermeiden, haben wir versucht, die folgenden:

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(); 

Dies ist jedoch entweder nicht funktioniert hat. Genauer gesagt, die Ausnahme, die ausgelöst wird, ist java.sql.SQLException: Cannot insert explicit value for identity column in table 'Employee' when IDENTITY_INSERT is set to OFF.. Es sollte jedoch klar sein, dass wir uns Mühe geben, es AN zu setzen.

Wir haben eine SQL Server Profiler Spur der Situation, und etwas interessantes gefunden. Etwas setzt IMPLICIT_TRANSACTIONS in jedem unserer Transaktionskörper auf ON. Hier einige Beispielausgabe des Profiler-Ablaufverfolgung (Ich habe unsere tatsächlichen Schema mit <schema> ersetzt, und einige große Daten-Bits mit kürzeren Etiketten):

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 

Nun sind wir speziell IMPLICIT_TRANSACTIONS Einstellung OFF sein, über den Verbindungs .setAutoCommit (false) in unserer Transaktion (Transaktionen werden über Spring @Transactional und Hibernate Transaction Manager verwaltet). Offensichtlich funktioniert das nicht, aber was sind die Alternativen abgesehen von der Verwendung von setAutoCommit, und warum würde es in Spring3.0/Hibernate 3.5 funktionieren, aber nicht in Spring 3.1/Hibernate 4?

Danke für irgendwelche Gedanken oder Vorschläge - wir sind ratlos.

Antwort

2

Nun, es war eine subtile Lösung ...

Unsere Arbeit Anruf ein java.sql.PreparedStatement intern verwendet, und wir riefen dann die execute() Methode. Anscheinend weist dies SQL Server an, den Befehl in einer eigenen gespeicherten Prozedur zu umbrechen, wie einige der Codebeispiele zeigen.

Wir wechselten von der Verwendung eines PreparedStatement einfach eine java.sql.Statement und ruft seine execute() Methode:

session.doWork(new Work() 
{ 
    @Override 
    public void execute(Connection connection) throws SQLException 
    { 
     Statement statement = null; 
     try 
     { 
      statement = connection.createStatement(); 
      statement.execute(String.format("SET IDENTITY_INSERT %s ON", fullTableName)); 

      session.save(entity); 

      statement = connection.createStatement(); 
      statement.execute(String.format("SET IDENTITY_INSERT %s OFF", fullTableName)); 
     } 
     finally 
     { /* close the statement */ } 
    } 
}); 

Also, was ist der Unterschied? Soweit wir das beurteilen können, generiert die PreparedStatement vorkompilierten SQL, während die Statement statische SQL erzeugt ... genau das, was wir für den Aufruf an IDENTITY_INSERT benötigten!

Lektion: Es gibt viele Bienenstöcke von Abschaum und Schurkerei ... wir müssen vorsichtig sein!

+0

Vielen Dank, das hat mir sehr viel Zeit gespart. –