2016-03-31 13 views
1

Ich verwende einen Liquibase-Changeset, um null Werte der Spalte customId zu aktualisieren. Die SQL ist eine modifizierte Version von this answer.Doppelte Eingabe Ausnahme beim Generieren von UUID in Liquibase changeset

Das Problem ist, dass es scheint, die gleiche UUID für alle Zeilen zu verwenden. Meine changeset wie folgt aussieht:

<changeSet id="v3.0.3" author="msp" runAlways="false"> 
    <preConditions onFail="MARK_RAN"> 
     <not> 
      <sqlCheck expectedResult="0">select count(*) from FOOBAR where customId is null</sqlCheck> 
     </not> 
    </preConditions> 

    <sql>update FOOBAR set customId = concat('cu:', (select uuid())) where customId is null</sql> 
</changeSet> 

Beachten Sie, dass, wenn ich diese leicht modifizierte Version der Abfrage renne in der MySQL-Konsole (eine Grenze von 2 Hinzufügen), dann funktioniert es:

update FOOBAR set customId = concat('cu:', (select uuid())) where customId is null limit 2

Aber wenn ich versuche, die gleiche Abfrage (einschließlich der Grenze) mit Liquibase zu laufen, erhalte ich die folgende Ausnahme:

Caused by: liquibase.exception.MigrationFailedException: Migration failed for change set changelog/db.changelog-v3.0.3.xml::v3.0.3::msp: 
    Reason: liquibase.exception.DatabaseException: Error executing SQL update FOOBAR set customId = concat('cu:', (select uuid())) where customId is null limit 2: Duplicate entry 'cu:cde325da-f71f-11e5-95f8-d15a50829a7d' for key 'customId' 
    at liquibase.changelog.ChangeSet.execute(ChangeSet.java:554) 
    at liquibase.changelog.visitor.UpdateVisitor.visit(UpdateVisitor.java:43) 
    at liquibase.changelog.ChangeLogIterator.run(ChangeLogIterator.java:70) 
    at liquibase.Liquibase.update(Liquibase.java:195) 
    at liquibase.Liquibase.update(Liquibase.java:174) 
    at liquibase.integration.spring.SpringLiquibase.performUpdate(SpringLiquibase.java:330) 
    at liquibase.integration.spring.SpringLiquibase.afterPropertiesSet(SpringLiquibase.java:287) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1625) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1562) 
    ... 77 more 
Caused by: liquibase.exception.DatabaseException: Error executing SQL update FOOBAR set customId = concat('cu:', (select uuid())) where customId is null limit 2: Duplicate entry 'cu:cde325da-f71f-11e5-95f8-d15a50829a7d' for key 'customId' 
    at liquibase.executor.jvm.JdbcExecutor.execute(JdbcExecutor.java:62) 
    at liquibase.executor.jvm.JdbcExecutor.execute(JdbcExecutor.java:122) 
    at liquibase.database.AbstractJdbcDatabase.execute(AbstractJdbcDatabase.java:1206) 
    at liquibase.database.AbstractJdbcDatabase.executeStatements(AbstractJdbcDatabase.java:1189) 
    at liquibase.changelog.ChangeSet.execute(ChangeSet.java:518) 
    ... 85 more 
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry 'cu:cde325da-f71f-11e5-95f8-d15a50829a7d' for key 'customId' 
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) 
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57) 
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) 
    at java.lang.reflect.Constructor.newInstance(Constructor.java:526) 
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:411) 
    at com.mysql.jdbc.Util.getInstance(Util.java:386) 
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1039) 
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4096) 
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4028) 
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2490) 
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2651) 
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2677) 
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2627) 
    at com.mysql.jdbc.StatementImpl.execute(StatementImpl.java:841) 
    at com.mysql.jdbc.StatementImpl.execute(StatementImpl.java:681) 
    at com.mchange.v2.c3p0.impl.NewProxyStatement.execute(NewProxyStatement.java:1006) 
    at liquibase.executor.jvm.JdbcExecutor$ExecuteStatementCallback.doInStatement(JdbcExecutor.java:310) 
    at liquibase.executor.jvm.JdbcExecutor.execute(JdbcExecutor.java:55) 
    ... 89 more 

Beachten Sie, dass es von Co urse eine UNIQUE Einschränkung auf customId - aber sollte nicht select uuid() (auch ausprobiert uuid() ohne Auswahl) einen eindeutigen Wert generieren, auch bei Verwendung von Liquibase?

Antwort

1

Das Problem kann mit einer kleinen Problemumgehung gelöst werden. Ich teile das Update in zwei Abfragen:

<changeSet id="v3.0.3" author="msp" runAlways="false"> 
    <preConditions onFail="MARK_RAN"> 
     <not> 
      <sqlCheck expectedResult="0">select count(*) from FOOBAR where customId is null</sqlCheck> 
     </not> 
    </preConditions> 

    <sql>update FOOBAR set customId = (select uuid())) where customId is null</sql> 
    <sql>update FOOBAR set customId = concat('cu:', customId) where length(customId) = 36 
</changeSet> 

Dies funktioniert natürlich nur für meinen Fall, wo ich sicher sein kann, dass alle Zeilen der ersten Abfrage kann durch length(customId) = 36 identifiziert werden.