Liquibase Java, changesets don't apply
Asked Answered
S

6

7

I'm currently building a project for my internship, and I'm stuck since two days trying to use Liquibase in java. Everything seems right : the changelog file is found, correct URI, username and password; but when I run it, my changesets are not processed.

I use this class to manage liquibase actions from my program, such as rollback, update, updateSQL and futureRollbackSQL, given a changelog and eventually a destination file. If the source or destination is from a remote server, I use some SSH interactions (scp to, scp from) with JSch and temporary files (but it's not the topic).

This is the java code I have for now, given db, user, passwd, realAction are set previously, changelogpath and dest are some data storage class.

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());
        }
    }
}

And here is my changelog:

<?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 seems to do something, except parsing my changeset. When I launch my actions, sql generated files only contains the creation of the two tables of liquibase (databasechangelog and databasechangeloglock) and that's all. The update action won't modify anything at all (not even creating the two previously mentioned tables). I'm (100%) sure that the table abcd does not exist in the database before execution.

So I think I need some help at this point, to figure out what isn't working. I tried to look at some examples from the liquibase forum, but nothing helped. I'm currently using Maven's liquibase 3.4.0:

<dependency>
    <groupId>org.liquibase</groupId>
    <artifactId>liquibase-core</artifactId>
    <version>3.4.0</version>
</dependency>

Is there another dependency to include I missed? One small other question is how do I include a special oracle database driver(ojdbc6.jar)?

Thank you for your answers.

EDIT 06/08/2015: I got the logs in debug mode (deliberately changed the schema name):

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
Strontia answered 4/8, 2015 at 16:21 Comment(0)
M
2

Here at Datical we have noticed that there are some issues with Liquibase and Java 1.8. You mentioned on your post to the Liquibase user forums that you were using Java 1.8, so it is possible that Java 1.8 may be the issue. Can you try using Java 1.7 and see if you get different results? If not, you could try increasing the logging level - add a line like this after you have created your Liquibase object:

LogFactory.getInstance().getLog().setLogLevel(logLevel);

Where logLevel is the string "debug"

Marlow answered 5/8, 2015 at 17:13 Comment(4)
I would run this in a debugger and see whether the changelog is indeed getting loaded properly. The line where you create your Liquibase object, passing in "new DatabaseChangeLog(fsource)" - extract that to a local variable and inspect it in the debugger.Marlow
The DBChangelog seems correctly instantiated, when outputted it returns me the path of my changelog. As a precaution, I even created a new instance of File with the returned path and called <code>exists()</code>, which returned true.Strontia
In that case, the suggestions I have are to either: 1. Continue debugging through Liquibase. The 'high level' logic for the update method is to look at the changelog table in the database and compare the changeset identifers to the changeset identifiers from the changelog.xml file and generate SQL for the items that are missing. 2. Use one of the update() methods on the Liquibase object that take a Writer argument, which will cause the SQL text to be written to the writer. I suspect that the SQL will also be nearly empty, so this might not be the best approach.Marlow
I used the "hard" way, launching Liquibase command as a process. Not pretty at all, but it does the work... Stupid deadlines =(Strontia
A
0

Most likely it is issue with XML versions.

Replace in XML header

http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-2.0.xsd

to

http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd

Aggarwal answered 5/8, 2015 at 17:42 Comment(1)
Most likely isn't. Xsd files are just here to validate the xml. Changing it to 3.4 (I tested it, just in case) didn't change anything.Strontia
D
0

I encounter the same issue even if the question is really old, I'll try to give an answer. The code is wrong in two points:

  • changeset path
  • PrintWriter

Liquibase API doesn't give good feedback if the path is unreadable, but usually, you will see logging locks without any applied query.

Furthermore, in your code, the execution is printed in the Writer instead of executing queries.

here you can find a working example:

Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(ds.getConnection()));
    
Liquibase liquibase = new Liquibase("./relativepathToChangeset", new FileSystemResourceAccessor(new File("basePathWhereChangeSetIsPresent")), database);
    
liquibase.update("");
    
Decalogue answered 21/1, 2022 at 18:45 Comment(0)
W
0

I'm sharing the solution I found to fix changes not being applied when running liquibase update. Please note, I am not using Java, I managing my changelog as a .sql file. I am using the Snowflake JDBC driver. The thing that fixed it for me was explicitly defining the defaultCatalogName and defaultSchemaName properties in the liquibase.properties file. Simply providing these parameters in the JDBC url was insufficient. My liquibase.properties file looks like so:

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

I hope this helps someone who comes across this StackOverflow post like I did.

Windom answered 7/2, 2022 at 1:23 Comment(0)
L
0

I has similar issue where the changeset wasn't being executed.. I changed the xsd version from 3.1 to 3.4 and it worked.

Laurilaurianne answered 28/11, 2022 at 7:9 Comment(0)
P
0

I had a similar issue where changeset wasn't getting applied as I was using SpringLiquibase with schema per tenant.

I needed to set liquibase.setLabelFilter(schemaName) to resolve the change log caching issue.

Palomino answered 29/12, 2023 at 15:11 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.