Flyway Migration with java

2020-03-30 03:11发布

问题:

I learnt flywaydb migration with java works with JDBC connection and also spring support through SpringTemplate, but flyway doesn't work with DAOs.

for tables/entities with more relationships,it makes life much easier to do migration with DAO's rather than sql.

is there a solution or work-around to deal with this ?

回答1:

First, Flyway has its own transaction managing system and does not use Spring transaction handling.

If your DAOs extend JdbcDaoSupport, you could instantiate manually the your DAO and then manually inject the provided JdbcTemplate in the DAO:

public class MyJdbcMigration implements SpringJdbcMigration {
  public void migrate(JdbcTemplate jdbcTemplate) {
    MyJdbcDao dao = new MyJdbcDao();
    dao.setJdbcTemplate(jdbcTemplate);
    dao.updateDate();
  }
}


回答2:

Your DAOs rely on the very structure Flyway was designed to change. We therefore have a chicken and egg problem here. The way to solve this is to run Flyway before the rest of your application (including the DAOs) gets initialized.



回答3:

I know this comes very late, but for future visitors with the same problem this might be helpful.

The creator of Flyway (Axel Fontaine) is actually wrong in this subject. It's perfectly fine to migrate data with business logic and there is no chicken and egg problem, as long as you do not change the structure of the database in your update script.

One example: you have a field "password" in your database and it is clear text. Because of security concerns you now want to use a special hash function and hash all passwords in the database (it should be a secure one and the database does not have a function to do that). The hash function is declared in your UserDAO and called when the user is created or when they change their password. Although that's not a perfect example, there are many possible scenarios where accessing a DAO for the migration makes sense.

Fortunately a work colleague of mine found a solution to the problem, and it's only requires around 5 lines of code. You also need to add Apache Deltaspike to your dependencies, if it isn't already.

In your DAO, add an import for BeanProvider:

import org.apache.deltaspike.core.api.provider.BeanProvider;

Then we simply make the DAO a singleton:

public static UserDao getInstance() {
    return BeanProvider.getContextualReference(UserDao.class, false, new DaoLiteral());
}

That's pretty much it. In your Flyway script you can now access the DAO:

@Override
public void migrate(Connection cnctn) throws Exception{
    UserDao userdao = UserDao.getInstance();
    List<User> userList = userdao.getAllUsers();
    ...
}

Explanation: the Class (VX_yourflywaymigrationscript) is not managed by the CDI Container, so it's not possible to inject the DAO. BeanProvider is made for exactly that - it can load a Bean and give you the reference, even if you are not in a CDI context.

I hope that helps.