Spring + Hibernate + Postgresql readOnly Transaction, сохранение по требованию - PullRequest
2 голосов
/ 20 декабря 2011

У меня нестандартная ситуация, когда мне нужно обновить объект внутри транзакции readOnly Hibernate. Дело в том, что я загружаю много других объектов, меняю их в рамках этой транзакции, но нужно сохранить только один, остальное откат. База данных, над которой я работаю - 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. add находится в режиме readOnly и передает объект Person методу save, который должен открыть новую транзакцию и сохранить в БД. В моем проекте в методе «add» у меня загружено много других объектов «Person», которые не должны быть сохранены. Причина, по которой мне нужен метод readOnly, заключается в том, что я загружаю еще больше объектов в коде :) Откат их - последнее, что я хочу сделать.

Можно ли сделать это таким образом?

1 Ответ

2 голосов
/ 20 декабря 2011

Транзакции обычно применяются путем генерации реализации для интерфейса службы (вы не показываете, что реализуете интерфейс, который может быть просто вашим примером кода?)

В любом случае, дело в том, чтов этом случае простой вызов 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(...)

(то, что вы описываете, звучит как запись какого-то сообщения об ошибке, где яИспользуется требует новой маркировки транзакции (хотя в J2EE, но я думаю, что точка несет))

...