Hibernate多租户和Spring批处理集成

3
我们有一个web应用程序,它使用Spring事务管理和Hibernate多租户模式设置,其中租户基于请求URL进行解析。我想根据Web请求执行一些特定于租户的Spring批处理作业,在我的理解中,提供给Spring批处理的数据源无法识别租户并将作业实例数据插入到相应的租户模式中。我猜我们可以将租户ID添加到作业参数中,使其成为唯一的租户作业,驻留在默认模式中。但我的要求是将作业实例数据保留在租户特定的模式中,并根据租户ID获取作业和运行作业。非常感谢任何想法。
1个回答

3
好的,我有好消息和坏消息。好消息是这很容易做到。默认的JobRepository(将作业元数据读取/写入数据库的内容)在某种意义上是无状态的,如果您提供给它的DataSource是租户感知的,则它会进入正确的模式。因此,你所需要做的就是为Spring Batch提供一个返回上下文正确连接的数据源。例如,确保数据源在返回连接之前将其设置为正确的模式。以下是一个示例:
@Bean
@Scope(value='thread', proxyMode = ScopedProxyMode.INTERFACES)
DataSource dataSource() {
    DataSource original = new JdbcDataSource(
        url:'jdbc:h2:mem:temp_db;DB_CLOSE_DELAY=-1',
        user: 'sa',
        password: 'sa',)
    new DataSource() {
        @Delegate
        DataSource delegate = original

        @Override
        Connection getConnection() throws SQLException {
            String schema = schemaHolder().schema
            original.connection.with {
                it.createStatement().execute("SET SCHEMA $schema")
                // in other databases, the syntax may be different, e.g.
                //it.createStatement().execute("USE $schema")
                it
            }
        }

        @Override
        Connection getConnection(String username, String password) throws SQLException {
            connection
        }
    }
}

在这个例子中(使用Groovy),当我从内存数据库H2返回一个连接时,我设置了正确的模式。请参见完整示例。我使用Spring thread范围来告诉每个线程应该使用哪个模式,但您可以使用任何方法来确定数据源中的正确模式。
现在,坏消息来了。如果您实际运行完整示例,则可能会出现以下错误:
Caused by: org.springframework.dao.OptimisticLockingFailureException: Attempt to update step execution id=1 with wrong version (2), where current version is 1
原因是Spring Batch确实有一个令人讨厌的全局状态--静态变量StepSynchronizationManager.manager包括一个名为contexts的映射,其中它存储了所有当前活动的步骤执行上下文。这是一个键为StepExecution的映射。 StepExecution :: equals 的定义方式使得具有相同作业实例ID,相同步骤名称和相同ID的两个实例将比较相等。如果您恰好同时运行具有相同(自动生成的)ID的两个作业,每个作业运行具有相同(自动生成的)ID和相同名称的两个步骤,则会遇到问题。在实际世界中,这种情况很不可能发生,但您应该意识到这一点。

谢谢@Artefacto,让我试试这个...希望我们可以通过作业参数为每个租户创建唯一的作业ID? - Sreekanth
@Nick 作业 ID 是使用序列/自增列选择的,因此更改作业参数是没有帮助的。但问题更多是理论上的。当然,作业/步骤 ID 无论如何都会分歧,因为您将为某些模式拥有更多的作业(大概率)。 - Artefacto
我无法将此转换为Java实现,您能给一些在Java中如何实现的想法吗? - Sreekanth
@Nick 具体是什么? @Delegate 只是以这样一种方式实现了 DataSource 的其余方法,即将调用转发到delegate - Artefacto
我在类路径中找不到 JdbcDataSource 或 Delegate 类,如果您能指向任何带有 Java 示例的 Github 项目,那将非常有帮助。 - Sreekanth
请投票支持 https://jira.spring.io/browse/BATCH-2480,以在Spring Batch本身中添加内置支持。 - Sreekanth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接