昨天和澎湃聊了这个事情,当时的想法是数据库中有表记录版本,项目代码中存储变更脚本.无意中看到数据库版本控制工具liquibase.最开始还是有点担心,怕这东西把数据库玩坏了.看了看官方文档,再粗略看了下主流程的源代码,发掘下我想要的功能,这个工具已经足够强大了,我们用好就行.

下面以cs为例,讲讲整个过程.

1. 在cs-dal中添加maven依赖.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    <build>
        <plugin>
            <groupId>org.liquibase</groupId>
            <artifactId>liquibase-maven-plugin</artifactId>
            <version>3.2.2</version>
            <configuration>
                <!--数据库变更主文件-->
                <changeLogFile>src/main/resources/db/changelog/db.master.xml</changeLogFile>
                <!--数据库相关配置文件-->
                <propertyFile>src/main/resources/db/config/dal-${spring.profiles.active}.properties</propertyFile>
            </configuration>
            <executions>
                <execution>
                    <phase>process-resources</phase>
                    <goals>
                        <goal>update</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

2. 编写数据库变更脚本

2.1 数据库变更主文件

1
db.master.xml
:

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
    xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
     http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.2.xsd">
	<!--数据库变更文件.注意:保证顺序,脚本执行顺序和include的先后有关系.includeAll可以加载所有脚本,加载顺序和文件命名有关系,容易犯错误,建议不使用.-->
	<include relativeToChangelogFile="true" file="db.1.0.sql"/>
   		<include relativeToChangelogFile="true" file="db.2.0.sql"/>
</databaseChangeLog>

2.2 变更脚本

1
db.1.0.sql
:

1
2
3
4
5
6
7
8
--liquibase formatted sql

--changeset qiubo:1
create table test1 (
	id int primary key,
	name varchar(255)
);
--rollback drop table test1;

1
db.2.0.sql
:

1
2
3
4
5
--liquibase formatted sql

--changeset qiubo:2
insert into test1 (id, name) values (1, 'name 1');
insert into test1 (id, name) values (2, 'name 2');

语法参考:http://www.liquibase.org/documentation/sql_format.html

2.3 数据库配置文件

dal-local.properties

1
2
3
4
5
6
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/yjf_cs?useUnicode=true&characterEncoding=UTF8&zeroDateTimeBehavior=convertToNull
username=root
password=root
#数据库schema名
changelogSchemaName=yjf_cs

建议大家把原来的数据库配置文件中的key改为和这个一致,没必要搞多份配置.

3.路径结构

确保xxx-dal如下的路径结构,请大家统一:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|---pom.xml
|---src
|    |---main
|    |    |---java
|    |    |---resources
|    |    |        |---db
|    |    |        |    |---changelog
|    |    |        |    |        |---db.1.0.sql
|    |    |        |    |        |---db.2.0.sql
|    |    |        |    |        |---db.master.xml
|    |    |        |    |---config
|    |    |        |    |     |---dal-dev.properties
|    |    |        |    |     |---dal-local.properties
|    |    |        |    |     |---dal-net.properties
|    |    |        |    |     |---dal-online.properties
|    |    |        |    |     |---dal-pnet.properties
|    |    |        |    |     |---dal-sdev.properties
|    |    |        |    |     |---dal-snet.properties
|    |    |        |    |     |---dal-stest.properties
|    |    |        |    |     |---dal-test.properties

4.执行

在cs-dal目录执行:

1
mvn liquibase:update -Dspring.profiles.active=local

上面的脚本会以local环境执行,读取

1
dal-local.properties
中的数据库配置,执行数据库变更脚本.执行成功后,会在数据库中新建两个表.
1
DATABASECHANGELOG
会记录数据库变更信息,
1
DATABASECHANGELOGLOCK
用于防止多台服务器同时部署时的并发问题.

5.注意事项

  1. 先不要搞线上.
  2. 变更脚本命名:我现在做得简单
    1
    db.1.0.sql
    
    ,最好版本号为项目版本号,便于跟踪.
  3. 新项目建议采用此方案,跟踪数据库所有的开发变动.
  4. 老项目可以采用全量的方式使用.全量,先根据数据库的基础数据生成变更脚本generating_changelogs,然后同步版本(changeLogSync)到数据库中.这样做的好处是,以后可以从无到有的创建当前版本的数据库了.参考Adding Liquibase on an Existing project
  5. 老项目也可以采用增量的方式使用,增量的方式不会管以前的数据版本.如果采用这种方式,在新环境搭建数据库,你需要先用数据库工具还原到没有版本之前的状态,然后再执行变更脚本.参考Adding Liquibase on an Existing project
  6. 请不要修改(脚本内容/脚本路径)之前的数据库变更脚本,liquibase会对每个Changesets生成摘要,执行时会去对比,如果你修改了以前的Changesets,会报错(所有的变更在事务中执行,出错了会回滚,不用担心会影响到数据库).
  7. 官方文档很全,想深入的同学请阅读FAQ/BEST PRACTICES/Maven Liquibase Plugin.遇到问题之前先检查配置是否正确,有bug可以找我^_^.

一次技术问答

## 一次技术问答最近一年多都没有写博客了,技术上做了很多有意义的事情,也有一些经验上的积累,逐步沉淀到博客上。今天回答某公司的技术上的一些疑问,把问题和回答贴上来。逐步`养`自己的技术观。### 1. 如何做数据安全防范?还有哪些支付安全需要注意?数据安全防范主要分为两个...… Continue reading

2016年05月Reading Notes

Published on August 10, 2016

2016年05月Reading Notes

Published on June 19, 2016