2010-06-16 4 views
6

Spring에서 관리하는 Hibernate Transaction을 가질 때 Hibernate Interceptor를 활성화하는 방법은 무엇입니까?

public class One { 

    private Integer id; 

    private List<Many> manyList = new ArrayList<Many>(); 

    @Id 
    @GeneratedValue 
    public Integer getId() { 
     return this.id; 
    } 

    @OneToMany 
    @JoinColumn(name="ONE_ID", updateable=false, nullable=false) 
    @Cascade(CascadeType.SAVE_UPDATE) 
    public List<Many> getManyList() { 
     return this.manyList; 
    }   

} 

그리고 많은 클래스

public class Many { 

    private Integer id; 

    /** 
     * required no-arg constructor 
     */ 
    public Many() {} 

    public Many(Integer uniqueId) { 
     this.id = uniqueId 
    } 

    /** 
     * Without @GeneratedValue annotation 
     * Hibernate will use assigned Strategy 
     */ 
    @Id 
    public Integer getId() { 
     return this.id; 
    } 

} 

나는 다음과 같은 시나리오가있는 경우

One one = new One(); 

/** 
    * generateUniqueId method will Take care of assigning unique id for each Many instance 
    */ 
one.getManyList().add(new Many(generateUniqueId())); 
one.getManyList().add(new Many(generateUniqueId())); 
one.getManyList().add(new Many(generateUniqueId())); 
one.getManyList().add(new Many(generateUniqueId())); 

그리고 다음과 같이 내가 @Cascade (CascadeType.SAVE_UPDATE)과 @OneToMany 관계가있는 경우 전화 :

sessionFactory.getCurrentSession().save(one); 
부모 ()가, update() 또는 saveOrUpdate(), 모든 어린이 저장 전달되면

에 가기 전에 Transitive persistence Hibernate 참조 문서에 따르면, 당신은

를 볼 수 있습니다 saveOrUpdate()에 전달됩니다.

ok. 이제이 될 saveOrUpdate 방법에 대한 최대 절전 책 회담으로 자바 지속성

최대 절전 모드 이 지정된 ID의 많은 테이블을 쿼리 것을 보자, 그리고 을가를 발견하는 경우, 은 행을 업데이트 최대 절전 모드. 찾을 수없는 경우, 새 행을 삽입하면이 필요하고 완료됩니다.

INSERT INTO ONE (ID) VALUES (?) 

/** 
    * I have four Many instances added To One instance 
    * So four select-before-saving 
    * 
    * I DO NOT NEED select-before-saving 
    * Because i know i have a Fresh Transient instance 
    */ 
SELECT * FROM MANY WHERE MANY.ID = ? 
SELECT * FROM MANY WHERE MANY.ID = ? 
SELECT * FROM MANY WHERE MANY.ID = ? 
SELECT * FROM MANY WHERE MANY.ID = ? 

INSERT INTO MANY (ID, ONE_ID) VALUES (?, ?) 
INSERT INTO MANY (ID, ONE_ID) VALUES (?, ?) 
INSERT INTO MANY (ID, ONE_ID) VALUES (?, ?) 
INSERT INTO MANY (ID, ONE_ID) VALUES (?, ?) 

선택-전에 절약되는 것을 방지하기 위해 해결 방법에 따라 번역 될 수

??? 예, 당신도

  • 는 방법 에로 (내가이 옵션 ) 그래서

