【发布时间】:2017-06-09 08:16:22
【问题描述】:
在这个队列处理中,我想将发送本身放入单独的事务中,以避免回滚发送状态。但是,由于在延迟提取时关闭会话或分离实体,我遇到了问题。
这是我的代码:
// Before this is called queueToSend is fetched in a separate transaction
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public void sendMails(List<QueuedMail> queueToSend)
{
for (QueuedMail queuedMail: queueToSend) {
sendMail(queuedMail);
}
}
public void sendMail(QueuedMail queuedMail)
{
System.out.println("Checking "+queuedMail);
crud.getEntityManager().merge(queuedMail);
Mail mail = (Mail)crud.find(queuedMail.getMail().getId(),Mail.class);
System.out.println("mail id: "+queuedMail.getMail().getId());
crud.getEntityManager().merge(mail);
Boolean unsubscribed = false;
Set<Campaign> campaigns = mail.getCampaigns();
for (Campaign campaign: campaigns) {
if (campaign.getUnsubscribedUsers().contains(queuedMail.getUser())) {
unsubscribed = true;
}
}
// ...
}
错误是:
failed to lazily initialize a collection of role: dps.simplemailing.entities.Mail.campaigns, could not initialize proxy - no Session
并且排在第一位:
for (Campaign campaign: campaigns) {
我认为这可能是因为 queuedMail 已经分离,但是我正在尝试使用合并重新附加 queuedMail 和邮件,但这没有帮助。
也可能它已经在缓存中,这就是它不启动新会话的原因。
基本上我希望它像以前一样(在我添加 TransactionAttribute 之前)做同样的事情,但作为循环中的一个单独事务。我认为我不应该做任何供应商特定的解决方案,因为这似乎是一项微不足道的任务。
更新:
我做了一些研究,发现我必须使用合并操作的结果才能重新附加分离的实体。这将特定于供应商的错误(如使用未定义的分离实体的延迟加载属性)更改为与供应商无关的错误,我认为它显示了真正的问题。
修改后的代码为:
public void sendMail(QueuedMail queuedMail)
{
System.out.println("Checking "+queuedMail);
queuedMail = crud.getEntityManager().merge(queuedMail);
Mail mail = (Mail)crud.getEntityManager().merge(queuedMail.getMail());
Boolean unsubscribed = false;
Set<Campaign> campaigns = mail.getCampaigns();
for (Campaign campaign: campaigns) {
if (campaign.getUnsubscribedUsers().contains(queuedMail.getUser())) {
unsubscribed = true;
}
}
我也改变了实体来定义级联类型:
@ManyToMany(mappedBy = "mails",cascade = CascadeType.MERGE)
private Set<Campaign> campaigns;
现在错误是这样的:
Transaction is required to perform this operation (either use a transaction or extended persistence context)
我不太了解这个错误是事务应该已经启动,因为类默认是TransactionAttributeType.REQUIRED。将其他方法设置为TransactionAttributeType.NOT_SUPPORTED 的目的是在此方法中启动事务。我是交易和实体管理的初学者,所以我会继续研究以更好地理解它,但也许我会在这里更快地得到答案,或者如果我找到解决方案,我会发布它。
【问题讨论】:
-
在广告系列中,您有关系实体。默认情况下它是惰性的,或者您将其设置为默认值。简单的解决方案它标志着它渴望。更好的是,您可以在方法调用 sendMails 之前加载所有惰性会话事务
-
这里的核心问题不是惰性实体,因为它很好,我不想急于加载它,这将是一个简单的解决方案,但它会降低性能。这里的问题是事务已经结束。我会尽快更新问题,因为我做了一些代码更改,改变了我得到的错误,所以它更有意义。
标签: java jpa jakarta-ee jta