오늘 트랜잭션이 어떻게 작동하는지 확인하기 위해 응용 프로그램의 테스트 케이스를 코딩했습니다. 그리고 나는 그것이 내가 생각했던대로 아무것도 작동하지 않는다는 것을 알았다.JPA 및 Spring 트랜잭션 - 설명해주십시오.
MySQL 기반의 JPA 프로 바이더로서 Hibernate를 사용하는 Spring 기반 애플리케이션이 있습니다. 스프링의 JpaDaoSupport를 확장하는 DAO 객체가 있습니다. 이것들은 Spring의 트랜잭션 관리에 의해 다루어진다.
내가 이런 작품을 만든 테스트 케이스 : 1) 엔티티가에 DAO 방법 incrementCounter()를 호출 모두 0 2로 설정 일부 카운터) 그리고 두 개의 스레드가 생성으로 만들어집니다에게 고리.
DAO 메소드가 트랜잭션으로 덮여있을 때 하나의 스레드 만 내부에 있다고 생각했습니다. 즉, 스프링이 동기화를 처리합니다. 그러나 이것은 잘못된 가정으로 입증되었습니다.
synchronized
을 DAO 메소드에 추가하여 (일시적으로)이 문제를 해결 한 후, Hibernate는 DAO 메소드에 의해 변경된 사항을 저장하지 않고, 다른 스레드는 엔티티를 찾을 때 오래된 데이터 . this.getJpaTemplate().flush();
의 명시적인 호출 만 도움이되었습니다.
나는 또한 엔티티 관리자가 나에게 영속 컨텍스트의 캐시에서 같은 엔티티 인스턴스를 줄 것이라고 생각했지만 이것은 또한 거짓이다. 나는 hashCode()와 equals()를 체크했다. 엔티티의 bussines 키를 기반으로 괜찮다.
모든 의견을 환영합니다. JPA/Spring이 트랜잭션과 함께 작동하는 방식에 대한 몇 가지 기본 개념을 놓친 것 같습니다.
- DAO 방법은
synchronized
이어야합니까? - 모든 DAO 메서드의 끝에서 flush()를 호출해야합니까?
- DAO 메서드 호출이 트랜잭션으로 동작하도록하는 책임은 스프링입니까? (즉, 동일한 엔티티에서 동시에 두 개의 스레드가 작동하지 않도록)
- 그렇지 않은 경우 어떻게해야합니까?
필자의 테스트 케이스에서는 하나의 DAO 객체를 사용하고 있지만 스프링의 bean은 싱글 톤이기 때문에 괜찮을 것입니다. 맞습니까?
도움 주셔서 감사합니다. synchronized
및 flush()
없이
public class EntityDaoImpl extends JpaDaoSupport implements EntityDao {
public synchronized void incrementCounter(String znacka)
{
String threadName = Thread.currentThread().getName();
log.info(threadName + " entering do incrementCounter().");
Entity ent = this.getJpaTemplate().find(Entity.class, znacka);
log.info("Found an entity "+ent.getZnacka()+"/"+ent.hashCode()+" - " + ObjectUtils.identityToString(ent));
log.info(threadName + ": Actual count: "+ent.getCount());
ent.setCount(ent.getCount() + 5);
int sleepTime = threadName.endsWith("A") ? 700 : 50;
try { Thread.sleep(sleepTime); }
catch(InterruptedException ex) { }
ent.setCount(ent.getCount() + 5);
this.getJpaTemplate().flush();
log.info(threadName + " leaving incrementCounter().");
}
}
, 이것은 하나 개의 스레드가 서로의 변경 사항을 덮어 씌우 것을 의미한다, 등등 ...
Thread A: Actual count: 220
...
Thread B: Actual count: 220
...
Thread A: Actual count: 240
...
Thread B: Actual count: 250
...
Thread A: Actual count: 250
같은 출력을 나에게주고 있었다.
답변 해 주셔서 감사합니다. JpaDaoSupport에서 DAO 객체는 참조를 적절한 유형으로 형 변환하는 데 사용되는 얇은 쉘 이었기 때문에 유스 케이스를 DAO에 넣기 시작했습니다. 유스 케이스에 대한 또 다른 레이어를 잘 이해한다면 다른 스프링 관리 빈들로 끝나고, DAO 대신 스프링 트랜잭션으로 AOP 된 유스 케이스를 구현할 것이다. 그래서 그것은 기술적으로 동일 할 것입니다, 그렇지 않습니까? 동기화를 처리하기 위해 어떤 접근 방식을 권하고 싶습니까? Spring 2.5 + JPA 튜토리얼 앱을 추천 해 주시겠습니까? 감사합니다. –
저는 Spring의 관용구를 여러분에게 인용했습니다. 특히 Spring을 처음 사용하는 경우, 다음과 같이하는 것이 좋습니다. 보통 Tomcat, JBOSS 또는 WebLogic과 같은 Java EE 응용 프로그램 서버에서 Spring을 실행하므로 각 요청은 자체 스레드에서 실행됩니다. 앱 서버는 처리 요청을 대기열에 넣습니다. Spring 레퍼런스 문서를 권하고 싶다. – duffymo
글쎄, 내가 뭘하는 웹 애플 리케이션을위한 백엔드도 Tomcat에서 실행됩니다. 스프링 참조는 훌륭하고 방대하지만 동기화에 대한 팁은 아직 포함되어 있지 않습니다. 적어도 찾지 못했습니다. EntityManager # lock (Object entity, LockModeType lockMode)은 내가 살펴 봐야 할 것입니다. 맞습니까? –