简体   繁体   中英

Liquibase and distributed transactions across a linked server, SQL Server 2019

A technical question concerning distributed transactions via a SQL Server "linked server" definition, using Liquibase.

background/context :

  • SQL script is being run by Liquibase, through a changelog file.
  • SQL Server 2019
  • Oracle 11g Express on the far side of the db link RPTDB_XE.
  • MSDTC is turned off on the SQL Server host.

liquibase.properties

classpath=C:\\Program Files\\Microsoft SQL Server\\sqljdbc_10.2\\enu\\mssql-jdbc-10.2.0.jre8.jar
driver=com.microsoft.sqlserver.jdbc.SQLServerDriver
url=jdbc:sqlserver://localhost:1433;database=SSReporting;Enlist=false
liquibaseSchemaName=dbo
username=deploy_dbbuild
password=deploy_dbbuild
changeLogFile=changelog.xml
liquibase.hub.mode=off
integratedSecurity=false

changelog.xml

<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
         http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-2.0.xsd">

    <changeSet runOnChange="true" author="smcintosh" id="dw-1042-distributed-trans-error-v2.sql">
        <sqlFile path="dw-1042-distributed-trans-error-v2.sql" relativeToChangelogFile="true" endDelimiter="GO"/>
    </changeSet>

</databaseChangeLog>

dw-1042-distributed-trans-error-v2.sql

use SSReporting
go
set xact_abort on;
go
set nocount on;
go
begin
    -- distributed transaction test
    print formatmessage('%s START: %s', convert(varchar(20),getdate(),20), convert(varchar(67),@@version));
    update RPTDB_XE..OWBTGT.DISTRIB_TRANSACTION_TEST_SCOTT set OBJECT_ID=OBJECT_ID+1;
    print formatmessage('%s Updated RPTDB_XE..OWBTGT.DISTRIB_TRANSACTION_TEST_SCOTT: %d rows', convert(varchar(20),getdate(),20), @@rowcount);

    insert into dbo.TASK_DETAIL_LOG (BATCH_ID, LOG_DTM, CATEGORY, SEVERITY, ACTION, TASK, SUBTASK, MSG)
    values (0,getdate(),'DISTRIB_TRANS','INFO','LIQUIBASE_MIGRATE','PERFORMANCE',null,
        'DISTRIB_TRANSACTION_TEST_SCOTT has been updated.');
    print formatmessage('%s Inserted dbo.TASK_DETAIL_LOG : %d rows',convert(varchar(20),getdate(),20), @@rowcount);
    print formatmessage('%s END', convert(varchar(20),getdate(),20));
end;
go

Run the script manually to verify that it works, using sqlcmd...

C:\>sqlcmd -Usa -Pxxxx -S tcp:SCOTT-MCINTOSH,1433 -dSSReporting -w 1000 -i dw-1042-distributed-trans-error-v2.sql
Changed database context to 'SSReporting'.
2022-03-23 13:52:08 START: Microsoft SQL Server 2019 (RTM-GDR) (KB4583458) - 15.0.2080.9 (X64)
2022-03-23 13:52:08 Updated RPTDB_XE..OWBTGT.DISTRIB_TRANSACTION_TEST_SCOTT: 3 rows
2022-03-23 13:52:08 Inserted dbo.TASK_DETAIL_LOG : 1 rows
2022-03-23 13:52:08 END

Run the script using Liquibase...

C:\>liquibase --defaults-file=liquibase.properties update
####################################################
##   _     _             _ _                      ##
##  | |   (_)           (_) |                     ##
##  | |    _  __ _ _   _ _| |__   __ _ ___  ___   ##
##  | |   | |/ _` | | | | | '_ \ / _` / __|/ _ \  ##
##  | |___| | (_| | |_| | | |_) | (_| \__ \  __/  ##
##  \_____/_|\__, |\__,_|_|_.__/ \__,_|___/\___|  ##
##              | |                               ##
##              |_|                               ##
##                                                ##
##  Get documentation at docs.liquibase.com       ##
##  Get certified courses at learn.liquibase.com  ##
##  Free schema change activity reports at        ##
##      https://hub.liquibase.com                 ##
##                                                ##
####################################################
Starting Liquibase at 13:55:46 (version 4.8.0 #1581 built at 2022-02-18 21:43+0000)
Liquibase Version: 4.8.0
Liquibase Community 4.8.0 by Liquibase
Running Changeset: changelog.xml::dw-1042-distributed-trans-error-v2.sql::smcintosh

Unexpected error running Liquibase: MSDTC on server 'SCOTT-MCINTOSH' is unavailable. [Failed SQL: (8501) begin
        -- distributed transaction test
        print formatmessage('%s START: %s', convert(varchar(20),getdate(),20), convert(varchar(67),@@version));
        update RPTDB_XE..OWBTGT.DISTRIB_TRANSACTION_TEST_SCOTT set OBJECT_ID=OBJECT_ID+1;
        print formatmessage('%s Updated RPTDB_XE..OWBTGT.DISTRIB_TRANSACTION_TEST_SCOTT: %d rows', convert(varchar(20),getdate(),20), @@rowcount);

        insert into dbo.TASK_DETAIL_LOG (BATCH_ID, LOG_DTM, CATEGORY, SEVERITY, ACTION, TASK, SUBTASK, MSG)
        values (0,getdate(),'DISTRIB_TRANS','INFO','LIQUIBASE_MIGRATE','PERFORMANCE',null,
                'DISTRIB_TRANSACTION_TEST_SCOTT has been updated.');
        print formatmessage('%s Inserted dbo.TASK_DETAIL_LOG : %d rows',convert(varchar(20),getdate(),20), @@rowcount);
        print formatmessage('%s END', convert(varchar(20),getdate(),20));
end;]

For more information, please use the --log-level flag

The Question :
Why can't Liquibase run this script, when sqlcmd can? In fact, other database tools like TOAD and DataGrip can also successfully run this script, and they too use a JDBC connection, just like Liquibase.

I can see that you're running the sqlFile change type in your changelog. Liquibase has two different modes of operation. The first splits commands on the delimiter (I see you set it to GO) and executes each statement via a JDBC call to the database. However, in your script the commands are not database commands, they are SQLCMD commands. When those statements get executed on the database they will fail.

However, I found this page on the Liquibase docs site that explains the second mode of operation, which is how to run native SQLCMD scripts via Liquibase.

https://docs.liquibase.com/concepts/changelogs/attributes/using-sqlcmd-integration.html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM