Идемпотентность Liquibase на Oracle DDL

Я исследую использование Liquibase для нового проекта с использованием Oracle, и мне интересно, как я могу обеспечить достаточную надежность моих наборов изменений для восстановления после любых сбоев без ручного вмешательства. В идеале я бы использовал атрибут runInTransaction, который позволял бы откатывать DDL при сбоях, но Oracle автоматически фиксировал на DDL. Для этой ситуации документация рекомендует:

Поэтому, как правило, лучше всего иметь только одно изменение на набор изменений, если только не существует группы изменений без автоматической фиксации, которые вы хотите применить в качестве транзакции, такой как вставка данных.

Наличие одного DDL на набор изменений уменьшит вероятность проблем, но не устранит их. Если DDL завершается успешно, но обновление DATABASECHANGELOG не удается, из моих тестов кажется, что Liquibase просто зависает, и требуется ручное вмешательство.

Нужно использовать предварительные условия на каждом шаге, чтобы избежать этой проблемы? Это делает результирующие changeSets довольно многословными. Это одно из определений таблицы примеров Liquibase:

<changeSet author="jsmith" id="1">
    <createTable tableName="departments"
                 remarks="The departments of this company. Does not include geographical divisions.">
        <column name="id" type="number(4,0)">
            <constraints nullable="false" primaryKey="true"
                         primaryKeyName="DPT_PK"/>
        </column>
        <column name="dname" type="varchar2(14)"
                remarks="The official department name as registered on the internal website."/>
    </createTable>
    <addUniqueConstraint constraintName="departments_uk1"
                         columnNames="dname" tableName="departments"/>
    <createSequence sequenceName="departments_seq"/>
</changeSet>

Чтобы сделать это идемпотентом, я думаю, что это должно измениться на что-то вроде следующего:

<changeSet author="jsmith" id="1">
    <preConditions onFail="MARK_RAN">
        <not>
            <tableExists tableName="departments" />
        </not>
    </preConditions>
    <createTable tableName="departments"
        remarks="The departments of this company. Does not include geographical divisions.">
        <column name="id" type="number(4,0)" / column>
            <column name="dname" type="varchar2(14)"
                remarks="The official department name as registered on the internal website." />
    </createTable>
</changeSet>

<changeSet author="jsmith" id="2">
    <preConditions onFail="MARK_RAN">
        <not>
            <primaryKeyExists primaryKeyName="pk_departments" />
        </not>
    </preConditions>
    <addPrimaryKey tableName="departments" columnNames="id"
        constraintName="pk_departments" />
</changeSet>

<changeSet author="jsmith" id="3">
    <preConditions onFail="MARK_RAN">
        <not>
            <uniqueConstraintExists constraintName="departments_uk1" />
        </not>
    </preConditions>
    <addUniqueConstraint constraintName="departments_uk1"
        columnNames="dname" tableName="departments" />
</changeSet>

<changeSet author="jsmith" id="4">
    <preConditions onFail="MARK_RAN">
        <not>
            <sequenceExists sequenceName="departments_seq" />
        </not>
    </preConditions>
    <createSequence sequenceName="departments_seq" />
</changeSet>

Есть ли какой-нибудь более простой способ добиться этого? Я бы подумал, что Liquibase сможет генерировать эти предпосылки.

Спасибо

1 ответ

К сожалению, в большинстве RDBMS операторы DDL фиксируют транзакцию, а Liquibase реагирует на неудачу, просто откатывая транзакцию. Итак, во-первых, я бы обернул каждый оператор DDL в отдельный набор изменений.

В каких случаях не удалось обновить databaschangelog? Мне любопытно, как это должно быть довольно крепким.

В любом случае, вы можете избежать повторения, написав небольшое расширение для Liquibase, которое делает это автоматически для всех ваших наборов изменений. Посмотрите на точку расширения предусловия.

Другие вопросы по тегам