我正在尝试使用与SQL Server 2008 R2数据库通信的Java应用程序。应用程序将数据导入数据库,它具有“测试模式”;数据库请求被包装在一个事务中,该事务在最后回滚。
使用特定数据集,该工具会禁用触发器,然后在导入后重新启用它。在测试模式下,在第一次传递时,一切都按预期工作 - '导入'中的数据集没有问题。但是,如果我尝试重复练习,应用程序会在尝试禁用触发器时挂起。
查看SQL事件探查器,我可以看到RPC:已完成的跟踪项,这表明SQL Server已收到并成功处理了请求。在这一点上,我希望Java应用程序能够获得控制并继续 - 除非它没有,我正在努力思考下一步该在哪里。
Java代码:
String sql = "ALTER TABLE MyTable DISABLE TRIGGER ALL";
PreparedStatement stmt = mDBConnection.prepareStatement (sql);
stmt.execute();
跟踪文字数据:
declare @p1 int
set @p1=1
exec sp_prepare @p1 output,N'',N'ALTER TABLE MyTable DISABLE TRIGGER ALL',1
select @p1
问:知道问题可能是什么?或者有关我如何进一步调查的任何建议?
更新: 当然,上面的跟踪仅显示sp_prepare。有一个相应的sp_execute语句 - 缺少RPC:Completed trace项,表明问题出在SQL Server端。修改后的跟踪显示RPC:Starting条目('exec sp_execute 1'),但没有匹配的RPC:已完成。
我可以运行sp_prepare& SSMS中的sp_execute(假设我删除了set语句),正如预期的那样 - 它在第一次传递后执行OK。
解决方案: 使用sp_who2(见下文),我可以看到第一个连接/ spid被阻塞了第二个;在提交时,数据库连接已关闭,但在回滚时则没有。由于我在测试和回滚模式下运行,这是我的问题的关键 - 关闭连接解决了问题。
sp_who2:
CREATE TABLE #sp_who2
(
SPID INT,
Status VARCHAR(1000) NULL,
Login SYSNAME NULL,
HostName SYSNAME NULL,
BlkBy SYSNAME NULL,
DBName SYSNAME NULL,
Command VARCHAR(1000) NULL,
CPUTime INT NULL,
DiskIO INT NULL,
LastBatch VARCHAR(1000) NULL,
ProgramName VARCHAR(1000) NULL,
SPID2 INT,
RequestID int
)
GO
INSERT INTO #sp_who2 EXEC sp_who2
GO
SELECT spid, status, blkby, command, ProgramName FROM #sp_who2 WHERE DBName = 'rio7_bch_test'
GO
DROP TABLE #sp_who2
GO
答案 0 :(得分:1)
请勿使用PreparedStatement
。只使用普通Statement
。
Statement stmt = mDBConnection.createStatement(sql);
答案 1 :(得分:1)
“ALTER TABLE”语句是DDL(数据定义语言)。 DDL必须等待所有DML(数据操作语言)语句完成。如果您有一个未关闭的ResultSet,Statement或PreparedStatement正在查询该表或该表上的视图,或者该表的连接,或者关闭自动提交更新 - 那么这就是DML不完整。
在像这样更改表之前,请确保已明确关闭其上打开的每个可能结果集,以及类似的任何语句。这将确保所有DML都完整并且可以执行DDL。
通常,最好使用PreparedStatements over Statements。 PreparedStatement编译一次。每次执行时都有一个语句。这意味着像您这样的非参数化语句没有区别,并且对于任何一次参数化都有潜在的好处。
假设一个受信任的JDBC实现,当PreparedStatement没有时,Statement就没有时间可以工作。
您可能还会发现this question有帮助。
答案 2 :(得分:1)
这听起来好像你有没有正确发布的锁并阻止你的DDL执行。
当语句挂起时,运行存储过程sp_who2
。
在该程序的结果中,您将阻止您的DDL,然后您可以采取适当的行动。