When you use a relational database, you need a way to track and organize your database schema evolutions. Typically there are several situation where you need a more sophisticated way to track your database schema changes:

  • When you work within a team of developers, each person needs to know about any schema change.
  • When you deploy on a production server, you need to have a robust way to upgrade your database schema.
  • If you work on several machines, you need to keep all database schemas synchronized.

If you work with JPA, Hibernate can handle database evolutions for you automatically. Evolutions are useful if you don’t use JPA or if you prefer to manually take care of your database schema for finer tuning.

Evolutions scripts

Play tracks your database evolutions using several evolutions script. These scripts are written in plain old SQL and should be located in the db/evolutions directory of your application.

The first script is named 1.sql, the second script 2.sql, and so on…

Each script contains two parts:

  • The Ups part the describe the required transformations.
  • The Downs part that describe how to revert them.

For example, take a look at this first evolution script that bootstrap a basic application:

# Users schema

# --- !Ups

CREATE TABLE User (
id bigint(20) NOT NULL AUTO_INCREMENT,
email varchar(255) NOT NULL,
password varchar(255) NOT NULL,
fullname varchar(255) NOT NULL,
isAdmin boolean NOT NULL,
PRIMARY KEY (id)
); # --- !Downs DROP TABLE User;

As you see you have to delimitate the both Ups and Downs section by using comments in your SQL script.

When evolutions are activated, Play will check your database schema state before each request in DEV mode, or before starting the application in PROD mode. In DEV mode, if your database schema is not up to date, an error page will suggest that you to synchronize your database schema by running the appropriate SQL script.

If you agree with the SQL script, you can apply it directly by clicking on the ‘Apply evolutions’ button.

If you use an in-memory database (db=mem), Play will automatically run all evolutions scripts if your database is empty.

Synchronizing concurrent changes

Now let’s imagine that we have two developers working on this project. Developer A will work on a feature that require a new database table. So it will create the following 2.sql evolution script:

# Add Post

# --- !Ups
CREATE TABLE Post (
id bigint(20) NOT NULL AUTO_INCREMENT,
title varchar(255) NOT NULL,
content text NOT NULL,
postedAt date NOT NULL,
author_id bigint(20) NOT NULL,
FOREIGN KEY (author_id) REFERENCES User(id),
PRIMARY KEY (id)
); # --- !Downs
DROP TABLE Post;

Play will apply this evolution script to Developer A’s database.

On the other hand, developer B will work on a feature that require to alter the User table. So it will also create the following 2.sql evolution script:

# Update User

# --- !Ups
ALTER TABLE User ADD age INT; # --- !Downs
ALTER TABLE User DROP age;

Developer B finishes his feature and commit (let’s say they are using Git). Now developer A has to merge the work of his colleague before continuing, so it run git pull, and the merge has a conflict, like:

Auto-merging db/evolutions/2.sql
CONFLICT (add/add): Merge conflict in db/evolutions/2.sql
Automatic merge failed; fix conflicts and then commit the result.

Each developer has created a 2.sql evolution script. So developer A needs to merge the content of this file:

<<<<<<< HEAD
# Add Post # --- !Ups
CREATE TABLE Post (
id bigint(20) NOT NULL AUTO_INCREMENT,
title varchar(255) NOT NULL,
content text NOT NULL,
postedAt date NOT NULL,
author_id bigint(20) NOT NULL,
FOREIGN KEY (author_id) REFERENCES User(id),
PRIMARY KEY (id)
); # --- !Downs
DROP TABLE Post;
=======
# Update User # --- !Ups
ALTER TABLE User ADD age INT; # --- !Downs
ALTER TABLE User DROP age;
>>>>>>> devB

The merge is really easy to do:

# Add Post and update User

# --- !Ups
ALTER TABLE User ADD age INT; CREATE TABLE Post (
id bigint(20) NOT NULL AUTO_INCREMENT,
title varchar(255) NOT NULL,
content text NOT NULL,
postedAt date NOT NULL,
author_id bigint(20) NOT NULL,
FOREIGN KEY (author_id) REFERENCES User(id),
PRIMARY KEY (id)
); # --- !Downs
ALTER TABLE User DROP age; DROP TABLE Post;

This evolution script represents the new revision 2 of the database, that is different of the previous revision 2 that developer A has already applied.

So Play will detect it and ask developer A to synchronize his database by first reverting the old revision 2 already applied, and by applying the new revision 2 script:

Inconsistent states

Sometimes you will make a mistake in your evolution scripts, and they will fail. In this case, Play will mark your database schema as being in an inconsistent state and will ask you to manually resolve the problem before continuing.

For example, the Ups script of this evolution has an error:

# Add another column to User

