Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 弹簧&x2B;Hibernate:插入多个记录和@Transactional_Java_Spring_Hibernate_Jpa_Transactional - Fatal编程技术网

Java 弹簧&x2B;Hibernate:插入多个记录和@Transactional

Java 弹簧&x2B;Hibernate:插入多个记录和@Transactional,java,spring,hibernate,jpa,transactional,Java,Spring,Hibernate,Jpa,Transactional,我有一个基于Spring+Hibernate的应用程序。我试图从文件中的条目列表将数据插入数据库。基本思想是插入所有具有有效数据的记录,并为所有尚未插入的条目记录错误报告 一个@Transactional服务类调用另一个服务类来读取文件并插入数据库。现在,我一个接一个地插入记录。也许我会改成批量处理。插入在try-catch块中执行 伪代码: @Transactional class MainService { public void insertFromFile(File

我有一个基于Spring+Hibernate的应用程序。我试图从文件中的条目列表将数据插入数据库。基本思想是插入所有具有有效数据的记录,并为所有尚未插入的条目记录错误报告

一个@Transactional服务类调用另一个服务类来读取文件并插入数据库。现在,我一个接一个地插入记录。也许我会改成批量处理。插入在try-catch块中执行

伪代码:

@Transactional
class MainService {     
     public void insertFromFile(File inputFile) {
          subServuce(toIterator(inputFile)); // toIterator(..) is just for understanding. 
     } 
}

class SubService {
    public void insert(Iterator input) {
        while (input.hasNext()) {
             try {
                 DBService.save(input.next());
             } catch (Exception e) {
                 // Log the error and continue with next records
             }
        }
    }
}

@Transactional
class DBService {
     public void save(Data input) {
          generalDao.save(input);
     }
}
尝试:

class SubService {
    public void insert(Iterator input) {
        while (input.hasNext()) {
             try {
                 save(input.next());
             } catch (Exception e) {
                 // Log the error and continue with next records
             }
        }
    }

    // @Transactional(propagation = Propagation.REQUIRES_NEW, noRollbackFor = Exception.class)
    @Transactional(propagation = Propagation.NOT_SUPPORTED, noRollbackFor = Exception.class)
    public void save(Data input) {
        DBService.save(input);
    }
}
即使处理了异常,整个事务仍在回滚,我得到了这个错误
无法提交JPA事务;嵌套异常为javax.persistence.RollbackException:标记为rollbackOnly的事务

我尝试在
SubService.insert(..)
上指定
@Transactional(noRollBack=Exception.class)
,但没有成功

以下是我的问题:

  • 我如何告诉Spring不要回滚并继续其他记录
  • 插入多个记录时不回滚是一种良好的做法吗?这不违背原子性规则吗
  • 在批处理中,这是如何处理的?如果发生错误,是否全部插入

    解决方案:

  • 在@Madhusudana Reddy Sunnapu的回答的帮助下,他能够解决这个问题

    使用Propagation.REQUIRES\u NEW在子服务和DBService之间创建了一个层。问题是,即使SubService.save(..)用@Transactional注释,因为它属于同一个Bean,代理也不会将其视为不同的会话

    SubServiceDao {
        // @Transactional(propagation = Propagation.REQUIRES_NEW)
        public void save(Data input) {
            DBService.save(input);
        }
    }
    
    class SubService {
        public void insert(Iterator input) {
            while (input.hasNext()) {
                 try {
                     SubServiceDao.save(input.next());
                 } catch (Exception e) {
                     // Log the error and continue with next records
                 }
            }
        }
    }
    
    从javadoc:

    如果会话引发异常,则必须滚动事务 返回并丢弃会话。会话的内部状态 异常发生后,可能与数据库不一致

    因此,整个事务被回滚,没有任何内容保持插入状态

    在插入之前进行验证(必要时进行必要的锁定),并在失败时重试整个事务。

    来自javadoc:

    如果会话引发异常,则必须滚动事务 返回并丢弃会话。会话的内部状态 异常发生后,可能与数据库不一致

    因此,整个事务被回滚,没有任何内容保持插入状态


    在插入之前进行验证(必要时进行必要的锁定),并在失败时重试整个事务。

    尽管捕获到异常,Spring仍然能够检测到entityManager出现了问题,在这种情况下,它将事务标记为仅回滚

    这是因为
    entityManager
    Spring injects是一个代理,它在委托给real
    entityManager
    之前拦截所有调用,并让它知道real
    entityManager
    抛出了异常,即使您捕获了它


    我看到的一个选项是,您可以在
    DBService.save(…)
    方法
    @Transactional(propagation=propagation.REQUIRES\u new)
    上启动一个新事务。这样,如果由于无效数据而发生任何异常,则只会影响插入该行,其余的仍将继续。

    尽管捕捉到异常,Spring仍然能够检测到entityManager出现了问题,在这种情况下,它会将事务标记为仅回滚

    这是因为
    entityManager
    Spring injects是一个代理,它在委托给real
    entityManager
    之前拦截所有调用,并让它知道real
    entityManager
    抛出了异常,即使您捕获了它


    我看到的一个选项是,您可以在
    DBService.save(…)
    方法
    @Transactional(propagation=propagation.REQUIRES\u new)
    上启动一个新事务。这样,如果由于无效数据而发生任何异常,则只会影响插入该行,剩余的行仍将继续。

    Hey!DBService本身用@Transactional注释。我更新了显示DBService类的问题。无论如何,我将调用DBService的部分移动到另一个方法,并将其标记为Propagation.REQUIRES\u NEW/NOT\u SUPPORTED。不起作用。您是否尝试在dao类中的
    generalDao.save(input)
    方法上添加
    Propagation.REQUIRES\u NEW
    。因为您应该在与
    entityManager
    交互的方法上添加此注释。我相信
    generalDao.save(input)
    是与entitymanager交互的工具。其余的其他事务可以在同一事务中运行。generalDao在这里,我不能为我的特定目的更改它的实现。所以我在这里无能为力,明白了。尽管您在
    SubService
    类中用
    REQUIRES\u NEW
    注释了
    save(input)
    方法,但我看到的问题是,您在while循环中直接调用了这个
    save
    方法。如果我们直接调用一个方法,它将不会被SpringAOP代理(没有新的事务),因此它将在与调用方相同的事务中运行。作为一种快速解决方法,您可以使用-
    ((子服务)AopContext.currentProxy()).save(input)
    调用save方法,或者更好地将
    save(input)
    方法移动到新bean中并使用此新bean调用它。很抱歉响应太晚。你最初的回答帮助我解决了这个问题。我在SubService和DBService之间添加了另一个DAO,并将persist方法移动到该类中。我用解决方案更新了我的答案。嘿!DBService本身用@Transactional注释。我更新了显示DBService类的问题。无论如何,我将调用DBService的部分移动到另一个方法,并将其标记为Propagation.REQUIRES\u NEW/NOT\u SUP