Liquibase 和 Spring 如何使用单独的用户进行架构更改

Posted

技术标签:

【中文标题】Liquibase 和 Spring 如何使用单独的用户进行架构更改【英文标题】:Liquibase & Spring how to use separate user for schema changes 【发布时间】:2014-11-06 08:09:01 【问题描述】:

我正在研究 Liquibase 作为一种潜在的解决方案,可以使用预先存在的数据库服务器(不同类型的)部署我的 Web 应用程序。

此应用程序应该使用只能操作数据的用户访问数据库,我想使用不同的用户作为架构所有者。 由于我的应用程序使用 Spring,我认为我可以使用集成类,但这意味着我必须创建第二个数据源,只要我的应用程序运行,它就会保持打开状态,这违背了分离帐户的目的。

有人遇到过同样的问题吗?任何解决方案的想法?我当然可以手动执行 liquibase 并传递相关信息,但我想知道是否有人想出了更清洁的方法。

提前感谢您的帮助。

【问题讨论】:

【参考方案1】:

将 Liquibase 与 Spring Boot(至少 2.0+)一起使用,现在可以在 application.yml 中配置单独的 Liquibase db 用户:

spring:
  datasource:
    driver-class-name: org.mariadb.jdbc.Driver
    url: jdbc:mariadb://...
    username: <app_user>
    password: $DB_PASSWORD
  liquibase:
    default-schema: my_schema
    user: <admin_user>
    password: $DB_ADMIN_PASSWORD

【讨论】:

【参考方案2】:

感谢您的输入 Nathan,我查看了 Spring 和 CommandLine 类并最终编写了自己的小型静态方法,该方法使用“所有者”凭据打开数据库连接,通过此连接应用更改日志并关闭它。

然后我从 WebApplicationInitializer 调用此方法,允许 liquibase 在 Spring bean 初始化之前运行。这样,我可以确定在与数据库相关的任何代码运行之前应用更改,而且我只能通过我的数据源进行“用户”连接。

作为一个很好的副作用,在启动单元测试时也可以使用该静态方法,这使我可以在干净创建的数据库上运行测试,而不是依赖 hibernate 的 DDL。

这里是代码示例,首先是一个实用程序类,它封装了从我的应用程序的属性文件 (http://pastebin.com/HP4HzFmp) 中检索架构所有者连接详细信息的逻辑,它还有一些方法可以简化与单元测试设置的集成。

然后在每个 Web 应用程序中,我使用 Spring 的 WebApplicationInitializer,它允许我在应用程序启动时(即在 Hibernate 向 DB 发出任何请求之前)触发 liquibase 更改应用程序:http://pastebin.com/anXicM15。这样做可以让我在架构操作和数据相关连接之间保持完全分离。

关于数据库连接细节,我将它们全部存储在一个属性文件中,这段代码可以直接读取该文件,并被 Spring 用作 Hibernate 配置的占位符替换源。如果您想实现进一步的隔离,您可以将获取连接细节的部分替换为更安全的位置。

【讨论】:

我的情况与您的问题完全相同。您能否发布您的解决方案代码或指向 github gist 的链接?这将有很大帮助。 您不需要在您的解决方案中使用 SpringLiquibase 吗? @TechCrunch,我用代码示例编辑了答案,希望对您有所帮助。 非常感谢。我现在继续使用 SpringLiquibase 和第二个数据源,但仍在考虑按照您的方式进行操作。到目前为止,您是否遇到过直接在生产应用程序中升级 DB 的问题?团队中的一些人希望它在应用程序之外手动运行。 到目前为止没有问题,我正在从多个 Web 应用程序运行完全相同的更新,尽管它们都以 Tomcat 的顺序开始。因此,只有第一个实际上应用了任何东西。我还没有测试过同时启动多个节点的情况,尽管在事务中运行更改应该可以确保所有 DBMS 正确处理事务的安全。【参考方案3】:

您是对的,标准的 SpringLiquibase 集成只支持传递一个数据源,并且该数据源将在您的应用程序的整个生命周期中存在。

如果您使用连接池,一旦 Liquibase 完成它使用的连接,它将被关闭,因此应该没有活动连接,但您的应用程序中仍然会引用它。

如果你想绕过一个开放的数据源,你可能需要创建一个 SpringLiquibase 的子类来覆盖 afterPropertiesSet() 方法和 getDataSouce() 方法。

afterPropertiesSet 是运行的主要方法,它创建 Liquibase 实例,然后运行更新方法。如果您的子类创建了一个它想要的新连接,然后调用super.afterPropertiesSet(),然后关闭连接,您应该能够确保一切都被清理干净。在 afterPropertiesSet 中调用 getDataSource() 方法,因此您需要覆盖该方法以返回在 afterPropertiesSet() 中创建的连接。

你可以在github.com/..../SpringLiquibase.java看到SpringLiquibase是如何实现的

【讨论】:

以上是关于Liquibase 和 Spring 如何使用单独的用户进行架构更改的主要内容,如果未能解决你的问题,请参考以下文章

使用 H2 数据库和 Liquibase 配置 Spring Boot

Spring Boot 和 Liquibase 示例

使用 Liquibase 的 Spring Boot 未在 Docker 中执行

具有 Liquibase 重载属性的 Spring-boot

如何用 Spring 解锁 Liquibase 锁?

Liquibase / Spring Boot / Postgres - 模式名称不起作用