Jpa 发生异常时回滚已提交记录

Jpa 发生异常时回滚已提交记录,jpa,jdbc,db2,ejb,Jpa,Jdbc,Db2,Ejb,根据我的理解,在理想情况下,提交的记录永远不会回滚。但是对于下面的代码,提交的记录确实会回滚。我不确定这是由JTA或数据库完成的,当引用的父表回滚时,该数据库会删除提交的记录 我将用下面的简单代码片段解释我的场景。我的事务方法createItems(List items)将通过调用itemService.saveParent(items)来创建父项列表。这将执行flush(),然后prepareChild(parentItems)将为每个父项创建数千个子项,其中子项将父项的主键设置为其外键。现在

根据我的理解,在理想情况下,提交的记录永远不会回滚。但是对于下面的代码,提交的记录确实会回滚。我不确定这是由JTA或数据库完成的,当引用的父表回滚时,该数据库会删除提交的记录

我将用下面的简单代码片段解释我的场景。我的事务方法
createItems(List items)
将通过调用
itemService.saveParent(items)
来创建父项列表。这将执行
flush()
,然后
prepareChild(parentItems)
将为每个父项创建数千个子项,其中子项将父项的主键设置为其外键。现在我通过生成块调用
saveChild(subList)
(因为我不想用单个事务提交100万条记录),它的事务属性是
REQUIRES\u NEW
,它将把每个子列表提交给DB。但其中一个区块出现异常。当我检查数据库时,我看到所有插入的子记录都回滚了。对于提交的记录,这是如何发生的

如果回滚不会发生,那么当父记录已经回滚且不存在PK时,子记录如何存在

@LocalBean
@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class Job {

    @EJB
    private ItemService itemService;

    public void createItems(List<items> items) {

        List<Parent> parentItems = itemService.saveParent(items);

        List<Child> childItems = itemService.prepareChild(parentItems);

        for(List<Child> subList: getSublist(childItems )) {
            itemService.saveChild(subList);
        }

    }
}


@LocalBean
@Stateless
public class ItemService {

    @EJB
    private ItemDLService itemDLService;

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void saveChild(List<child> childList) {

        itemDLService.save(childList);

    }
}
@LocalBean
@无国籍
@TransactionAttribute(TransactionAttributeType.REQUIRED)
公开课工作{
@EJB
私人项目服务项目服务;
公共项目(列表项目){
List parentItems=itemService.saveParent(items);
List childItems=itemService.prepareChild(parentItems);
for(列表子列表:getSublist(子项)){
itemService.saveChild(子列表);
}
}
}
@本地豆
@无国籍
公共类项目服务{
@EJB
私人项目服务项目服务;
@TransactionAttribute(TransactionAttributeType.REQUIRES\u NEW)
public void saveChild(List childList){
itemDLService.save(childList);
}
}

据猜测,数据库可能在保护您-如果父记录未提交,则无法合理提交子记录,因为如果父记录最终回滚,则子记录将指向不存在的父记录。您的意思是说,当引用的父记录尚未提交时,即使它们是不同事务的一部分,子记录也未实际提交?有道理。那么我有一个疑问。对于理想情况,提交将仅在外部方法(createItems())完成后发生?那么这将引起DB方面的关注。这里的全部意图是使用中间提交来避免更长的事务。。。。您需要先显式提交父事务,然后再提交。或者将它们通过连接推送到(会话创建的)临时表中,然后在一个事务中将整个集合移动到目标表中(仅作为数据库,将更短)。或者,根据应用程序正在做的其他事情,只需占用事务时间;除极端情况外,表的其余部分仍然是可更新的。不管怎样,我们在这里谈论的是多少行?对于父表,只有不到500行,子表大约有20万行。我们对整个处理有一分钟的SLA。让我问你一个疑问,如果我们必须实现unitOfWork(带有事务),同时我们需要中间提交(以避免DB人员的担忧),那么常见的设计方法是什么?因为这看起来是常见的用例。您的SLA是一个独立的关注点,您实际上会花费额外的时间处理分块事务(由于额外的工作)。要避免对公共表的长时间粗锁(DBA会担心这一点),最好的办法可能是将200k行加载到非日志临时表中,然后启动事务,插入父记录并移动子记录。批量加载200k记录应该是可行的,这也将改善这里的时间。