JTDS and Transactions



当我直接从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

我发现了这种行为的原因。

我假设在调用setAutoCommit(false)之后,jTDS显式地开始了连接的事务。事实上,它的行为并不是那样的。它所做的是在连接上发出SET IMPLICIT_TRANSACTIONS ON

根据微软的说法(http://msdn.microsoft.com/en-us/library/ms187807.aspx)-"当IMPLICIT_TRANSACTION=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执行这些过程时得到的输出一致。

最新更新