7

Spring 3.1 / Hibernate 4 / Java 7 / Tomcat 7 / MSSQL 2008R2Webアプリケーションを実行します。レガシーデータとアーカイブデータを処理する必要があります。アーカイブからデータを抽出するときは、他の(アーカイブされていない)レコードが正しく再水和されるように、元の一意の識別子を使用する必要があります。これらの識別子は、主キー/自動増分フィールドに格納されます。

これまで、Spring 3.0 / Hibernate 3.5を使用していたとき、次のコードは、抽出されたレコードを適切なテーブルに挿入し直すために機能しました(すでに変数、、、sessionおよびentityスコープfullTableNameがあります)。

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の違いに何か問題はありますか?

問題を解決し、Workインターフェイスの問題を回避するために、次のことを試みました。

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.まだですが、それをオンに設定するのに苦労していることは明らかです。

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

現在、トランザクションのConnection.setAutoCommit(false)を介してIMPLICIT_TRANSACTIONSをOFFに設定しています(トランザクションはSpring@TransactionalおよびHibernateTransaction Managerを介して管理されています)。明らかに、それは機能していませんが、setAutoCommitを使用する以外の選択肢は何ですか?また、Spring3.0 /Hibernate3.5では機能するのにSpring3.1/ Hibernate4では機能しないのはなぜですか?

考えや提案をありがとう-私たちは困惑しています。

4

1 に答える 1

2

まあ、それは微妙な解決策でした...

Work呼び出しはjava.sql.PreparedStatement内部的に使用され、次にexecute()メソッドを呼び出しました。明らかに、これは、いくつかのコードサンプルが示すように、SQLServerにコマンドを独自のストアドプロシージャでラップするように指示します。

aを使用するPreparedStatementことから単にaに変更し、そのメソッドjava.sql.Statementを呼び出します。execute()

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!の呼び出しに必要なものです。

レッスン:スカムと極悪のじんましんがたくさんあります...私たちは注意する必要があります!

于 2012-10-22T19:24:43.543 に答える