ItemReader中的中间结果集

时间:2016-06-30 22:27:35

标签: spring-batch batch-processing jsr352

Spring Batch机制相当新 - 我设法让它运行起来但我的业务逻辑似乎不适合作为Spring Batch工作。请允许我解释一下:

该工作负责向用户发送电子邮件,如下所示:

  1. 获取满足特定条件(Set<News>
  2. 的新闻项目集
  3. 获取尚未收到其中一个新闻项目的用户组(Set<User>
  4. 对于每个用户,请为用户未收到的每条新闻发送电子邮件。
  5. '标记'已收到新闻的用户。
  6. 实体bean定义如下:

        @Entity
        public class News {
            ...
            // ID with a sequence generator (more recent news have a higher ID value)
            private Integer id;
            ...
        }
    
        @Entity
        public class User {
            ...
            // last received news;
            private Integer lastReceivedNewsId;
            ...
        }
    

    两者之间没有一对多的关系,所以为了检索未接收的新闻,可以检索如下:

    SELECT n FROM db.news n 
    JOIN User u on n.id > u.lastReceivedNewsId; 
    

    我决定使用Spring Batch,因为我的用户群目前为28,000并计算,设置步骤1和2为ItemReader,步骤3和4为ItemWriter

    问题在于第一步:我决定使用JpaPagingItemReader<T>作为我的读者,但不幸的是,它非常严格,因此我只能指定一个查询,而不会将结果集映射到其他内容。在我的示例中,我首先需要获取一组新闻,然后查询数据库以根据收到的新闻(Tuple<User, Set<News>>)获取用户集。

    我可以做些什么来让我的读者返回一个用户组和他/她未接收的新闻集?我错过了什么?

    非常感谢。如果您需要更多信息,请告诉我。

1 个答案:

答案 0 :(得分:0)

如果您可以使用Hibernate,我建议您查看HibernateCursorItemReader。我将对您的数据模型做一些假设,所以希望这足够接近有用......

USER: USER_ID
NEWS: NEWS_ID, CONDITION_COL
USER_NEWS: USER_ID, NEWS_ID, SENT_FLG

假设你的持久性对象之间有关系,你可以编写HQL看起来像这样:

select un from UserNews un
inner join fetch un.news news
inner join fetch un.user user
where un.sentFlag = false
and news.condition = :injectCondition

这也假设您在创建新新闻时,使用SENT_FLG = 'N'预先填充USER_NEWS表。

如果情况不对,您可以这样做:

INSERT INTO USER_NEWS (USER_ID, NEWS_ID, SENT_FLG)
SELECT U.USER_ID, N.NEWS_ID, 'N' SENT_FLG
FROM USER U, NEWS N
WHERE NOT EXISTS (
  SELECT 1 
  FROM USER_NEWS UN
  WHERE     UN.USER_ID = U.USER_ID
        AND UN.NEWS_ID = N.NEWS_ID
)

编辑:您的数据模型中没有多对多的连接表太糟糕了,但是如果添加Hibernate仍然可以提供帮助模糊的一对多关系:

@OneToMany
@JoinColumnsOrFormulas({
    @JoinColumnOrFormula(formula=@JoinFormula(value="(SELECT n.id FROM News n)", referencedColumnName="id"))
})
private Set<News> newsItems;

然后你的HQL查询看起来像这样:

from User u
left join fetch u.newsItems n
where n.id > u.lastReceivedNewsId

如果这不起作用,那么你可以写一个不那么漂亮的选项,你可以写下这样的驾驶查询:

select u, n from User u, News n where n.id > u.lastReceivedNewsId
order by u.id, n.id

上面的光标不会为您提供您正在寻找的确切元组,但您将获得Object [2],其中第一个对象是User,Second是未发送的新闻项。据推测,您可以在阅读器中编写聚合器,将多个结果组合到您想要的元组中。