I don't understand the detailed steps when rolling back using Liquibase.
I had scenario like 6 changesets and for one changeSet rollback was not defined - that is, only <rollback/> within the changeset.
After executing using deployIT I could see 7 entries in Databasechangelog table, 6 for added, one for tag creation due usage of deployIT.
After rolling back I saw the behavior of removing all newly added 6 changesets even though one of the six changesets had an empty rollback tag.
Please any expert tell me why? What is the exact behavior of rollback?
Overall want to know when records from Databasechangelog removed ?
When running rollback, liquibase finds the changeSets to roll back, and then checks for a <rollback> tag in each describing how to roll the changeSet back.
If there is no <rollback> tag, then Liquibase checks if the changes in the changeSet have built-in logic on how to roll themselves back. Like gile pointed out, if there is enough information in the change to undo it (like how the createTable change has the table name needed to drop the table) it will be able to still roll them back.
But if there isn't enough information in the change (like how a dropTable doesn't have the information needed to re-create the table) then the rollback command will fail with a "cannot roll back" error.
So the rollback logic is:
Use what is defined in a block
If no rollback block, try to deduce what is needed
If there isn't enough information to roll back, exit before rolling back
If you specify an empty rollback block, you are telling Liquibase "the logic needed to roll this back is to do nothing", so Liquibase happily runs your no-op rollback command and marks the changeSet as rolled back.
Depending on your change sets, may be you fall in case of statements having rollback commands generated automatically, as for Liquibase Rollback documentation:
Many refactorings such as “create table”, “rename column”, and “add
column” can automatically create rollback statements. If your change
log contains only statements that fit into this category, your
rollback commands will be generated automatically.
Other refactorings such as “drop table” and “insert data” have no
corresponding rollback commands that can be automatically generated.
In these cases, and cases where you want to override the default
generated rollback commands, you can specify the rollback commands via
the tag within the changeSet tag. If you do not want anything done to
undo a change in rollback mode, use an empty tag.
At http://forum.liquibase.org/topic/understanding-rollback you can find more details and other links.
Related
I learned that Liquibase runs each changeSet in a transaction and commits it after inserting into the DATABASECHANGELOG table.
If something goes wrong during the changeSet, the transaction gets rolled back.
My question is, what happens if the changeSet also includes a <rollback> tag.
I know that the rollback tags are used in combination with liquibase dedicated rollback commands, but which one has precedence during a regular migration, the command from the rollback tag or the transaction abortion?
The <rollback> block is not used in when an update fails. If the update fails, Liquibase just calls "rollback" on the connection and relies on the database to correctly roll things back. The <rollback> block is only used when doing the separate rollback command where we're "undoing" the changeset that was already committed in the database.
NOTE: the fact that Liquibase relies on the connection rollback to revert a failed update is why you have to be careful if you have multiple statements in the same changeSet. If you have two createTable calls and your the database auto-commits after the first and the second fails, the rollback on the connection will not roll back the first table. So when you run update the next time, you'll get a table already exists error from the first createTable. The rules on exactly what statements auto-commit are database-specific, so the good rule of thumb is "only one statement per changeset"
What would be the rollback of droptable:
- changeSet:
id: 1
author: vikas
changes:
- sql:
sql: DROP TABLE IF EXISTS `adapter`
What should I put in rollback for the above changeset.
I am getting below error when I was trying to rollback without having rollback tag:
Error setting up or running Liquibase: liquibase.exception.RollbackImpossibleException: No inverse to liquibase.change.core.RawSQLChange created
The error
Error setting up or running Liquibase: liquibase.exception.RollbackImpossibleException: No inverse to liquibase.change.core.RawSQLChange created
happens because you use raw sql, and not the appropriate tag for it (it would be dropTable), so liquibase doesn't know what to do with it. It can't create a rollback.
Also, the documentation says that
Other refactorings such as “drop table” and “insert data” have no corresponding rollback commands that can be automatically generated. In these cases, and cases where you want to override the default generated rollback commands, you can specify the rollback commands via the tag within the changeSet tag. If you do not want anything done to undo a change in rollback mode, use an empty tag.
So you'll have to create a proper rollback for drop table operation.
If i run change log file that contain multiple change set from command line and it failed because of wrong sql at say change set 2. So change set 1 has executed and committed then how will i rollback this change using liquibase.
The easiest would be to use the rollbackCount command. Running "liquibase rollbackCount 1" will roll back the last changeSet executed using either the specified <rollback> block in the changeSet or by figuring it out if Liquibaes can based on the information in the changeSet. For example, a createTable command has the information needed to create a drop table statement, but a dropTable command does not have the information needed to do a create table so you would need to specify your own rollback block.
I want to understand better how Liquibase executes change sets.
1)
a) For example I have a change log with 4 change sets and I execute updateDatabase (http://www.liquibase.org/documentation/ant/updatedatabase_ant_task.html).
Liquibase will execute 4 change sets.
b) If I run the same change log once again Liquibase not execute any set.
c) If I will add a new change set to the change log and will run the change log Liquibase will execute the new change set only.
Questions:
How Liquibase knows what change sets to execute?
How Liquibase knows what change sets already executed?
2) How change set ID is important? Can I change it after a change log execution?
3) How change set author is important? Can I change it after a change log execution?
4) What happens if I will execute the rollbackDatabase (http://www.liquibase.org/documentation/ant/rollbackdatabase_ant_task.html)?
How Liquibase knows what change sets to rollback?
a) What happens if I will execute the rollback after 1 a).
Will Liquibase call to rollback element that is located in each change sets (4 rollback elements)?
b) What happens if I will execute the rollback after 1 b).
How Liquibase will know not to call to any to rollback element?
c) What happens if I will execute the rollback after 1 c).
Will Liquibase call to rollback element of only the new change set?
I can answer a few questions, perhaps not all though.
c. - Liquibase creates 2 new tables in the database when you do the first update. The main table is DATABASECHANGELOG, and that is used to keep track of what change sets have been applied to the database. Liquibase uses a couple of ways to identify each changeset - the id, author, and path are used as a composite key. Liquibase also generates a checksum of each changeset that is used to tell whether the changeset has been altered after being applied to the database.
and 3. Because the change set id and author are used as part of the primary key, if you deploy, then change either one of those, you may run into unexpected behavior on subsequent deploys. I think that the id and author are also part of the checksum calculation, so that might affect things also. I would recommend that you do not change those after deploying.
Rollback uses the same mechanism to know what change sets to roll back. When you roll back you have to specify in some way what changes to undo - see this page for more info: http://www.liquibase.org/documentation/rollback.html
The rollback identification mechanisms are by tag (which means you have to apply tags when you deploy), by date (Liquibase keeps track of when each changeset was deployed), or by number (which implicitly uses the date/time of when each changeset was deployed).
I have a problem to solve which requires undo operation of each executed sql file in Oracle Database.
I execute them in an xml file with MSBuild - exec command sqlplus with log in and #*.sql.
Obviously rollback won't do, because it can't rollback already commited transaction.
I have been searching for several days and still can't find the answer. What I learned is Oracle Flashback and Point in Time Recovery. The problem is that I want the changes to be undone only for the current user i.e. if another user makes some changes at the same time then my solution performs undo only on user 'X' not 'Y'.
I found the start_scn and commit_scn in flashback_transaction_query. But does it identify only one user? What if I flashback to a given SCN? Will that undo only for me or for other users as well? I have taken out
select start_scn from flashback_transaction_query WHERE logon_user='MY_USER_NAME'
and
WHERE table_name = "MY_TABLE NAME"
and performed
FLASHBACK TO SCN"here its number"
on a chosen operation's SCN. Will that work for me?
I also found out about Point in Time Recovery but as I read it makes the whole database unavailable so other users will be unable to work with it.
So I need something that will undo a whole *.sql file.
This is possible but maybe not with the tools that you use. sqlplus can rollback your transaction, you just have to make sure auto commit isn't enabled and that your scripts only contain a single commit right before you end the sqlplus session (if you don't commit at all, sqlplus will always roll back all changes when it exits).
The problems start when you have several scripts and you want, for example, to rollback a script that you ran yesterday. This is a whole new can of worms and there is no general solution that will always work (it's part of the "merge problem" group of problems, i.e. how can you merge transactions by different users when everyone can keep transactions open for as long as they like).
It can be done but you need to carefully design your database for it, the business rules must be OK with it, etc.
To general approach would be to have a table which contains the information which rows were modified (= created,updated,deleted) by the script plus the script name plus the time when it was executed.
With this information, you can generate SQL which can undo the changes created by a script. To fill such a table, use triggers or generate your scripts in such a way that they write this information as well (note: This is probably beyond a "simple" sqlplus solution; you will have to write your own data loader for this).
Ok I solved the problem by creating a DDL and DML TRIGGER. The first one takes "extra" column (which is the DDL statement you have just entered) from v$open_cursor and inserts into my table. The second gets "undo_sql" from flashback_transaction_query which is the opposite action of your DML action - if INSERT then undo_sql is DELETE with all necessary data.
Triggers work before DELETE,INSERT (DML) on specific table and ALTER,DROP,CREATE (DDL) on specific SCHEMA or VIEW.