Liquibase Java,变更集不适用
Posted
技术标签:
【中文标题】Liquibase Java,变更集不适用【英文标题】:Liquibase Java, changesets don't apply 【发布时间】:2015-10-27 03:53:00 【问题描述】:我目前正在为我的实习项目构建一个项目,自从尝试在 Java 中使用 Liquibase 两天以来,我就陷入了困境。一切似乎都正确:找到了更改日志文件,正确的 URI、用户名和密码;但是当我运行它时,我的变更集没有得到处理。
我使用这个类来管理我的程序中的 liquibase 操作,例如 rollback、update、updateSQL 和 futureRollbackSQL em>,给定一个更改日志,并最终给出一个目标文件。如果源或目标来自远程服务器,我会使用 JSch 和临时文件(但这不是主题)进行一些 SSH 交互(scp to、scp from)。
这是我现在拥有的 java 代码,因为 db、user、passwd、realAction 是之前设置,changelogpath 和 dest 是一些数据存储类。
Connection c = null;
Database database = null;
PrintWriter pw = null;
File file = null;
liquibase.Liquibase liquibase = null;
contexts = db+"."+user;
try
pw = new PrintWriter(new FileWriter(file));
// Get connection
c = SQLManager.getInstance().getConnection(db, user, passwd);
// Get liquibase connection
database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(c));
liquibase = new liquibase.Liquibase(new DatabaseChangeLog(fsource), new FileSystemResourceAccessor(),
database);
// Run liquibase action
switch (realAction)
case Constants.LIQUIBASE_ACTION_FUTUREROLLBACKSQL:
liquibase.futureRollbackSQL(pw);
break;
case Constants.LIQUIBASE_ACTION_UPDATESQL:
liquibase.update(contexts, pw);
break;
case Constants.LIQUIBASE_ACTION_UPDATE:
liquibase.update(contexts);
if (!c.getAutoCommit())
c.commit();
break;
default:
throw new OdewipElementRuntimeException(this, "Action not implemented");
pw.close();
database.close();
c.close();
catch (IOException | SQLException | LiquibaseException e)
throw new Exception(e.getMessage());
finally
if (c != null)
try
c.close();
catch (SQLException e)
// nothing to do
throw new RuntimeException(e.getClass() + ": " + e.getMessage());
这是我的更新日志:
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ora="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-2.0.xsd http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">
<changeSet id="mychangeset" author="testy">
<preConditions onSqlOutput="TEST" onFail="MARK_RAN">
<not>
<tableExists tableName="abcd"/>
</not>
</preConditions>
<createTable tableName="abcd">
<column name="id" type="number">
<constraints primaryKey="true"/>
</column>
</createTable>
</changeSet>
</databaseChangeLog>
Liquibase 似乎在做一些事情,除了解析我的变更集。当我启动我的操作时,sql 生成的文件只包含 liquibase 的两个表(databasechangelog 和 databasechangeloglock)的创建,仅此而已。 update 操作根本不会修改任何内容(甚至不会创建前面提到的两个表)。我 (100%) 确定执行前数据库中不存在表 abcd。
所以我想我现在需要一些帮助,以找出什么不起作用。我试图查看 liquibase 论坛中的一些示例,但没有任何帮助。 我目前正在使用 Maven 的 liquibase 3.4.0:
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
<version>3.4.0</version>
</dependency>
是否还有我错过的其他依赖项? 另一个小问题是如何包含一个特殊的 oracle 数据库驱动程序(ojdbc6.jar)?
感谢您的回答。
编辑 06/08/2015: 我在调试模式下获得了日志(故意更改了架构名称):
DEBUG 06/08/15 09:28: liquibase: Executing QUERY database command: select count(*) from MYSCHEMA.DATABASECHANGELOGLOCK
DEBUG 06/08/15 09:28: liquibase: Create Database Lock Table
DEBUG 06/08/15 09:28: liquibase: Executing EXECUTE database command: CREATE TABLE MYSCHEMA.DATABASECHANGELOGLOCK (ID NUMBER(10) NOT NULL, LOCKED NUMBER(1) NOT NULL, LOCKGRANTED TIMESTAMP, LOCKEDBY VARCHAR2(255), CONSTRAINT PK_DATABASECHANGELOGLOCK PRIMARY KEY (ID))
DEBUG 06/08/15 09:28: liquibase: Created database lock table with name: MYSCHEMA.DATABASECHANGELOGLOCK
DEBUG 06/08/15 09:28: liquibase: Executing QUERY database command: select count(*) from MYSCHEMA.DATABASECHANGELOGLOCK
DEBUG 06/08/15 09:28: liquibase: Initialize Database Lock Table
DEBUG 06/08/15 09:28: liquibase: Executing EXECUTE database command: DELETE FROM MYSCHEMA.DATABASECHANGELOGLOCK
DEBUG 06/08/15 09:28: liquibase: Executing EXECUTE database command: INSERT INTO MYSCHEMA.DATABASECHANGELOGLOCK (ID, LOCKED) VALUES (1, 0)
DEBUG 06/08/15 09:28: liquibase: Executing QUERY database command: SELECT LOCKED FROM MYSCHEMA.DATABASECHANGELOGLOCK WHERE ID=1 FOR UPDATE
DEBUG 06/08/15 09:28: liquibase: Lock Database
DEBUG 06/08/15 09:28: liquibase: Executing UPDATE database command: UPDATE MYSCHEMA.DATABASECHANGELOGLOCK SET LOCKED = 1, LOCKEDBY = 'CRO09177 (xx.xx.xx.xxx)', LOCKGRANTED = to_date('2015-08-06 09:28:28', 'YYYY-MM-DD HH24:MI:SS') WHERE ID = 1 AND LOCKED = 0
INFO 06/08/15 09:28: liquibase: Successfully acquired change log lock
DEBUG 06/08/15 09:28: liquibase: Create Database Change Log Table
INFO 06/08/15 09:28: liquibase: Creating database history table with name: MYSCHEMA.DATABASECHANGELOG
DEBUG 06/08/15 09:28: liquibase: Executing EXECUTE database command: CREATE TABLE MYSCHEMA.DATABASECHANGELOG (ID VARCHAR2(255) NOT NULL, AUTHOR VARCHAR2(255) NOT NULL, FILENAME VARCHAR2(255) NOT NULL, DATEEXECUTED TIMESTAMP NOT NULL, ORDEREXECUTED NUMBER(10) NOT NULL, EXECTYPE VARCHAR2(10) NOT NULL, MD5SUM VARCHAR2(35), DESCRIPTION VARCHAR2(255), COMMENTS VARCHAR2(255), TAG VARCHAR2(255), LIQUIBASE VARCHAR2(20), CONTEXTS VARCHAR2(255), LABELS VARCHAR2(255))
DEBUG 06/08/15 09:28: liquibase: Executing QUERY database command: select count(*) from MYSCHEMA.DATABASECHANGELOG
INFO 06/08/15 09:28: liquibase: Reading from MYSCHEMA.DATABASECHANGELOG
DEBUG 06/08/15 09:28: liquibase: Executing QUERY database command: SELECT FILENAME,AUTHOR,ID,MD5SUM,DATEEXECUTED,ORDEREXECUTED,EXECTYPE,DESCRIPTION,COMMENTS,TAG,LIQUIBASE,LABELS,CONTEXTS FROM MYSCHEMA.DATABASECHANGELOG ORDER BY DATEEXECUTED ASC, ORDEREXECUTED ASC
DEBUG 06/08/15 09:28: liquibase: Executing QUERY database command: select count(*) from MYSCHEMA.DATABASECHANGELOGLOCK
DEBUG 06/08/15 09:28: liquibase: Release Database Lock
DEBUG 06/08/15 09:28: liquibase: Executing UPDATE database command: UPDATE MYSCHEMA.DATABASECHANGELOGLOCK SET LOCKED = 0, LOCKEDBY = NULL, LOCKGRANTED = NULL WHERE ID = 1
INFO 06/08/15 09:28: liquibase: Successfully released change log lock
【问题讨论】:
【参考方案1】:我正在分享我发现的解决方案,用于修复运行 liquibase update
时未应用的更改。请注意,我没有使用 Java,我将我的变更日志管理为 .sql
文件。我正在使用雪花 JDBC 驱动程序。为我解决的问题是在liquibase.properties
文件中明确定义defaultCatalogName
和defaultSchemaName
属性。仅仅在 JDBC url 中提供这些参数是不够的。我的liquibase.properties
文件如下所示:
changeLogFile: sql/changelog.sql
url: jdbc:snowflake://<url>?db=<database name>&schema=PUBLIC&role=SYSADMIN&warehouse=COMPUTE_WH
driver: net.snowflake.client.jdbc.SnowflakeDriver
username: <username>
password: <password>
classpath: snowflake-jdbc-3.13.14.jar
defaultCatalogName: <database name>
defaultSchemaName: PUBLIC
liquibase.hub.mode=off
我希望这可以帮助像我一样看到这篇 *** 帖子的人。
【讨论】:
【参考方案2】:即使问题真的很老,我也会遇到同样的问题,我会尝试给出答案。代码有两点错误:
变更集路径PrintWriter
如果路径不可读,Liquibase API 不会提供良好的反馈,但通常情况下,您会看到没有任何应用查询的日志记录锁。
此外,在您的代码中,执行打印在 Writer 中,而不是执行查询。
在这里您可以找到一个工作示例:
Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(ds.getConnection()));
Liquibase liquibase = new Liquibase("./relativepathToChangeset", new FileSystemResourceAccessor(new File("basePathWhereChangeSetIsPresent")), database);
liquibase.update("");
【讨论】:
【参考方案3】:很可能是 XML 版本的问题。
在 XML 标头中替换
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-2.0.xsd
到
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd
【讨论】:
很可能不是。 Xsd 文件只是在这里验证 xml。将其更改为 3.4(我对其进行了测试,以防万一)并没有改变任何内容。【参考方案4】:在 Datical,我们注意到 Liquibase 和 Java 1.8 存在一些问题。您在 Liquibase 用户论坛上的帖子中提到您使用的是 Java 1.8,因此 Java 1.8 可能是问题所在。您可以尝试使用 Java 1.7 并查看是否得到不同的结果吗?如果没有,您可以尝试提高日志记录级别 - 在创建 Liquibase 对象后添加这样的一行:
LogFactory.getInstance().getLog().setLogLevel(logLevel);
其中 logLevel 是字符串“debug”
【讨论】:
我会在调试器中运行它并查看更改日志是否确实正确加载。创建 Liquibase 对象的行,传入“new DatabaseChangeLog(fsource)” - 将其提取到局部变量并在调试器中检查它。 DBChangelog 似乎已正确实例化,输出时它返回我的更改日志的路径。作为预防措施,我什至使用返回的路径创建了一个新的 File 实例并调用exists()
,它返回 true。
在这种情况下,我的建议是: 1. 通过 Liquibase 继续调试。更新方法的“高级”逻辑是查看数据库中的变更日志表,并将变更集标识符与 changelog.xml 文件中的变更集标识符进行比较,并为缺失的项目生成 SQL。 2. 在 Liquibase 对象上使用带有 Writer 参数的 update() 方法之一,这将导致 SQL 文本被写入 writer。我怀疑 SQL 也几乎是空的,所以这可能不是最好的方法。
我使用“硬”方式,将 Liquibase 命令作为进程启动。一点也不漂亮,但它确实有效......愚蠢的截止日期=(以上是关于Liquibase Java,变更集不适用的主要内容,如果未能解决你的问题,请参考以下文章