# --- !Ups
ALTER TABLE Userxxx ADD company varchar(255); # --- !Downs
ALTER TABLE User DROP company;

So trying to apply this evolution will fail, and Play will mark your database schema as inconsistent:

Now before continuing you have to fix this inconsistency. So you run the fixed SQL command:

ALTER TABLE User ADD company varchar(255);

… and then mark this problem as manually resolved by clicking on the button.

But because you evolution script has error, you probably want to fix it. So you modify the 3.sql script:

# Add another column to User

# --- !Ups
ALTER TABLE User ADD company varchar(255); # --- !Downs
ALTER TABLE User DROP company;

Play detects this new evolution that replaces the previous 3 one, and will run the following script:

Now everything is fixed, and you can continue to work.

In developement mode however it is often simpler to simply trash your developement database and reapply all evolutions from the beginning.

Evolutions commands

The evolutions run interactively in DEV mode. However in PROD mode you will have to use theevolutions command to fix your database schema before running your application.

If you try to run a application in production mode on a database that is not up to date, the application will not start.

~        _            _
~ _ __ | | __ _ _ _| |
~ | '_ \| |/ _' | || |_|
~ | __/|_|\____|\__ (_)
~ |_| |__/
~
~ play! master-localbuild, http://www.playframework.org
~ framework ID is prod
~
~ Ctrl+C to stop
~
13:33:22 INFO ~ Starting ~/test
13:33:22 INFO ~ Precompiling ...
13:33:24 INFO ~ Connected to jdbc:mysql://localhost
13:33:24 WARN ~
13:33:24 WARN ~ Your database is not up to date.
13:33:24 WARN ~ Use `play evolutions` command to manage database evolutions.
13:33:24 ERROR ~ @662c6n234
Can't start in PROD mode with errors Your database needs evolution!
An SQL script will be run on your database. play.db.Evolutions$InvalidDatabaseRevision
at play.db.Evolutions.checkEvolutionsState(Evolutions.java:323)
at play.db.Evolutions.onApplicationStart(Evolutions.java:197)
at play.Play.start(Play.java:452)
at play.Play.init(Play.java:298)
at play.server.Server.main(Server.java:141)
Exception in thread "main" play.db.Evolutions$InvalidDatabaseRevision
at play.db.Evolutions.checkEvolutionsState(Evolutions.java:323)
at play.db.Evolutions.onApplicationStart(Evolutions.java:197)
at play.Play.start(Play.java:452)
at play.Play.init(Play.java:298)
at play.server.Server.main(Server.java:141)

The error message ask you to run the play evolutions command:

$ play evolutions
~ _ _
~ _ __ | | __ _ _ _| |
~ | '_ \| |/ _' | || |_|
~ | __/|_|\____|\__ (_)
~ |_| |__/
~
~ play! master-localbuild, http://www.playframework.org
~ framework ID is gbo
~
~ Connected to jdbc:mysql://localhost
~ Application revision is 3 [15ed3f5] and Database revision is 0 [da39a3e]
~
~ Your database needs evolutions! # ---------------------------------------------------------------------------- # --- Rev:1,Ups - 6b21167 CREATE TABLE User (
id bigint(20) NOT NULL AUTO_INCREMENT,
email varchar(255) NOT NULL,
password varchar(255) NOT NULL,
fullname varchar(255) NOT NULL,
isAdmin boolean NOT NULL,
PRIMARY KEY (id)
); # --- Rev:2,Ups - 9cf7e12 ALTER TABLE User ADD age INT;
CREATE TABLE Post (
id bigint(20) NOT NULL AUTO_INCREMENT,
title varchar(255) NOT NULL,
content text NOT NULL,
postedAt date NOT NULL,
author_id bigint(20) NOT NULL,
FOREIGN KEY (author_id) REFERENCES User(id),
PRIMARY KEY (id)
); # --- Rev:3,Ups - 15ed3f5 ALTER TABLE User ADD company varchar(255); # ---------------------------------------------------------------------------- ~ Run `play evolutions:apply` to automatically apply this script to the db
~ or apply it yourself and mark it done using `play evolutions:markApplied`
~

If you want Play to automatically run this evolution for you, then run:

$ play evolutions:apply

If you prefer running this script manually on your production database, you need to tell Play that you database is up-to-date by running:

$ play evolutions:markApplied

If there are any errors while automatically running the evolutions scripts, as in DEV mode, you need to manually resolve them, and mark your database schema a fixed by running:

$ play evolutions:resolve

Continuing the discussion

Learn how to configure Logging.

