我有一堆创建/删除序列、用户和其他对象的 sql 脚本。我正在通过 liquibase 运行这些脚本,但它们失败了,因为当我尝试删除不存在的序列或创建现有用户时,oracle 会抱怨。
有没有一种预言机方法来防止错误发生?
类似的东西
如果不存在则创建用户/序列
如果存在则删除用户/安全
据我所知,我有以下选择:
- 写一个plsql脚本
- 使用 liquibase 上下文。
- 使用 liquibase 前提条件,但这意味着工作量太大。
任何想法/想法将不胜感激。
Liquibase 有一个 failOnError 属性,您可以在包含可能失败的调用的 changeSet 上将其设置为 false。
<changeSet failOnError="false">
<createSequence sequenceName="new_sequence"/>
</changeSet>
这允许您拥有简单的创建用户、创建序列、删除用户和删除序列更改集,并且如果语句由于用户/序列存在/不存在而引发错误,它们仍将被标记为已运行并且更新将继续。
这种方法的缺点是它也会将它们标记为已运行,如果它们由于某些其他原因(错误的权限、连接失败、无效的 SQL 等)而出错,它也会继续。更准确的方法是使用前置条件,如下所示:
<changeSet>
<preconditions onFail="MARK_RAN"><not><sequenceExists/></not></preconditions>
<createSequence name="new_sequence"/>
</changeSet>
目前没有 userExists 前置条件,但您可以创建自定义前置条件或回退到前置条件。有关文档,请参阅http://www.liquibase.org/documentation/preconditions.html
编写一个类似于此的函数 do_ddl 并捕获您要捕获的所有异常:
DECLARE
allready_null EXCEPTION;
PRAGMA EXCEPTION_INIT(allready_null, -1451);
BEGIN
execute immediate 'ALTER TABLE TAB MODIFY(COL NULL)';
EXCEPTION
WHEN allready_null THEN
null; -- handle the error
END;
/
我只是使用 PL/SQL 匿名块。
begin
for x in (select sequence_name
from user_sequences
where sequence_name in ('SEQ1','SEQ2' ... 'SEQn'))
loop
execute immediate 'drop sequence '||x.sequence_name;
end loop;
end;
/
根据我的经验,根据 Liquibase 3.5.1 的行为,使用 failOnError="false" 时,如果操作失败,changeSet 不会记录为“RAN”。对我来说,这似乎是一个错误,内森的回答似乎不正确?
这种方法的缺点是它也会将它们标记为已运行,如果它们由于某些其他原因(错误的权限、连接失败、无效的 SQL 等)而出错,它也会继续。更准确的方法是使用前置条件,如下所示:
即:它不会将它们标记为已运行!
liquibase 前提条件没有为我检查现有序列。所以,经过多次尝试,我尝试了简单<changeSet id="test-id"><sql>
DROP SEQUENCE IF EXISTS "TABLENAME_ID_seq"; </sql></changeSet>