如何创建具有快照隔离级别的 Flyway 模式历史记录?

Posted

技术标签:

【中文标题】如何创建具有快照隔离级别的 Flyway 模式历史记录?【英文标题】:How to create Flyway schema history with snapshot isolation level? 【发布时间】:2021-02-19 02:11:38 【问题描述】:

我正在调查是否可以在我一直从事的项目中使用 Flyway 进行数据库架构迁移……数据库迁移是手动完成的,我真的很想开始使用 Flyway。

这是一个 Spring Boot (v2.2.0) 应用程序,我正在尝试使用 Flyway 版本 v.7.1.1 配置迁移。

我已从数据库生成现有架构并将其设置为 V1 基本版本。但是,当尝试运行应用程序时(使用 baseline-on-migrate: true),迁移由于异常而失败:

Caused by: org.flywaydb.core.internal.sqlscript.FlywaySqlScriptException: 
Migration  failed
-----------------
SQL State  : S0001
Error Code : 3964
Message    : Transaction failed because this DDL statement is not allowed inside a snapshot isolation transaction. Since metadata is not versioned, a metadata change can lead to inconsistency if mixed within snapshot isolation.
Location   :  ()
Line       : 1
Statement  : CREATE TABLE [TestDB].[dbo].[flyway_schema_history] (
    [installed_rank] INT NOT NULL,
    [version] NVARCHAR(50),
    [description] NVARCHAR(200),
    [type] NVARCHAR(20) NOT NULL,
    [script] NVARCHAR(1000) NOT NULL,
    [checksum] INT,
    [installed_by] NVARCHAR(100) NOT NULL,
    [installed_on] DATETIME NOT NULL DEFAULT GETDATE(),
    [execution_time] INT NOT NULL,
    [success] BIT NOT NULL
);

从应用配置来看,HikariCP 数据源配置设置为使用:

事务隔离:TRANSACTION_SQL_SERVER_SNAPSHOT_ISOLATION_LEVEL

如果事务隔离更改为例如TRANSACTION_READ_COMMITTED 迁移成功。我可以按预期执行所有其他迁移。 软件架构师告诉我快照隔离级别背后的原因是因为应用程序用于生成大量报告,这可能需要几个小时,而快照隔离级别“保护我们免受应用程序冻结和锁定”。

我尝试通过创建回调来解决这个问题,我可以在运行时、beforeMigrate 和 afterMigrate Java 回调中更改事务隔离,但在运行时无法更改 HikariDataSource 配置。

有人可以提供一些建议,是否可以通过快照隔离进行迁移(和创建基线架构)?

【问题讨论】:

【参考方案1】:

我非常喜欢 SQL Server 中的快照隔离,但它并不适合作为所有部署的隔离级别。

以下是需要考虑的三个主要事项:

1。关于 DDL 和显式多语句事务的快照隔离限制

快照隔离非常有用,但是 SQL Server 确实限制了您可以使用它的用途,如错误消息所示:

事务失败,因为此 DDL 语句不允许在 快照隔离事务。由于元数据没有版本化,一个 如果在快照中混合元数据更改可能会导致不一致 隔离。

这不仅适用于创建 flyway_schema_history 表,SQL Server 也会将此规则应用于迁移脚本中的其他 DDL 更改。

更多信息在documentation here:

SQL Server 不支持元数据的版本控制。为此原因, DDL 操作可以在一个 在快照隔离下运行的显式事务。这 快照隔离下不允许以下 DDL 语句 在 BEGIN TRANSACTION 语句之后:ALTER TABLE、CREATE INDEX、CREATE XML 索引、更改索引、删除索引、DBCC 重新索引、更改分区 FUNCTION、ALTER PARTITION SCHEME 或任何公共语言运行时 (CLR) DDL 语句。

2。无论如何,DDL 操作都需要架构修改锁

此外,即使在快照隔离下,DDL 更改也需要高级架构修改锁 (SCH-M),这需要对表进行独占访问。这个in that same paper还有更多内容:

SQL Server 数据库引擎使用架构修改 (Sch-M) 锁 在表数据定义语言 (DDL) 操作期间,例如 添加列或删除表。举办期间, Sch-M 锁防止对表的并发访问。这意味着 Sch-M 锁会阻塞所有外部操作,直到锁被释放。

