Using Flyway for two databases, but only one at a time - java

I'm testing out PostgreSQL and CockroachDB with my application. I've got it such that I can run my application with either PostgreSQL OR CockroachDB. Is it possible to set Flyway up such that I can run either with Flyway support without errors occurring from also having it configured for the other database I'm not using at the moment?
I've tried looking for documentation that answers this, but it seems that most documentation in this area pertains to running both databases concurrently, which isn't what I'm trying to do here.
Not a huge deal, but I am curious... Thank you!

The default behavior of Flyway uses the config file. Issuing a command like flyway migrate will go to the configured database with the designated locations (folders where the migrations are stored).
So, to be able to switch on the fly, you have two choices. You can create two config files and then set them on execute from the command line, or, take direct control of the configuration settings through the command line. So, two different command lines with the appropriate settings for where the migrations are stored and how to connect to them should let you do exactly this.

Related

Database data upgrade with versioning by environment

I have a java app which I deploy on various plateforms (using ansible).
This app uses a database, which sometimes needs to get schema updates, which I perform and log/version with flyway (as a software dependency).
I now face the need to update data on all plateforms, but with different values depending on the plateforms. This is not a schema update, but is nonetheless data (list of other apps to which it connects) that forms the main structure of my app, and as such I want it to be versioned, in a similar way to what flyway does.
At first I was thinking I should input the different data in my ansible configuration, which seemed to make sense as it's ansible that knows about the various plateforms. And then I thought that this information would get passed to flyway somehow so that it performs the required updates.
However if that is handled using 'versioned migrations', I could end up with version conflicts because one environment requires an update and another doesn't (common versioning vs environment versioning).
There is a slight mention of this issue in the flyway FAQ, and one can set the flyway.locations property, or maybe I could use flyway placeholders that are set by ansible ?
Am I on the right track ? Or should I not use flyway altogether (is it meant to be used with DML, or should it be reserved for DDL) ?
Flyway can be used for both schema and data updates. Although it's primary purpose is around versioning schema updates.
It sounds like you need a way to deploy some scripts only in certain environments. Flyway provides functionality that will support this workflow. However, you'll need to decide on the approach that works best for you.
Here are some ideas.
Use different locations
The simplest way I can think of is to have environment specific scripts in their own locations. You can also have a location for 'common' scripts.
When you deploy, you can specify the 'common' location, alongside the environment specific one. Something like:
flyway migration -locations=common/sql, test/sql
flyway migration -locations=common/sql, production/sql
And so on.
shouldExecute script config & placeholders
Another way is to use the Flyway Teams feature shouldExecute. This let's you define a boolean expression to determine if a script should be run. You can inject a value from a placeholder. There is a blog post that explains more about it.
Use the cherryPick configuration option
Another Teams Edition feature is cherryPick, which allows you to specify exactly which scripts to deploy. So you might have a configuration file per environment with a cherryPick config that specifies the exact scripts to run. This one might be unwieldy since you need to explicitly list every script, but it does give you complete control.

Maven: How to create a correct JDBC driver dependency, if I don't know which database the client will use?

I'm currently learning to use maven, I understood how to create a maven project using dependencies from maven repository - and now I have the following question:
If I have an application which uses a database access, for example via Hibernate, then I need to add a dependency representing the corresponding database driver, for example mysql-connector-java for MySql, ojdbc for Oracle and so on.
But what if I want the program to run on a different machine and I don't know what database engine it uses? What is the common way to solve this? Just import all possible drivers as dependencies? Or is there a more elegant way?
Using a ORM (Object Relational Mapping) like Hibernate is the best solution since you write Java code that will be interpreted by Hibernate and translated into SQL queries.
At some point, you will have to decide which database are you going to use, then you will have to add the driver.
Another solution can be making configurations for different environments using maven: https://maven.apache.org/guides/mini/guide-building-for-different-environments.html
The problem is not particularly maven bound. Whenever you move to a new database, the administrator would have to use the correct JDBC driver according to DB, and yes, it requires different jar files.
The thing is, that you don't want to bundle the database jar file with your code. It may already exist (e.g. in the application server) or you may specify a path to drop it during installation.
Assuming you are creating a webapp. If you bundle a war-file with maven, it will include all dependencies inside the war file, so you must specify that the dependency is there during compilation and testing, but not in any package. The way to do so, is by specifying it as provided
<dependency>
<groupId>some.db</groupId>
<artifactId>jdbc-driver<artifactId>
<scope>provided</scope>
</dependency>
This means that the jar file will exist on the target platform, and hence, should not be packaged in a any bundle.
So the assumption I make is really, is this a web-app? Or is it standalone? Anyway, hope it helps.
You don't need a dependency at all. What you need is a driver to be available at runtime. It's true that one way to do this is with a dependency, but if you don't know the database you can't really bundle everything in there. You could stick some most common drivers, but then as said there would be licensing issues.
If you're talking about a web application, you could just tell the user to get the appropriate driver and configure a JNDI datasource that the software uses. This is/was a standard from back in the days, but it assumes that the application is a webapp and the end user knows how to configure things (although if he doesn't, he probably shouldn't be setting up the system in the first place).
For a standalone program using a local database, you have the easy choice of using an in memory database like H2 and not allowing any other databases. Naturally this case doesn't work for everything, but I'm including it as an example. In any case it would boil down to the same as with a webapp. Have the end user get the correct driver. If they're running a database server and your app, they should be able to find the right driver too. Then you just need to make sure it's included in the runtime classpath, which might be a bit harder.
The way this is done by SquirrelSQL for example, is by explicitly selecting the drivers as shown in the below picture. This of course again means the user needs to understand what he's doing.
I assume that you want everything to happen automagically and you're not too eager to instruct each user/machine admin how to configure system to have your app working. I am afraid it is not possible in the way you might have hoped.
The standalone database solution that Kayaman suggested might be the best solution in your case but hard to say without knowing further.
However here are some aspects regarding using maven and possible difficulties with some notes.
If I have an application which uses a database access, for example via
Hibernate, then I need to add a dependency representing the
corresponding database driver, for example mysql-connector-java for
MySql, ojdbc for Oracle and so on.
Yes. And you also would need to tell hibernate about this Driver and perhaps other stuff related. It is not just adding dependency but also filtering some prop file or persistence.xml. That might be a job for maven and some of its plugins. But still it would require knowledge about all the possible db alternatives and maven profiles for each of those to handle them.
But what if I want the program to run on a different machine and I
don't know what databse it uses? What is the common way to solve this?
What options do I have? Just import all possible drivers as
dependencies? Is there a more elegant way?
All programs have dependencies. Was it related to DB or not. In a sense as other answers suggest this is not maven specific (but quite related still! ) thing. You need to be aware of the requirements of any environment if you really want to develop on the level of JDBC drivers.
This specific question of yours is something that - I believe - is the motivation to develop things like:
ODBC
JNDI
NOTE 1 even similar naming ODBC & JDBC are totally in different level (I mean how JDBC drivers are found which actually might be the main problem...)
NOTE 2 JNDI is not restricted to DataSources
However maven can be a great help depending on what you need and finally decide to do. But not in so big role if you can use ODBC / JNDI.

