Spring batch Hibernate多租户和Spring批处理集成

Spring batch Hibernate多租户和Spring批处理集成,spring-batch,multi-tenant,Spring Batch,Multi Tenant,我们有一个web应用程序,它使用spring事务管理和hibernate多模式每个租户设置,租户根据请求url得到解决。我想基于web请求执行一些特定于租户的spring批处理作业,据我所知,提供给spring批处理的数据源不具备识别租户并将作业实例数据插入相应租户模式的能力。我想我们可以将租户id添加到job参数中,并使其成为驻留在默认模式中的每个租户的唯一作业。但我的要求是将作业实例数据保存在租户特定的模式中,并根据租户id获取作业和运行作业。任何想法都将不胜感激。好吧,我有好消息和坏消息。

我们有一个web应用程序,它使用spring事务管理和hibernate多模式每个租户设置,租户根据请求url得到解决。我想基于web请求执行一些特定于租户的spring批处理作业,据我所知,提供给spring批处理的数据源不具备识别租户并将作业实例数据插入相应租户模式的能力。我想我们可以将租户id添加到job参数中,并使其成为驻留在默认模式中的每个租户的唯一作业。但我的要求是将作业实例数据保存在租户特定的模式中,并根据租户id获取作业和运行作业。任何想法都将不胜感激。

好吧,我有好消息和坏消息。好消息是这很容易做到。默认的
JobRepository
(将作业元数据读/写到数据库中的内容)是无状态的,因为如果您提供给它的
数据源是租户感知的,那么它将进入正确的模式。所以,您所需要做的就是为Spring批处理提供一个返回上下文正确连接的数据源。例如,在返回连接之前,请确保数据源在其上设置了正确的模式。以下是一个例子:

@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 原因:org.springframework.dao.OptimisticLockingFailureException:尝试使用错误版本(2)更新步骤执行id=1,其中当前版本为1
原因是Spring批处理确实有一个糟糕的全局状态——静态变量
StepSynchronizationManager.manager
包含一个名为
contexts
的映射,其中存储了当前活动的所有步骤执行上下文。这是一个映射,其键为
StepExecution
StepExecution::equals
的定义方式是,具有相同作业实例id、相同步骤名称和相同id的两个实例将进行相等比较。如果您碰巧有两个具有相同(自动生成)id的作业同时运行,每个作业运行两个具有相同(自动生成)id和相同名称的步骤,您将遇到问题。这在现实世界中不大可能发生,但这是你应该注意的。

谢谢@Artefactor,让我试试这个。。。希望我们可以使用作业参数为每个租户创建唯一的作业id?@Nick作业id是使用序列/自动增量列选择的,因此更改作业参数没有帮助。但这个问题更多的是理论性的。当然,作业/步骤ID无论如何都会有所不同,因为某些模式的作业比其他模式的要多(大概是这样)。我无法将其转换为java实现,可以给出一些在java中如何实现的想法吗?@Nick,特别是什么
@Delegate
只是实现了
DataSource
的其余方法,调用被转发到
Delegate
。在我的类路径中我看不到JdbcDataSource或Delegate类,如果您能给我指出任何带有java的示例github项目,可能会有所帮助。