JTDS 和交易
Posted
技术标签:
【中文标题】JTDS 和交易【英文标题】:JTDS and Transactions 【发布时间】:2014-11-06 20:17:45 【问题描述】:当我直接从 SSMS 调用存储过程 (MSSQL 2008R2) 或从 JTDS 调用它时,我会看到不同的行为。
首先,请看这两个程序。
CREATE PROCEDURE [Template].[UnguardedTest]
@outparam_StartTransactionCount INT OUTPUT,
@outparam_TransactionCount INT OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
DECLARE @StartTranCount INT
SELECT @StartTranCount = @@TRANCOUNT
BEGIN TRANSACTION
BEGIN
SELECT @outparam_StartTransactionCount = @StartTranCount
SELECT @outparam_TransactionCount = @@TRANCOUNT
END
COMMIT TRANSACTION
END
第二个与第一个非常相似,除了它不会开始(或提交)事务,除非条目上的@@TRANCOUNT
为 0。
CREATE PROCEDURE [Template].[GuardedTest]
@outparam_StartTransactionCount INT OUTPUT,
@outparam_TransactionCount INT OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
DECLARE @StartTranCount INT
-- Record the @@TRANCOUNT at the beginning of this procedure / trigger.
SELECT @StartTranCount = @@TRANCOUNT
IF @StartTranCount = 0
BEGIN TRANSACTION
BEGIN
SELECT @outparam_StartTransactionCount = @StartTranCount
SELECT @outparam_TransactionCount = @@TRANCOUNT
END
IF @StartTranCount = 0
COMMIT TRANSACTION
END
如果我从 SSMS 调用它们,请使用以下代码
DECLARE @outparam_TransactionCount INT
DECLARE @outparam_StartTransactionCount INT
EXECUTE [Template].[UnguardedTest] @outparam_StartTransactionCount OUTPUT, @outparam_TransactionCount OUTPUT
SELECT 'UNGUARDED_NOT_WRAPPED' AS Description, @outparam_StartTransactionCount AS [StartTranCount], @outparam_TransactionCount AS [TranCount]
BEGIN TRAN
EXECUTE [Template].[UnguardedTest] @outparam_StartTransactionCount OUTPUT, @outparam_TransactionCount OUTPUT
SELECT 'UNGUARDED_WRAPPED' AS Description, @outparam_StartTransactionCount AS [StartTranCount], @outparam_TransactionCount AS [TranCount]
COMMIT TRAN
EXECUTE [Template].[GuardedTest] @outparam_StartTransactionCount OUTPUT, @outparam_TransactionCount OUTPUT
SELECT 'GUARDED_NOT_WRAPPED' AS Description, @outparam_StartTransactionCount AS [StartTranCount], @outparam_TransactionCount AS [TranCount]
BEGIN TRAN
EXECUTE [Template].[GuardedTest] @outparam_StartTransactionCount OUTPUT, @outparam_TransactionCount OUTPUT
SELECT 'GUARDED_WRAPPED' AS Description, @outparam_StartTransactionCount AS [StartTranCount], @outparam_TransactionCount AS [TranCount]
COMMIT TRAN
输出是我所期望的。
Description StartTranCount TranCount
--------------------- -------------- -----------
UNGUARDED_NOT_WRAPPED 0 1
Description StartTranCount TranCount
----------------- -------------- -----------
UNGUARDED_WRAPPED 1 2
Description StartTranCount TranCount
------------------- -------------- -----------
GUARDED_NOT_WRAPPED 0 1
Description StartTranCount TranCount
--------------- -------------- -----------
GUARDED_WRAPPED 1 1
即在事务中包装对过程的调用导致 StartTranCount 为 1,否则为零。
但是,当我通过 JTDS/JDBC 执行相同的过程时,按照下面的代码,我看到了奇怪的行为。
int tc = -1, startTC = -1;
final Connection con2 = DriverManager.getConnection(url);
con2.setAutoCommit(false);
final CallableStatement proc2 = con2.prepareCall(" call Template.GuardedTest(?,?) ");
proc2.registerOutParameter("@outparam_StartTransactionCount", Types.INTEGER);
proc2.registerOutParameter("@outparam_TransactionCount", Types.INTEGER);
proc2.execute();
startTC = proc2.getInt("@outparam_StartTransactionCount");
tc = proc2.getInt("@outparam_TransactionCount");
log.info("Guarded StartTC: " + startTC + ", TC: " + tc);
proc2.close();
con2.commit();
con2.close();
final Connection con1 = DriverManager.getConnection(url);
con1.setAutoCommit(false);
final CallableStatement proc1 = con1.prepareCall(" call Template.UnguardedTest(?,?) ");
proc1.registerOutParameter("@outparam_StartTransactionCount", Types.INTEGER);
proc1.registerOutParameter("@outparam_TransactionCount", Types.INTEGER);
proc1.execute();
startTC = proc1.getInt("@outparam_StartTransactionCount");
tc = proc1.getInt("@outparam_TransactionCount");
log.info("Unguarded StartTC: " + startTC + ", TC: " + tc);
proc1.close();
con1.commit();
con1.close();
我看到以下输出:
- Guarded StartTC: 0, TC: 2
- Unguarded StartTC: 0, TC: 2
正如我期望看到与上面的“包装”示例相同的值(据我所知,JDBC 在调用 setAutoCommit(false)
时会开始一个新事务,我真的不知道发生了什么。任何洞察力?
附加信息:
如果我切换到 Microsoft JDBC 驱动程序,我会得到预期的结果
MSFT Driver - Guarded StartTC: 1, TC: 1
MSFT Driver - Unguarded StartTC: 1, TC: 2
【问题讨论】:
【参考方案1】:我发现了这种行为的原因。
我假设 jTDS 在调用 setAutoCommit(false)
之后明确地开始了连接事务。事实上,它的行为并非如此。它所做的是在连接上发出SET IMPLICIT_TRANSACTIONS ON
。
根据 Microsoft (http://msdn.microsoft.com/en-us/library/ms187807.aspx) - “当 IMPLICIT_TRANSACTIONS = ON 时,显式 BEGIN TRANSACTION 将启动两个嵌套事务。”
例如,如果我们在 SSMS 中执行以下操作
SET IMPLICIT_TRANSACTIONS ON
EXECUTE [Template].[UnguardedTest] @outparam_StartTransactionCount OUTPUT, @outparam_TransactionCount OUTPUT
SELECT 'UNGUARDED_IMPLICIT' AS Description, @outparam_StartTransactionCount AS [StartTranCount], @outparam_TransactionCount AS [TranCount]
COMMIT TRAN
SET IMPLICIT_TRANSACTIONS ON
EXECUTE [Template].[GuardedTest] @outparam_StartTransactionCount OUTPUT, @outparam_TransactionCount OUTPUT
SELECT 'GUARDED_IMPLICIT' AS Description, @outparam_StartTransactionCount AS [StartTranCount], @outparam_TransactionCount AS [TranCount]
COMMIT TRAN
我们得到以下信息:
Description StartTranCount TranCount
------------------ -------------- -----------
UNGUARDED_IMPLICIT 0 2
Description StartTranCount TranCount
---------------- -------------- -----------
GUARDED_IMPLICIT 0 2
这与我们在 jTDS 执行这些程序时得到的输出一致。
【讨论】:
以上是关于JTDS 和交易的主要内容,如果未能解决你的问题,请参考以下文章