一些数据操作语言 (DML) 操作,例如表格 截断,使用 Sch-M 锁来防止访问受影响的表 并发操作。

换句话说,当涉及到您可能在迁移脚本中进行的任何 DDL 操作时,快照隔离不能/不会提供更少的阻塞和应用程序冻结。

3。如果你在数据修改上使用 Snapshot Iso,你需要准备好处理更新冲突

快照可用于更新 DML 语句中的数据,但它确实增加了复杂性,您需要为其添加错误处理。可能会发生更新冲突if data in a table may be modified by two processes at the same time:

如果数据行在快照事务之外被修改, 发生更新冲突,快照事务终止。 更新冲突由 SQL Server 数据库引擎和 无法禁用更新冲突检测。

快照隔离有什么帮助

根据您的说法,我认为应用程序/报告继续使用快照隔离是有意义的,但您可以从默认的已提交读隔离级别在 Flyway 中运行您的部署

只要应用程序/报告使用快照隔离,这意味着它们不会被您在 flyway 部署中执行的任何插入/更新/删除阻止。

您更改架构的任何 DDL 都可能会阻止报告。但是,在部署中使用快照隔离不会为您改变这一点——无论哪种方式,您都需要 SCH-M 锁。

肯德拉

【讨论】:

您好,肯德拉,感谢您的回复。它帮助我更好地理解了这个问题。但是,根据您的回答,我几乎没有假设我不确定是否正确。 1.这绝对意味着我不能将快照iso级别用于Flyway部署,由于上述SQL Server的异常? 2. 根据您的建议,我可以选择使用 READ_COMMITED 隔离级别,而在应用程序中,在有意义的情况下,在 @Transactional 注释中传递不同的隔离级别?让我感到困惑的是,当设置不同的 ISO 级别时会发生什么,一个是 RDBMS,另一个是 Hikari CP 您好——您可以使用 SNAPSHOT,但您需要在迁移脚本中围绕 SQL Server 允许的事务/语句类型将其设置为打开和关闭——例如:SET TRANSACTION ISOLATION快照; (和关闭)隔离级别特定于每个会话,您可以在整个会话期间更改它。 RDBMS 会影响默认隔离级别。不同的会话可能同时使用不同的隔离级别。希望有帮助!【参考方案2】:

我已经成功绕过应用程序的 Hikari 数据源隔离级别,方法是为 Flyway 迁移创建单独的数据源,其中事务隔离设置为 READ_COMMITED。 Flyway 迁移成功运行,并且未更改主数据源配置(使用 SNAPSHOT 隔离)。

@Bean
@FlywayDataSource
public DataSource flywayDataSource(@Autowired @Qualifier(value = "primaryDataSource") DataSource primaryDataSource) 
    HikariDataSource hds = (HikariDataSource) primaryDataSource;
    HikariConfig flywayHikariConfig = new HikariConfig();
    hds.copyStateTo(flywayHikariConfig);
    flywayHikariConfig.setTransactionIsolation(IsolationLevel.TRANSACTION_READ_COMMITTED.toString());
    return new HikariDataSource(flywayHikariConfig);

我无法在 ISO 级别发生更改的 Flyway 回调、Java 或 SQL 中应用类似的逻辑。 但是,我认为这可以通过在 some Flyway 配置 bean 上设置 @Transactional(isolation=Isolation.READ_COMMITTED) 以不同的方式完成,但我无法使其工作(例如尝试使用 FlywayMigrationStrategy)。

【讨论】:

以上是关于如何创建具有快照隔离级别的 Flyway 模式历史记录?的主要内容,如果未能解决你的问题,请参考以下文章

快照隔离级别是不是可以防止幻读?

Flyway:如何支持清理具有相同生命周期的多个模式?

MSSQL 数据库 - SQL Server2019创建数据库并关联表空间启用快照隔离级别实例演示,使用MSSM工具创建数据库

读取提交的快照 VS 快照隔离级别

MySQL--REPEATABLE-READ隔离级别下读取到的“重复数据”

在 SQL Server 视图中使用快照隔离级别