Liquibase:变更集自动生成 ID

Liquibase: changeset auto generate ID

如何使用 liquibase 自动生成变更集 ID?

我不想手动设置每个变更集的 ID,有没有办法自动设置?

我认为生成的 ID 不是个好主意。原因是 liquibase 使用 changeSet id 来计算校验和(除了作者和文件名)。所以如果你在其他人之间插入一个 changeSet,所有后续 changeSet 的校验和都会改变,你会得到大量的 warnings/errors。

无论如何,如果您仍然想生成 ID,我可以想到这些解决方案:

  1. 创建你自己的ChangeLogParser

如果您自己解析 ChangeLog,您可以随意生成您想要的 ID。 缺点是您必须为更改日志提供自定义 Xml 架构。来自 Liquibase 的模式对 changeSet id 有限制(必需)。使用新模式,您可能必须对解析器进行大量调整。 或者,您可以选择另一种 changeLog 格式(YAML、JSON、Groovy)。他们的解析器可能更容易定制,因为他们不需要该架构定义。

  1. 做一些预处理

您可以编写一个简单的 xslt(Xml 转换),从具有 none.

的文件生成带有 changeSet id 的 changeLog
  1. 使用时间戳作为 ID

这是我的建议。它并没有按照您提出的方式解决问题,但它简单、一致,提供了额外的信息,对于其他数据库迁移工具也是一种很好的做法 http://www.jeremyjarrell.com/using-flyway-db-with-distributed-version-control/

我写了一个 Python 脚本来生成唯一的 ID 到 Liquibase 更新日志中。

小心!

DO 生成 ID

  • 更新日志正在开发或准备发布时
  • 或者当你控制目标数据库的校验和时

不要生成 ID - 当变更日志已经部署时

"""
###############################################################################
Purpose: Generate unique subsequent IDs into Liquibase changelogs
###############################################################################

Args:
    param1:     Full Windows path changelog directory (optional) 
                OR
                --inplace: directly process changelogs (optional) 

    By default, XML files in the current directory are processed.

Returns:
    In case of success, the output path is returned to stdout. 
    Otherwise, we crash and drag the system into mordor.

    If you feel like wasting time you can: 
        a) port path handling to *nix 
        b) handle any obscure exceptions 
        c) add Unicode support (for better entertainment)

Dependencies:
    Besides Python 3, in order to preserve XML comments, I had to use lxml 
    instead of the stock ElementTree parser. 
    Install lxml:

    $ pip install lxml

    Proxy clusterfuck? Don't panic! Simply download a .whl package from: 
    https://pypi.org/project/lxml/#files and install with pip.

Bugs:
    Changesets having id="0" are ignored. Usually, these do not occur.    

Author:
    Tobias Bräutigam 

Versions:
    0.0.1 - re based, deprecated
    0.0.2 - parse XML with lxml, CURRENT 
"""

import datetime
import sys
import os
from pathlib import Path, PureWindowsPath

try:    
    import lxml.etree as ET
except ImportError as error:
    print (''' 
    Error: module lxml is missing.
    Please install it:

    pip install lxml
    ''')
    exit()

# Process arguments
prefix = '' # hold separator, if needed 
outdir = 'out'

try: sys.argv[1]
except: pass
else:
    if sys.argv[1] == '--inplace':
        outdir = ''
    else:                
        prefix = outdir + '//'
        # accept Windows path syntax
        inpath = PureWindowsPath(sys.argv[1]) 
        # convert path format
        inpath = Path(inpath) 
        os.chdir(inpath) 
        try: os.mkdir(outdir)
        except: pass
        filelist = [ f for f in os.listdir(outdir) ]
        for f in filelist: os.remove(os.path.join(outdir, f))

# Parse XML, generate IDs, write file 
def parseX(filename,prefix):    
    cnt = 0    
    print (filename)
    tree = ET.parse(filename)
    for node in tree.getiterator():
        if int(node.attrib.get('id', 0)):                        
            now = datetime.datetime.now()            
            node.attrib['id'] = str(int(now.strftime("%H%M%S%f"))+cnt*37)
            cnt = cnt + 1 
    root = tree.getroot()
    # NS URL element name is '' for Etree, lxml requires at least one character
    ET.register_namespace('x', u'http://www.liquibase.org/xml/ns/dbchangelog') 
    tree = ET.ElementTree(root)        
    tree.write(prefix + filename, encoding='utf-8', xml_declaration=True)
    print(str(cnt) +' ID(s) generated.')

# Process files
print('\n')
items = 0
for infile in os.listdir('.'):
    if (infile.lower().endswith('.xml')) == True:      
        parseX(infile,prefix)
        items=items+1

# Message
print('\n' + str(items) + ' file(s) processed.\n\n')
if items > 0:
    print('Output was written to: \n\n')    
    print(str(os.getcwd()) + '\' + outdir + '\n')