【问题标题】:Spring + Hibernate + Postgresql readOnly Transaction, save on demandSpring + Hibernate + Postgresql readOnly Transaction,按需保存
【发布时间】:2011-12-19 23:45:11
【问题描述】:

我有这种非标准情况,我需要更新只读休眠事务中的对象。问题是,我加载了许多其他对象,在该事务中更改它们,但只有一个应该被保存,其余的回滚。我工作的数据库是 Postgresql 8.4

我不确定我对文档的理解是否正确,但提出了一种服务方法:

@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)

应该导致为该保存显式打开新的 RW 事务。

主要的是,这不起作用:

@Transactional(readOnly = true)
public class PersonService {

    @Resource(name="sessionFactory")
    private SessionFactory sessionFactory;

    public void add(Person person){

        person.setFirstName("changed its name");
        save(person);
    }

    @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
    public void save(Person person) {

        Session session = sessionFactory.getCurrentSession();

        session.save(person);
        session.flush();
    }
}

然后我得到

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update

从控制器调用“添加”方法。 'add' 处于只读模式,它将 Person 对象传递给 'save' 方法,该方法应该打开新的 Transaction 并保存到 DB。在我的“添加”方法的项目中,我加载了许多其他“人”对象,不应保存。 我需要只读方法的原因是我在代码中加载了更多的对象:) 回滚它们是我想做的最后一件事。

这样可以吗?

【问题讨论】:

    标签: hibernate spring postgresql


    【解决方案1】:

    事务通常通过为服务接口生成实现来应用(您没有表明您正在实现接口,这可能只是您的示例代码?)

    无论如何,关键是在这种情况下,简单地调用 save(...) 不会通过包装器,它只是在目标对象上运行方法。您需要从服务向自身注入一个引用,以便它可以调用自身并应用包装。那就是:

    public class PersonServiceImpl implements PersonService {
      PersonService personService;
      public void readOnlyMethod() {
        // ...
        personService.readWriteMethod(...);
      }
      public void readWriteMethod(...) {
      }
    }
    

    调用堆栈看起来像:

    PersonServiceImpl.readWriteMethod(...)
    TransactionAroundAdvice.advise(...) // starts/ends new read-write transaction
    $Proxy.readWriteMethod(...) // implementing PersonService
    PersonServiceImpl.readOnlyMethod(...)
    TransactionAroundAdvice.advise(...) // starts/ends read-only transaction
    $Proxy.readOnlyMethod(...) // implementing PersonService
    ClientCode.doSomethingNotReallyReadOnly(...)
    

    (您所描述的听起来像是记录某种错误消息,这是我使用 requiresNew 事务标记的地方(虽然在 J2EE 中,但我认为这一点很重要))

    【讨论】:

    • +1 是的,这就是它不起作用的原因。添加 @Resource(name="personService") private PersonService personService 并调用 personService.save(person) 后,它工作正常并保存在数据库中。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 2020-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-11
    相关资源
    最近更新 更多