问题 比较数据库并使用liquibase生成sql脚本


我正在使用与ant集成的liquibase来比较两个数据库。但它产生的输出就像通用格式。它没有给出sql语句。请任何人都可以告诉我如何使用与ant或命令行实用程序集成的liquibase来比较两个数据库。


11006
2017-12-06 09:12


起源



答案:


获取表示两个数据库之间差异的SQL语句是一个两步操作:

  1. 生成XML“diff”更改日志
  2. 生成SQL语句

这个例子需要一个 liquibase.properties 文件(简化 命令行 参数):

classpath=/path/to/jdbc/jdbc.jar
driver=org.Driver
url=jdbc:db_url1
username=user1
password=pass1
referenceUrl=jdbc:db_url2
referenceUsername=user2
referencePassword=pass2
changeLogFile=diff.xml

现在运行以下命令来创建SQL语句:

liquibase diffChangeLog
liquibase updateSQL > update.sql

liquibase的一个很好的功能是它还可以生成回滚SQL:

liquibase futureRollbackSQL > rollback.sql

更新

Liquibase不会在数据库之间生成数据差异,只会生成模式。但是,可以将数据库数据转储为一系列更改集:

liquibase --changeLogFile=data.xml --diffTypes=data generateChangeLog

一个人可以使用 data.xml中 用于迁移新表中包含的数据的文件。

更新2:

也可以使用groovy生成liquibase变更集。

import groovy.sql.Sql 
import groovy.xml.MarkupBuilder

//
// DB connection
//
this.class.classLoader.rootLoader.addURL(new URL("file:///home/path/to/h2-1.3.162.jar"))
def sql = Sql.newInstance("jdbc:h2:db/db1","user","pass","org.h2.Driver")

//
// Generate liquibase changeset
//
def author = "generated"
def id = 1

new File("extract.xml").withWriter { writer ->
    def xml = new MarkupBuilder(writer);

    xml.databaseChangeLog(
        "xmlns":"http://www.liquibase.org/xml/ns/dbchangelog",
        "xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance",
        "xsi:schemaLocation":"http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-2.0.xsd"
    ) {
        changeSet(author:author, id:id++) {
            sql.eachRow("select * from employee") { row ->
                insert(tableName:"exmployee") {
                    column(name:"empno",    valueNumeric:row.empno)
                    column(name:"name",     value:row.name)
                    column(name:"job",      value:row.job)
                    column(name:"hiredate", value:row.hiredate)
                    column(name:"salary",   valueNumeric:row.salary)
                }
            }
        }
    }
}

16
2017-12-06 23:20



我能看到差异,但如果缺少一个表,它只会创建表,但不会将表数据从源db复制到目标db。对此有什么解决方案吗? - bhasker
不是一个完整的解决方案。我更新了我的答案,指出如何将数据转储为一系列更改集。生成的数据可用于在新数据库中加载新表。 - Mark O'Connor
执行命令后,它会给出java堆空间错误。我尝试将java堆大小设置为%JAVA_OPTS%-Xms512m -Xmx1024m -XX:MaxPermSize = 1024m。你能帮助我吗? - bhasker
我认为你的数据集太大了。尝试生成变更集(更新我的答案)或者只是使用普通的数据库数据加载工具。 - Mark O'Connor


答案:


获取表示两个数据库之间差异的SQL语句是一个两步操作:

  1. 生成XML“diff”更改日志
  2. 生成SQL语句

这个例子需要一个 liquibase.properties 文件(简化 命令行 参数):

classpath=/path/to/jdbc/jdbc.jar
driver=org.Driver
url=jdbc:db_url1
username=user1
password=pass1
referenceUrl=jdbc:db_url2
referenceUsername=user2
referencePassword=pass2
changeLogFile=diff.xml

现在运行以下命令来创建SQL语句:

liquibase diffChangeLog
liquibase updateSQL > update.sql

liquibase的一个很好的功能是它还可以生成回滚SQL:

liquibase futureRollbackSQL > rollback.sql

更新

Liquibase不会在数据库之间生成数据差异,只会生成模式。但是,可以将数据库数据转储为一系列更改集:

liquibase --changeLogFile=data.xml --diffTypes=data generateChangeLog

一个人可以使用 data.xml中 用于迁移新表中包含的数据的文件。

更新2:

也可以使用groovy生成liquibase变更集。

import groovy.sql.Sql 
import groovy.xml.MarkupBuilder

//
// DB connection
//
this.class.classLoader.rootLoader.addURL(new URL("file:///home/path/to/h2-1.3.162.jar"))
def sql = Sql.newInstance("jdbc:h2:db/db1","user","pass","org.h2.Driver")

//
// Generate liquibase changeset
//
def author = "generated"
def id = 1

new File("extract.xml").withWriter { writer ->
    def xml = new MarkupBuilder(writer);

    xml.databaseChangeLog(
        "xmlns":"http://www.liquibase.org/xml/ns/dbchangelog",
        "xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance",
        "xsi:schemaLocation":"http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-2.0.xsd"
    ) {
        changeSet(author:author, id:id++) {
            sql.eachRow("select * from employee") { row ->
                insert(tableName:"exmployee") {
                    column(name:"empno",    valueNumeric:row.empno)
                    column(name:"name",     value:row.name)
                    column(name:"job",      value:row.job)
                    column(name:"hiredate", value:row.hiredate)
                    column(name:"salary",   valueNumeric:row.salary)
                }
            }
        }
    }
}

16
2017-12-06 23:20



我能看到差异,但如果缺少一个表,它只会创建表,但不会将表数据从源db复制到目标db。对此有什么解决方案吗? - bhasker
不是一个完整的解决方案。我更新了我的答案,指出如何将数据转储为一系列更改集。生成的数据可用于在新数据库中加载新表。 - Mark O'Connor
执行命令后,它会给出java堆空间错误。我尝试将java堆大小设置为%JAVA_OPTS%-Xms512m -Xmx1024m -XX:MaxPermSize = 1024m。你能帮助我吗? - bhasker
我认为你的数据集太大了。尝试生成变更集(更新我的答案)或者只是使用普通的数据库数据加载工具。 - Mark O'Connor