User Tools
Writing /app/www/public/data/meta/development/database_migration.meta failed
development:database_migration
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| development:database_migration [2018/09/19 11:03] – adowling | development:database_migration [2021/06/25 10:09] (current) – external edit 127.0.0.1 | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| + | ====== Database Upgrade Scripts Process ====== | ||
| + | --- // | ||
| + | |||
| + | The scripts are located in each project that the scripts need to be run for i.e. Snmp Manager upgrade scripts are in the Snmp Manager codebase | ||
| + | |||
| + | Presentation on this : | ||
| + | https:// | ||
| + | |||
| + | ===== SQL File Checklist ===== | ||
| + | * Adding a column/ | ||
| + | * Dropping a column/ | ||
| + | * Creating a table has if not exists statement | ||
| + | * Drop table has an if exists statement | ||
| + | * INSERTS specify the order and values i.e. INSERT INTO table(col1, col2) values(1,2) is valid. INSERT INTO table values(1,2) IS NOT VALID.(A quick way to generate insert statements in the correct ordering is show below in section **Generate INSERTS from Workbench**.) | ||
| + | * UPDATE/ | ||
| + | * ids should not be inserted or update where possible, MySQL should be left to autogenerate the ids | ||
| + | * specific customer data should be wrapped in if customer name condition | ||
| + | * when inserting into a table with a version, remember to set that to 0 in the insert | ||
| + | * Ensure INSERTS/ | ||
| + | |||
| + | |||
| + | ===== Naming Convention ===== | ||
| + | |||
| + | * Flyway is being used to automatically run the SQL scripts in all our deployed projects (if not, contact Colm) | ||
| + | * Currently we use older plugin to get free usage of it with MySQL 5.1 (it also works with 5.5 and onwards) | ||
| + | * There is a naming convention for scripts : < | ||
| + | * The format is V followed by the next number, followed by 2 underscores and then a short description | ||
| + | |||
| + | ===== Where are they located ===== | ||
| + | It depends on the project for Grails 2 and 3 they are in : | ||
| + | < | ||
| + | grails-app/ | ||
| + | </ | ||
| + | |||
| + | For Spring Boot apps they are in : | ||
| + | < | ||
| + | src/ | ||
| + | </ | ||
| + | |||
| + | ===== How do I know what number to take ===== | ||
| + | * A channel has been created which you should join called **sql-upgrade-scripts** | ||
| + | * When you want to make a new script send a message out in this channel say you are for instance making a new script in the Ticketer, a message would look like :< | ||
| + | * This makes life easier so if we are both working on the Ticketer I can then take V5 and not V4 | ||
| + | |||
| + | ===== Dos and Don'ts ===== | ||
| + | * Never ever ever ever ever ever ever ever ever….ever edit a script once it has been pushed and run on production...ever | ||
| + | * In general, always make a new script if you need to do something, if you edit the script flyway will know via the checksum and prevent the application from starting! | ||
| + | * For customer specific inserts/ | ||
| + | * Try keep the DB backwards compatible for up to 2 releases so rolling back of the DB is never needed. To do this, if a column should be dropped make a ticket to drop this column in the next release or for the one after. | ||
| + | |||
| + | ===== Stored Procedure Example ===== | ||
| + | < | ||
| + | /* For Customer Specific Inserts/ | ||
| + | DELIMITER // | ||
| + | DROP PROCEDURE IF EXISTS load_of_dummy_inserts // | ||
| + | CREATE PROCEDURE load_of_dummy_inserts() | ||
| + | |||
| + | BEGIN | ||
| + | | ||
| + | IF @customerName = ' | ||
| + | | ||
| + | id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY, | ||
| + | | ||
| + | | ||
| + | ); | ||
| + | | ||
| + | END IF; | ||
| + | END; // | ||
| + | |||
| + | CALL load_of_dummy_inserts() // | ||
| + | DROP PROCEDURE IF EXISTS load_of_dummy_inserts // | ||
| + | DELIMITER ; | ||
| + | </ | ||
| + | |||
| + | ===== Create Customer Table ===== | ||
| + | < | ||
| + | CREATE TABLE IF NOT EXISTS errigal_customer ( | ||
| + | name VARCHAR(255) NOT NULL | ||
| + | ); | ||
| + | |||
| + | INSERT INTO errigal_customer(name) values(CUST_ABBREVIATION); | ||
| + | </ | ||
| + | |||
| + | ===== Current Customer' | ||
| + | |||
| + | ^ ServerEnv | ||
| + | | atcqa | ATC | ||
| + | | atcprod | ||
| + | | nvqa | ATC | | ||
| + | | ccprod | ||
| + | | errigalqa | ||
| + | | qa | CC | | ||
| + | | idmsqa | ||
| + | | sfqa | EXT | | ||
| + | | extqa | EXT | | ||
| + | | extprod | ||
| + | | scottypro | ||
| + | |||
| + | ===== Recommended way to create the scripts ===== | ||
| + | - run the app with ddl_auto set to update | ||
| + | - export the DDL for newly created tables (or extract the new columns for ALTER commands) | ||
| + | - make sure the tables/ | ||
| + | - for any apps that are using table based sequences (e.g. fiber, the tables usually have the //_SEQ// sufix), provide inserts for the sequence table (look at [[https:// | ||
| + | - prepare your Flyway script (it is also recommended to create a rollback script for further steps) | ||
| + | - stop the application | ||
| + | - rollback the changes (possibly using the rollback script created above) | ||
| + | - put your Flyway script into the right location of the project (documented in the sections above) | ||
| + | - run the app again, verify logs for Flyway messages (upgrading the schema) and possibly test the new tables via application | ||
| + | - repeat until it all works | ||
| + | |||
| + | |||
| + | ===== Rules for the scripts ===== | ||
| + | These rules are elaboration of what has been mentioned //Dos and Don' | ||
| + | * Never change a name of a table or column in the DB | ||
| + | * if this is really needed then you should create a new field and make the current application work with both fields (writing to both of them) until the old field gets deprecated | ||
| + | * Never change a type of a column (unless increasing size of the string types) | ||
| + | * if this is really needed then you should create a new field (with new type) and make the current application work with both fields (writing to both of them, reading from the new) until the old field gets deprecated (more on that below) | ||
| + | * Never drop a table or a column (unless it is time to deprecate it - more on that below) | ||
| + | * You should generally only add new columns and tables | ||
| + | |||
| + | ===== Deprecating the fields or tables ===== | ||
| + | If you think some of the fields/ | ||
| + | * Field/ | ||
| + | * Deprecated in, sample: 3.4 | ||
| + | * To be removed in, sample: 3.6 | ||
| + | * Action, sample: Remove from the domain, create flyway script to drop the column, inform all customers about the change (ahead) | ||
| + | |||
| + | |||
| + | ===== Add a column to a table ===== | ||
| + | Always make sure the column does not already exists first | ||
| + | < | ||
| + | DELIMITER // | ||
| + | DROP PROCEDURE IF EXISTS add_column // | ||
| + | CREATE PROCEDURE add_column() | ||
| + | |||
| + | BEGIN | ||
| + | DECLARE colName TEXT; | ||
| + | SELECT column_name INTO colName | ||
| + | FROM information_schema.columns | ||
| + | WHERE table_schema = ' | ||
| + | AND table_name = ' | ||
| + | AND column_name = ' | ||
| + | |||
| + | IF colName is null THEN | ||
| + | ALTER TABLE the_table ADD COLUMN the_column THE_TYPE; | ||
| + | END IF; | ||
| + | END// | ||
| + | |||
| + | CALL add_column() // | ||
| + | |||
| + | DROP PROCEDURE IF EXISTS add_column // | ||
| + | DELIMITER ; | ||
| + | </ | ||
| + | |||
| + | ===== Drop a column from a table ===== | ||
| + | Only do this if the field has not been used for 2 or more releases ago | ||
| + | < | ||
| + | DELIMITER // | ||
| + | DROP PROCEDURE IF EXISTS remove_column // | ||
| + | CREATE PROCEDURE remove_column() | ||
| + | |||
| + | BEGIN | ||
| + | DECLARE colName TEXT; | ||
| + | SELECT column_name INTO colName | ||
| + | FROM information_schema.columns | ||
| + | WHERE table_schema = ' | ||
| + | AND table_name = ' | ||
| + | AND column_name = ' | ||
| + | |||
| + | IF colName is not null THEN | ||
| + | ALTER TABLE the_table DROP COLUMN the_column; | ||
| + | END IF; | ||
| + | END// | ||
| + | |||
| + | CALL remove_column() // | ||
| + | |||
| + | DROP PROCEDURE IF EXISTS remove_column // | ||
| + | DELIMITER ; | ||
| + | </ | ||
| + | |||
| + | =====Generate INSERTS from Workbench ===== | ||
| + | In MySQL workbench you can export an insert statement, which gives you the full column order for that table if you are unsure of your insert statement. | ||
| + | To get this select a row from a table for example: | ||
| + | < | ||
| + | select * from ticketer.ticket where id = 10; | ||
| + | </ | ||
| + | |||
| + | In the results you will see above the row a save icon with the name Export/ | ||
| + | {{ : | ||
| + | Click this and select the Format of SQL INSERT statements to save the sql export as: | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | |||
| + | :!: Open the exported file and **remove the smart quotes** around column names and also **remove the id column and its associated value.** Set the version number to 0 for the insert you are creating and you should have a correctly ordered and formatted insert statement to use for the table you exported.: | ||
| + | |||
| + | |||
| + | |||
| + | ===== Troubleshooting ===== | ||
| + | To troubleshoot the Flyway scripts - make sure to understand how it works by reading [[https:// | ||
| + | Flyway logs it's initialisation with following logs, so that is the first place to look at when something doesn' | ||
| + | < | ||
| + | 2018-09-14 11: | ||
| + | 2018-09-14 11: | ||
| + | 2018-09-14 11: | ||
| + | 2018-09-14 11: | ||
| + | 2018-09-14 11: | ||
| + | </ | ||
| + | |||
| + | Flyway allows the application to run in the rollback scenario - e.g. if the DB is version 4, but the app has just version 3 it will run anyway. | ||
| + | Flyway will fail to start in following situations: | ||
| + | * Any of the migrations (records in schema_version) in the DB is different to what is in the application (so changing already applied scripts will cause this) | ||
| + | * This should generally only happen locally (otherwise it is very bad) for 2 reasons - you changed some of the older scripts, or you changed the last script that you are developing | ||
| + | * Solution (only **locally for the last script**, which you are developing) is to manually rollback all the changes performed by the script and delete the last record in the schema_version table, fix the script and run the app again | ||
| + | * The new script fails for some reason on the DB level (typo, bad column names, etc.) | ||
| + | * The same rules/ | ||