Liquibase:changeset自动生成ID

时间:2017-01-04 13:40:03

标签: liquibase

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

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

2 个答案:

答案 0 :(得分:1)

我不认为生成的ID是个好主意。原因是liquibase使用changeSet id来计算校验和(除了author和fileName)。因此,如果您在其他人之间插入changeSet,则所有后续changeSet的校验和将发生变化,您将收到大量警告/错误。

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

  1. 创建您自己的ChangeLogParser
  2. 如果您自己解析ChangeLog,则可以根据需要自由生成ID。 缺点是您必须为changeLog提供自定义Xml架构。 Liquibase的模式对changeSet ids(必需)有约束。使用新架构,您可能需要对解析器进行大量调整。 或者,您可以选择另一种changeLog格式(YAML,JSON,Groovy)。他们的解析器可能更容易定制,因为他们不需要该模式定义。

    1. 做一些预处理
    2. 您可以编写一个简单的xslt(Xml转换),它从没有的文件生成带有changeSet ID的changeLog。

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

答案 1 :(得分:1)

我编写了一个Python脚本,以在Liquibase更改日志中生成唯一的ID。

小心!

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')