2012-10-16 65 views
7

我們運行Spring 3.1/Hibernate 4/Java 7/Tomcat 7/MSSQL 2008 R2 Web應用程序。我們必須處理遺留數據和歸檔數據。從檔案中提取數據時,我們需要使用原始的唯一標識符,以便其他(非歸檔)記錄能夠正確地重新提供水分。這些標識符存儲在主鍵/自動增量字段中。Hibernate 3.5 vs 4 IDENTITY_INSERT問題

到現在,當我們在使用Spring 3.0/Hibernate的3.5之前,下面的代碼工作中插入一個提取的記錄回其相應的表(我們已經有變量sessionentityfullTableName範圍):

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 */ } 
    } 
}); 

就像我剛纔提到的,這一切都在Hibernate 3.5中運行良好,但現在我們已經升級到Hibernate 4,它已停止工作。 Work和IsolatedWork之間有什麼不同?

在努力解決這個問題,並避免任何工作界面的問題,我們嘗試了以下內容:

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

不過,這也不能工作。具體來說,拋出的異常是java.sql.SQLException: Cannot insert explicit value for identity column in table 'Employee' when IDENTITY_INSERT is set to OFF.然而,應該清楚的是,我們正在努力將其設置爲ON。

我們做了一個SQL Server Profiler跟蹤情況,發現了一些有趣的事情。有些事情是在我們每個交易主體中設置IMPLICIT_TRANSACTIONS ON。下面是來自探查器跟蹤的一些示例輸出(我把它換成我們的實際模式與<schema>和數據用較短的標籤,一些大型位):

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 

現在,我們專門設置IMPLICIT_TRANSACTIONS爲OFF,通過連接.setAutoCommit(false)在我們的事務中(事務正在通過Spring @Transactional和Hibernate事務管理器進行管理)。顯然,這不起作用,但除了使用setAutoCommit之外,還有什麼替代方法,以及爲什麼它可以在Spring3.0/Hibernate 3.5中工作,而不是在Spring 3.1/Hibernate 4中工作?

感謝您的任何想法或建議 - 我們難住。

回答

2

嗯,這是一個微妙的解決方案......

我們的工作呼叫使用的java.sql.PreparedStatement內部,我們當時稱爲​​方法。顯然,這會告訴SQL Server將命令封裝在自己的存儲過程中,如一些代碼示例所示。

我們從使用PreparedStatement只需一個java.sql.Statement並調用其​​方法改變:

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 */ } 
    } 
}); 

那麼,有什麼區別?據我們所知,PreparedStatement生成預編譯的SQL,而Statement生成靜態SQL ...正是我們撥打IDENTITY_INSERT所需的東西!

教訓:有很多人渣和惡棍......我們必須謹慎小心!

+0

非常感謝,當然,這節省了我很多時間。 –