Managing database evolutions的更多相关文章

  1. Database SQL script automation management tools investigation

    Recently researched about database SQL scripts auto management tools, recorded the results here. Res ...

  2. 1Z0-053 争议题目解析

    1Z0-053 争议题目解析 Summary 题目NO. 题目解析链接地址 题库答案 参考答案 考查知识点  24 http://www.cnblogs.com/jyzhao/p/5319220.ht ...

  3. Oracle OCP 1Z0-053 Exam Topics

    根据OU官方发布的考试大纲,OCP 1Z0-053考点如下: 1. Database Architecture and ASM Describe Automatic Storage Managemen ...

  4. [转]Design Pattern Interview Questions - Part 4

    Bridge Pattern, Composite Pattern, Decorator Pattern, Facade Pattern, COR Pattern, Proxy Pattern, te ...

  5. 使用DBMS_STATS来收集统计信息【转】

    overview Oracle's cost-based optimizer (COB) uses statistics to calculate the selectivity (the fract ...

  6. Oracle_OCP课程实验学习

    Linux启动oracl.查看lsnrctl状态,然后启动监听start.sqlplus / as sysdba 启动数据库.conn sys/jxsrpv as sysdba .startup Ad ...

  7. android-SQLite 和 Content

    SQLite 游标(Cursor)相当于指向底层数据中结果集的指针,而不是提取和返回结果值的副本,是在结果集中对位置(行)进行控制的管理方式. moveToFirst:把游标移动到查询结果的第一行 m ...

  8. OCA读书笔记(7) - 管理数据库存储结构

    7.Managing Database Storage Structures 逻辑结构 数据库的存储结构有物理结构和逻辑结构组成的 物理结构:物理上,oracle是由一些操作系统文件组成的 SQL&g ...

  9. Oracle 11g OCM 考试大纲

    考试大纲共分9部分.   一.Server Configuration 服务器配置 1  Create the database 创建数据库 2  Determine and set sizing p ...

随机推荐

  1. struts1一:基本简介

    struts是开源框架.使用Struts的目的是为了帮助我们减少在运用MVC设计模型来开发Web应用的时间.如果我们想混合使用Servlets和JSP的优点来建立可扩展的应用,struts是一个不错的 ...

  2. Atitit 深入理解耦合Coupling的原理与attilax总结

    Atitit 深入理解耦合Coupling的原理与attilax总结     耦合是指两个或两个以上的电路元件或电网络等的输入与输出之间存在紧密配合与相互影响,并通过相互作用从一侧向另一侧传输能量的现 ...

  3. Atitit xml命名空间机制

    Atitit xml命名空间机制 命名冲突1 使用前缀来避免命名冲突2 使用命名空间(Namespaces)2 XML Namespace (xmlns) 属性2 默认的命名空间(Default Na ...

  4. 一起学微软Power BI系列-官方文档-入门指南(3)Power BI建模

    我们前2篇文章:一起学微软Power BI系列-官方文档-入门指南(1)Power BI初步介绍 和一起学微软Power BI系列-官方文档-入门指南(2)获取源数据 中,我们介绍了官方入门文档与获取 ...

  5. Android okHttp网络请求之Retrofit+Okhttp+RxJava组合

    前言: 通过上面的学习,我们不难发现单纯使用okHttp来作为网络库还是多多少少有那么一点点不太方便,而且还需自己来管理接口,对于接口的使用的是哪种请求方式也不能一目了然,出于这个目的接下来学习一下R ...

  6. 图的广度优先搜索(BFS)

    把以前写过的图的广度优先搜索分享给大家(C语言版) #include<stdio.h> #include<stdlib.h> #define MAX_VERTEX_NUM 20 ...

  7. C算法编程题(六)串的处理

    前言 上一篇<C算法编程题(五)“E”的变换> 连续写了几篇有关图形输出的编程题,今天说下有关字符串的处理. 程序描述 在实际的开发工作中,对字符串的处理是最常见的编程任务.本题目即是要求 ...

  8. C# Excel 为图表添加模拟运算表

    Excel中的图表能够将数据可视化,方便我们比较分析数据.但也有一定的局限,例如:不能够直接从图表中读出原来数据的准确值.Excel提供的解决方案是,在图表下方添加一个模拟运算表,即在坐标轴下方添加包 ...

  9. 2015-10-22 前思后想,决定重构表结构,免得这个APP死在数据表设计上

    新的设计稿出来了,如下,原来旧的是第二张       -------  原来的评论级数只有2级,现在是不限,2级的意思是,用户评论该帖是一级,用户的评论能被人评论,这是第2级,评论评论的评论不能够再被 ...

  10. unbuntu14.04 安装nginx配置

    记录一下linux下安装nginx的所需要的配置. 首先从 nginx官网 下载所需要的版本,复制链接,执行 wget http://nginx.org/download/nginx-1.8.0.ta ...