Ora*_*bat 7 hibernate transactions implicit identity-insert
我们运行Spring 3.1/Hibernate 4/Java 7/Tomcat 7/MSSQL 2008 R2 Web应用程序.我们必须处理遗留数据和归档数据.从存档中提取数据时,我们需要使用原始唯一标识符,以便其他(非存档)记录能够正确地重新水合.这些标识符存储在主键/自动增量字段中.
在此之前,现在,当我们在使用Spring 3.0/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 */ }
}
});
Run Code Online (Sandbox Code Playgroud)
就像我提到的,这在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();
Run Code Online (Sandbox Code Playgroud)
但是,这也不起作用.具体来说,抛出的异常是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.以下是Profiler跟踪的一些示例输出(我用<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
Run Code Online (Sandbox Code Playgroud)
现在,我们通过事务中的Connection.setAutoCommit(false)专门将IMPLICIT_TRANSACTIONS设置为OFF(事务通过Spring @Transactional和Hibernate事务管理器进行管理).显然,这不起作用,但除了使用setAutoCommit之外还有什么替代方案,为什么它可以在Spring3.0/Hibernate 3.5中工作,而不是Spring 3.1/Hibernate 4?
感谢您的任何想法或建议 - 我们很难过.
嗯,这是一个微妙的解决方案......
我们的 Work 调用java.sql.PreparedStatement在内部使用了 a,然后我们调用了该execute()方法。显然,这告诉 SQL Server 将命令包装在它自己的存储过程中,如一些代码示例所示。
我们从使用 a 改为PreparedStatement简单的 ajava.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 */ }
}
});
Run Code Online (Sandbox Code Playgroud)
那么,有什么区别呢?据我们所知,PreparedStatement生成预编译的 SQL,而Statement生成静态 SQL...正是我们调用所需的IDENTITY_INSERT!
教训:败类和恶行层出不穷……我们必须小心谨慎!
| 归档时间: |
|
| 查看次数: |
2981 次 |
| 最近记录: |