How to use FlywayDB without align databases with Production dump?

I'd like to start using a flyway to keep our different db environments synced.
The problem I have is that we can't align all the environments using a Prod dump on test and dev since our Prod env contains sensitive data that testers and developers can't access.
I understand that to start using flyway on an existing environment the steps are:
Create Prod dump
Execute Flyway Init
Align Test with prod dump
Execute Flyway Clean on Dev
Execute prod dump on Dev
Start using flyway migration normaly
I based on Axel Fontaine's video on minute 32:00 maybe there is another way to achieve this. So the question is how can I do to use flyway without using a production dump? Any help or idea?
As as I said in the talk, dump the structure and the reference data. These are the things you will be managing using Flyway. The application data doesn't need to be dumped.
What you want is the structure and the reference data to be in sync, not the application data.

How should I do this? I can't use jUnit etc

I am working on a Spring Webflow programming using MySQL has the database.
I have some jUnit test cases that Maven runs on the build that uses a test database base not the dev database. we have a diff database for running the projects in dev then the builds.
I have some test data that I need setup in dev before running my project. I was using jUnit for it as part of the package/test in maven but the issue is that test is using diff xml and database. how do you think I can go about making the project remove some delete in dev before running.. Does anyone know of any MySQL plugin for maven that will run a script before?
I'm not entirely sure what you're asking, but I think you want to have certain data available in a DB when you run tests and that data is different in different environments.
Given you're already using maven I would suggest you set up build profiles for each environment, which will allow you to specify different DB connections, indeed if you implement an ORM such as hibernate, you can even get the DB schema and data dropped and recreated on each run in your test / dev environments.
Further more, in environments where you want the data to be specific to your test run and the data does not need to persist beyond the scope of your tests, implement an in memory DB, such as HSQL which can be seeded with data as required and wiped at the end, this will make your development environment more suitable for larger numbers of developers and remove the need for physical DB resources.
I think you're asking about how to set up a database before running a Junit test. If so, I suggest you look at DBUnit and (as suggested in another answer) an in-memory database.

How to use separate databases for production and testing in an eclipse RCP app

I am writing an eclipse RCP app and I am trying to use a separate db for tests to prevent corrupting my production db. During the setup of the test db i need to execute an sql file to fill it with test data.
Is there a way to tell the app to use a different db and execute a specific sql script (maybe via launch properties or maybe fragments or sth else)?
Thank you
I found and am using a different approach now, more RCP-ish IMHO. I define a fragment to override the database props and replacing a dummy query file in the host plug-in. Then i define two features - one for the testing with the fragment, and the production feature without the fragment. And then use the features in different products - one for production, one for testing. Works fine
Sounds like a perfect use-case for OSGi Services.
Your application will accept arguments like the Eclipse executable. You can specify the arguments in the ini file of your app (in Eclipse it is eclipse.ini, you can rename it for your app) in the form of
-vmargs
-Dkey=value
These values can be read using System.getProperty
On some platforms you should be able to accept these arguments from the command line as well.
For an RCP I usually use some type of property file. Within it I'd specify things such as the DB to use and startup script (if necessary). This approach will be well worth it as your application grows.

Categories