月度归档: 2017 年 3 月

  • 数据库迁移工具Flyway对比Liquibase

    很多应用的运行是需要数据库支持的,而随着快速迭代,产品更替的节奏加快,除了产品本身需要不断更新以外,数据库也需要做出合适的管理了。

    为什么需要数据库迁移管理

    比如第一个版本的产品只包含了最基本的功能,而第二版本就需要增加评论功能,这就涉及到数据结构的修改(包括创建新表,修改旧表的列,增加已有表的列等等)。直接进入产品数据库修改数据库并不适合快速的开发节奏,不仅仅不安全,更多的情况下数据库可能并不对外或者并不适合对外直接暴露连接,比如PAAS平台的数据库以服务的形式直接提供。

    对比代码管理的一些实践,很明显在数据库方面做的还欠缺很多。比如代码管理中我们有

    • 版本管理(svn,git等等)
    • 持续集成技术
    • 良好的发布工具和流程

    而在数据库方面会遇到很多问题

    • 某台数据库现在是什么状态
    • 修改变更的脚本是否已经应用
    • 对于生产环境的紧急修复有没有被应用在测试环境
    • 如何创建一个新的数据库实例

    数据库迁移工具可以很好的管理这些问题,并提供了以下特性

    • 从迁移脚本中创建新的数据库
    • 检查数据库状态
    • 从一个版本快速到达另外一个版本

     Flyway和Liquibase

    数据库迁移工具很多,这里我们选择Flyway和Liquibase来说主要是两个原因,一是它们都是Java生态圈的,其次就是Spring Boot提供了这两者的内建支持,可以很快应用到产品中。

    Flyway相对简单,直接将你需要执行的SQL语句保存为文件,放入应用中执行即可。比如

    V1__init-database.sql
    V2__add-comment.sql

    Flyway的好处在于简单,而且直接书写SQL并不需要额外的学习。

    Liquibase相对就复杂了很多,它支持四种格式

    • xml
    • json
    • yaml
    • sql

    如果使用过Flyway就会有一定的体会,Flyway的简单是有代价的,举个简单的例子,如果我们开发环境是h2数据库,而测试环境和产品环境是MySQL,这里就有一个问题,SQL语句并不是一个广泛兼容的语言,有些关键字是独有的,而我们并不希望放弃这部分功能。这种情况下你就需要书写两套SQL迁移文件。Spring Boot是内建这种支持的,可以从目录上做区分。

    而Liquibase可以根据数据库的情况为你生成最后的迁移语句,同时因为数据库变动首先是被Liquibase解析,所以也可以简单支持回滚。

    来看一个Liquibase的例子,以XML为例,我个人觉得yaml更简洁,但是经常有对齐的问题。

    <?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"
            xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
            xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog 
    …
  • 使用onelogin快速集成Okta SSO

    使用onelogin快速集成Okta SSO

    Okta是专业的身份管理平台,它是以整合的思路管理企业应用和资源。

    如果企业有一个内部应用需要认证后使用,那么Okta提供的单点登录功能就是一个很好的集成点。集成Okta可以将用户认证部分从应用剥离,使用者还是可以使用Okta的信息登录,并且应用也能获得对应的信息。

    本文选用的是通过SAML协议集成Okta。SAML即安全断言标记语言,英文全称是Security Assertion Markup Language。 它是一个基于XML的标准,用于在不同的安全域(security domain)之间交换认证和授权数据。

    来个示意图:

    从图中可以看到集成部分从收到Response之后应用就获得用户的信息(比如Name ID),之后的事情就是应用自己的了。

    Saml毕竟是一个标准协议,直接使用公开的库就行了。OpenSaml本来是最合适的,但是使用有些麻烦,最后选择的是onelogin的java-saml库。

    必要的配置只有五个

    onelogin.saml2.sp.entityid
    onelogin.saml2.sp.assertion_consumer_service.url
    onelogin.saml2.idp.entityid
    onelogin.saml2.idp.single_sign_on_service.url
    onelogin.saml2.idp.x509cert

    这个在Okta的配置页面就有。

    一般应用程序需要提供两个功能点,一个是GET方法检测是否需要进入SSO流程,一个是POST方法用于接收Saml的返回断言。

    @GET
        public Response showLoginPage(@Context HttpServletResponse response,
                                      @Context HttpServletRequest request) throws Exception {
            Auth auth = new Auth(request, response);
            auth.login();
            return 
    …
  • JDBC的MySQL连接字符串

    JDBC的MySQL连接字符串

    今天迁移一个应用,放在heroku死活没法运行。仔细对比以后发现heroku会暴露名为JDBC_DATABASE_URL的环境变量,而这个环境变量只有一个默认参数reconnection=true。

    而原应用运行环境中还多了两个参数,一个是allowMultiQueries 和zeroDateTimeBehavior 。最开始没有太在意,想着应用很简单,无非就是影响一下性能而已,结果直接无法运行,被迫加上。

    来看看这两个参数,第一个allowMultiQueries 是运行一次运行多行。多行是指命令层级的含义,比如select ‘hello’;select ‘world’ 。

    第二个zeroDateTimeBehavior 是对于时间的处理,比如有一个条插入语句,没有提供需要的时间时,默认情况会抛出

    Cannot convert value '0000-00-00 00:00:00' from column 7 to TIMESTAMP

    这时候将zeroDateTimeBehavior 指定为convertToNull可以避免写入错误的值。…