Tsql Transact-SQL迁移中出现错误时Flyway失败
将Flyway与Microsoft SQL Server结合使用时,我们注意到了上所述的问题 基本上,这样的迁移脚本不会在另一部分失败时回滚成功的Tsql Transact-SQL迁移中出现错误时Flyway失败,tsql,flyway,Tsql,Flyway,将Flyway与Microsoft SQL Server结合使用时,我们注意到了上所述的问题 基本上,这样的迁移脚本不会在另一部分失败时回滚成功的GO分隔的批: 开始交易 --创建一个包含两个可空列的表 创建表[dbo]。[t1]( [id][nvarchar](36)空, [姓名][nvarchar](36)空 ) --添加具有一个空列的行 插入[dbo].[t1]值(NEWID(),NULL) --将一列设置为不可为空 --由于上一次插入,此操作失败 ALTER TABLE[dbo].[t1
GO
分隔的批:
开始交易
--创建一个包含两个可空列的表
创建表[dbo]。[t1](
[id][nvarchar](36)空,
[姓名][nvarchar](36)空
)
--添加具有一个空列的行
插入[dbo].[t1]值(NEWID(),NULL)
--将一列设置为不可为空
--由于上一次插入,此操作失败
ALTER TABLE[dbo].[t1]ALTER COLUMN[name][nvarchar](36)不为空
去
--创建一个表作为下一个操作,以便测试回滚是否正确发生
创建表[dbo]。[t2](
[id][nvarchar](36)不为空
)
去
提交事务
在上面的示例中,即使前面的altertable
语句失败,仍将创建表t2
关于相关问题,提出了以下方法(飞行路线范围外):
- 动态SQL使得脚本很难阅读,这将非常不方便
-b
选项在出现错误时中止脚本
- 这在flyway中可用吗?
- flyway可能就是这样吗?是否有特定于飞道的配置来启用正确的故障排除错误?
编辑:备选示例 给定:简单数据库
开始交易
创建表[a](
[a_id][nvarchar](36)不为空,
[a_name][nvarchar](100)不为空
);
创建表[b](
[b_id][nvarchar](36)不为空,
[a_name][nvarchar](100)不为空
);
插入[a]值(NEWID(),'name-1');
插入[b]值(NEWID(),'name-1'),(NEWID(),'name-2');
提交事务
迁移脚本1(失败,未执行)
开始交易
ALTER TABLE[b]添加[a_id][nvarchar](36)NULL;
更新[b]从[a]设置[a\U id]=[a].[a\U id],其中[a].[a\U名称]=[b].[a\U名称];
ALTER TABLE[b]ALTER COLUMN[a_id][nvarchar](36)不为空;
ALTER TABLE[b]删除列[a_name];
提交事务
这将导致出现错误消息更新语句的列名“a\u id”无效。
。可能的解决方案:在语句之间引入
GO
迁移脚本2(使用GO:working for“happy case”,但在出现错误时仅进行部分回滚)
开始交易
将XACT_中止设置为ON
去
ALTER TABLE[b]添加[a_id][nvarchar](36)NULL;
去
更新[b]从[a]设置[a\U id]=[a].[a\U id],其中[a].[a\U名称]=[b].[a\U名称];
去
ALTER TABLE[b]ALTER COLUMN[a_id][nvarchar](36)不为空;
去
ALTER TABLE[b]删除列[a_name];
去
提交事务
- 只要表
中的所有值在表[b]
中都有匹配的条目,就可以执行所需的迁移[a]
- 在给定的示例中,情况并非如此。即,我们得到两个错误:
- 应为:
无法将值NULL插入到“test.dbo.b”表的“a_id”列中;列不允许空值。更新失败。
- 意外:
提交事务请求没有相应的开始事务。
- 可怕的是:最后一个
语句实际上已执行、提交且未回滚。也就是说,由于链接列丢失,以后无法修复此问题ALTER TABLE[b]DROP COLUMN[a_name]
- 应为:
- 将XACT_ABORT设置为ON(默认情况下为off)。此设置“指定当Transact-SQL语句引发运行时错误时,SQL Server是否自动回滚当前事务”
- 在您发送的每个批定界符后检查@@TRANCOUNT状态,并使用它“退出”RAISERROR/RETURN(如果需要)
- Try/catch/throw——在这些示例中,我使用的是RAISERROR,如果您可以使用throw,Microsoft建议您使用throw(我认为可以使用SQL Server 2016+了)——
- 将XACT_ABORT设置为ON李>
- 在发送每个批定界符后对@TRANCOUNT执行检查,以查看是否应运行下一批。这里的关键是,如果发生错误,@@TRANCOUNT将为0。如果未发生错误,则为1。(注意:如果显式打开多个“嵌套”事务,则需要调整trancount检查,因为它可能高于1)
开始交易;
将XACT_ABORT设置为ON;
去
--创建一个包含两个可空列的表
创建表[dbo]。[t1](
[id][nvarchar](36)空,
[姓名][nvarchar](36)空
)
--添加具有一个空列的行
插入[dbo].[t1]值(NEWID(),NULL)
--将一列设置为不可为空
--由于上一次插入,此操作失败
ALTER TABLE[dbo].[t1]ALTER COLUMN[name][nvarchar](36)不为空
去
如果@@TRANC