를 (적용되지 않음) @Version 열

  • 이 isTransient 방법은 하이버 네이트 인터셉터에 의해 제공되는 구현을 추가 할 수 있습니다 이 종류의 계단식을 사용할 때 기본 동작을 피하십시오. 최대 절전 모드 인터셉터를 최대 절전 모드 세션에 할당하여 코드를 개선했습니다. 트랜잭션은 스프링에 의해 관리됩니다.

    여기에 (어떤 최대 절전 모드 인터셉터없이) 내 저장소 전에

    간다 : 그것은 잘 작동!봄하지 않는 이유 : -

    @Repository 
    public class SomeEntityRepository extends AbstractRepository<SomeEntity, Integer> { 
    
        @Autowired 
        private SessionFactory sessionFactory; 
    
        @Override 
        public void add(SomeEntity instance) { 
         sessionFactory.openSession(new EmptyInterceptor() { 
          /** 
           * To avoid select-before-saving 
           */ 
          @Override 
          public Boolean isTransient(Object o) { 
           return true; 
          } 
         }).save(instance); 
        } 
    
    } 
    

    내 질문은 뭔가 잘못 (어느 쪽도 절전을 선택-전에 삽입 아니다 없음 SQL 쿼리가 실행되지 않습니다) : (최대 절전 모드 Inteceptor이와 함께)이 후

    @Repository 
    public class SomeEntityRepository extends AbstractRepository<SomeEntity, Integer> { 
    
        @Autowired 
        private SessionFactory sessionFactory; 
    
        @Override 
        public void add(SomeEntity instance) { 
         sessionFactory.getCurrentSession().save(instance); 
        } 
    
    } 
    

    최대 절전 모드 인터셉터를 사용할 때 내 개체와 그 관계를 유지하고 잘 작동하려면 해결 방법으로 무엇을해야합니까 ???

  • 답변

    3

    봄은 현재 세션 및 현재의 트랜잭션 (transaction) (SessionFactoryUtils.java를 참조하십시오.) 이미 현재의 DAO 메서드 호출에 대한 관련 세션이 있으므로,이 세션을 사용하거나의 돌입을 가지고 가야 사이의 관계를 유지 참조 새 세션을 이전 트랜잭션 컨텍스트와 연관시키는 세부적인 사항에 개입하지 않아도됩니다. 아마도 가능할 지 모르지만 상당한 위험을 감수하고 확실히 권장하지는 않습니다. 최대 절전 모드에서 세션이 이미 열려 있다면이를 사용해야합니다.

    그렇다면 스프링을 사용하여 새로운 세션을 만들고 현재 트랜잭션 컨텍스트와 연결할 수 있습니다. SessionFactoryUtils.getNewSession(SessionFactory, Interceptor)을 사용하십시오. 최대 절전 모드의 sessionFactory가 아닌 이것을 사용한다면 트랜잭션과의 연관성을 유지해야한다.

    처음에는 이것을 DAO에서 직접 코딩 할 수 있습니다. AOP를 사용하여 새로운 세션을 만들고 정리하는 add() 메소드에 대한 조언을 추가하는 등 DAO에서 스프링 코드를 이동하는 단계를 수행 할 수 있습니다.

    또 다른 대안은 글로벌 인터셉터를 사용하는 것입니다. 글로벌이지만 로컬에서 제어 할 수있는 동작을 제공 할 수 있습니다. TransientInterceptor에는 threadLocal<Boolean>이 포함되어 있습니다. isTransient에 대해 인터셉터가 true를 반환해야 하는지를 나타내는 현재 스레드의 플래그입니다. add() 메서드의 시작 부분에서이 값을 true로 설정하고 끝에서이를 지 웁니다. 예 :

    class TransientInterceptor extends EntityInterceptor { 
         ThreadLocal<Boolean> transientFlag = new ThreadLocal<Boolean)(); 
         public boolean isTransient() { 
         return transientFlag.get()==Boolean.TRUE; 
         } 
         static public setTransient(boolean b) { 
          transientFlag.set(b); 
         } 
        } 
    

    그리고 당신의 DAO에 :

    @Override 
    public void add(SomeEntity instance) { 
        try { 
         TransientInterceptor.set(true); 
         sessionFactory.getCurrentSession().save(instance); 
        } 
        finally { 
         TransientInterceptor.set(false); 
        } 
    } 
    

    그런 다음 (. 예를 들어 LocalSessionFactoryBean) SessionFactory를에 글로벌 인터셉터로 설정 TransientInterceptor이 덜 침습적 만들려면 수 있습니다, 당신이 조언을 주위에 AOP를 만들 수 있습니다 적절한 경우 모든 DAO 추가 메서드에이 동작을 적용합니다.

    0

    'after'메서드에서 새 세션을 만들고 플러시하지 않으므로 데이터베이스에 업데이트가 보내지지 않습니다. 이것은 Spring과 아무 관련이 없지만, 순수한 최대 절전 모드 동작이다.

    아마도 Spring을 사용하여 구성한 sessionFactory에 (엔터티) 인터셉터를 추가하는 것이 좋습니다. 이전처럼 저장소의 add() 메소드를 유지할 수 있습니다. http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/orm/hibernate3/LocalSessionFactoryBean.html#setEntityInterceptor%28org.hibernate.Interceptor%29

    +0

    설명 : * SessionFactory *에 인터셉터를 추가 할 수 있습니다. Interceptor를 SessionFactory에 추가했는지 여부에 관계없이 ** 전역 ** 동작이 발생합니다. add (SomeEntity 인스턴스) 메소드에서 사용되는 Session 인스턴스에 인터셉터를 추가하기 만하면됩니다. 모든 해결 방법 ??? –

    관련 문제