Hibernate 의 Sessionflush 와 격 리 단계 코드 상세 설명

본 고 는 주로 Hibernate 의 Session 을 연구 하고 있다.flush 와 격 리 단계,구체 적 인 소개 와 실례 는 다음 과 같다.
개념 소개
우 리 는 먼저 몇 가지 개념 을 살 펴 보 자.
1.더러 운 읽 기:더러 운 읽 기 는 잘못된 데이터 의 읽 기 라 고도 합 니 다.데이터 베 이 스 를 방문 할 때 사물 T1 이 특정한 값 을 수정 한 다음 에 사물 T2 가 이 값 을 읽 었 습 니 다.그 후에 T1 은 특정한 이유 로 이 값 에 대한 수정 을 취소 하면 T2 가 읽 은 데 이 터 는 무효 입 니 다.더러 운 읽 기 란 한 사물 이 데 이 터 를 방문 하고 데 이 터 를 수정 하 는 것 을 말한다.이런 수정 은 데이터 베이스 에 제출 되 지 않 았 을 때 다른 사물 도 이 데 이 터 를 방문 한 후에 이 데 이 터 를 사용 했다.이 데 이 터 는 제출 한 데이터 가 없 기 때문에 다른 사물 이 읽 은 이 데 이 터 는 더러 운 데이터 이 고 더러 운 데이터 에 따라 조작 하 는 것 은 정확 하지 않다.
2.반복 해서 읽 으 면 안 됩 니 다.예 를 들 어 제 가 댓 글 을 읽 고 있 습 니 다.제 가 찾 아 낸 데 이 터 는 장 삼,이사 입 니 다.그리고 제 가 새로 고침 을 하 자마자 처음에 장 삼 이 장 팔 이 되 었 습 니 다.이것 이 바로 중복 해서 읽 을 수 없 는 것 입 니 다.제 가 읽 은 데 이 터 는 중복 되 지 않 았 기 때 문 입 니 다.
3.환 독:제 가 데 이 터 를 찾 을 때 부터 찾 아 낸 기록 은 3 개 입 니 다.제 가 새로 고침 을 하 자 기록 이 8 개 로 바 뀌 었 습 니 다.이것 이 바로 환 독 입 니 다.
4.제출 읽 기:제출 한 후에 야 읽 을 수 있 습 니 다.Oracle 은 기본적으로 이것 입 니 다.이런 방식 은 더러 운 읽 기 가 존재 하지 않 습 니 다.
5.중복 가능 도:중복 읽 을 수 없 는 것 과 반대 되 는 것 이 분명 하 다.중복 읽 을 수 없 는 것 을 피 할 수 있 지만 이것 은 환 독 을 피 할 수 없다.
6.서열 화:이런 방식 은 매우 엄격 하 다.쉽게 말 하면 내 가 한 가지 일 을 할 때 다른 누구 도 할 수 없고 안전 하지만 효율 이 매우 낮다.
격 리 단계

다음은 하 이 버 네 이 트 가 캐 시 를 지 우 는 애플 리 케 이 션 을 실제 사례 를 통 해 알 아 보 겠 습 니 다.
Hibernate 맵 데이터 베 이 스 는 메 인 키 생 성 정책 과 관련 이 있 습 니 다.
사례 1
UUID 방식 으로 메 인 키 를 생 성 하 는 예:

public class User {
	private String uid;
	private String uname;
	private Date birthday;
	public String getUid() {
		return uid;
	}
	public void setUid(String uid) {
		this.uid = uid;
	}
	public String getUname() {
		return uname;
	}
	public void setUname(String uname) {
		this.uname = uname;
	}
	public Date getBirthday() {
		return birthday;
	}
	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}
}
User.hbm.xml:

<?xml version="1.0"?> 
<!DOCTYPE hibernate-mapping PUBLIC 
  "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 
  "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 
<!-- package         -->   
<hibernate-mapping package="com.lixue.bean"> 
 <!-- class   name       ,table           table    --> 
 <class name="User" table="t_user"> 
  <id name="uid"> 
   <!--   UUID      --> 
   <generator class="uuid"/> 
  </id> 
  <property name="uname"/> 
  <property name="birthday"/> 
 </class> 
</hibernate-mapping> 
테스트 방법:

/** 
  *   uuid       
  */ 
 public void testSave1(){ 
  /*   Session   */ 
  Session session = null; 
  Transaction transaction = null; 
   
  try { 
   /*  session   */ 
   session = HibernateUtils.getSession(); 
   transaction = session.beginTransaction(); 
    
   /*    */ 
   User user = new User(); 
   user.setUname("   "); 
   user.setBirthday(new Date()); 
    
   /** 
    *   User        uuid,     save  ,   User   Session   
    *     insert  ,  ID    ,PersistenceContext  existsInDatebase   false 
    */ 
   session.save(user); 
    
   /** 
    *   flush,Hibernate     ( session->insertions              ,       ) 
    *               ,                   , 
    *         flush    ,  PersistenceContext existsInDatabase   true 
    */ 
   session.flush(); 
    
   /** 
    *      
    *      ,commit     flush    , 
    *          flush 
    * commit          
    */ 
   transaction.commit(); 
  } catch (Exception e) { 
   e.printStackTrace(); 
   transaction.rollback(); 
  } finally{ 
   HibernateUtils.closeSession(session); 
  } 
 } 
우 리 는 정지점 디 버 깅 프로그램 을 통과 할 수 있다.
1.User 의 메 인 키 생 성 사 이 드 율 이 UUID 이기 때문에 save()방법 을 호출 한 후에 User 대상 을 Session 관리 에 포함 시 킬 수 있 을 뿐 insert 문 구 를 보 내지 않 습 니 다.그러나 ID 는 이미 생 성 되 었 습 니 다.(주:save 이후 두 곳 이 중요 합 니 다.먼저 session->actionQueue->insertions->element Data 배열 에 우리 의 대상 을 저장 하 는 요소 가 있 습 니 다.이것 은 임시 집합 대상 입 니 다.또 하 나 는 PersistenceContext->Entity Entries->map->table->한 배열 요소->value 가 이 대상 을 저장 하고 있 습 니 다.value 아래 에 또 하나의 속성 이 있 습 니 다.바로 exists InDatabase 는 데이터베이스 에 대응 하 는 데이터 가 있 는 지 여부 입 니 다).그림:


2.flush()방법 을 호출 한 후 session 에 있 는 actionQueue 의 임시 저장 값 을 비 운 다음 PersistenceContext 에 있 는 exists InDatabase 의 값 을 true 로 설정 합 니 다.이때 데이터베이스 에 해당 하 는 데이터 가 있 음 을 표시 합 니 다.그러나 이때 데이터 베 이 스 를 열 면 데이터 가 보이 지 않 습 니 다.왜냐하면 우리 MySQL 데이터베이스 의 기본 격 리 단 계 는 제출 읽 기 입 니 다.즉,제출 해 야 데 이 터 를 읽 을 수 있 습 니 다.commt()방법 을 호출 한 후 데이터베이스 에 데이터 가 있 습 니 다.
사례 2
native 방식 으로 메 인 키 를 만 드 는 예:

public class User1 {
	private Integer uid;
	private String uname;
	private Date birthday;
	public Integer getUid() {
		return uid;
	}
	public void setUid(Integer uid) {
		this.uid = uid;
	}
	public String getUname() {
		return uname;
	}
	public void setUname(String uname) {
		this.uname = uname;
	}
	public Date getBirthday() {
		return birthday;
	}
	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}
}
User1.hbm.xml:

<?xml version="1.0"?> 
<!DOCTYPE hibernate-mapping PUBLIC 
  "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 
  "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 
<!-- package         -->   
<hibernate-mapping package="com.lixue.bean"> 
 <!-- class   name       (                ,     bug),table           table    --> 
 <class name="User1" table="t_user1"> 
  <id name="uid"> 
   <!--     --> 
   <generator class="native"/> 
  </id> 
  <property name="uname"/> 
  <property name="birthday"/> 
 </class> 
</hibernate-mapping> 
테스트 방법:

/** 
  *   native       
  */ 
 public void testSave2(){ 
  /*   Session   */ 
  Session session = null; 
  Transaction transaction = null; 
   
  try { 
   /*  session   */ 
   session = HibernateUtils.getSession(); 
   transaction = session.beginTransaction(); 
    
   /*    */ 
   User1 user = new User1(); 
   user.setUname("   "); 
   user.setBirthday(new Date()); 
    
   /** 
    *   User1        native,    Session.save() ,   insert  ,            
    *          ID,  Session   ,   Session existsInDatabase   true, 
    *                  ,        save     
    */ 
   session.save(user); 
    
   transaction.commit(); 
  } catch (Exception e) { 
   e.printStackTrace(); 
   transaction.rollback(); 
  } finally{ 
   HibernateUtils.closeSession(session); 
  } 
 } 
정지점 디 버 깅 프로그램 통과:
1.메 인 키 의 생 성 정책 이 native 이기 때문에 save()방법 을 호출 한 후 insert 문 구 를 실행 하고 임시 집합 대상 의 데 이 터 를 비우 고 데이터베이스 에서 생 성 된 ID 를 되 돌려 줍 니 다.
2.대상 을 session 관리 에 포함 시 키 고 Persistence Context 의 exists In Database 속성 을 true 로 수정 하 였 습 니 다.
사례 3
하 이 버 네 이 트 의 또 다른 방법 을 테스트 해 보 자.바로 evict()로 대상 을 session 에서 쫓 아 내 겠 다 는 뜻 이다.
UUID 메 인 키 생 성 정책 프로그램 에 대한 테스트 방법:

/** 
  *   uuid       
  */ 
 public void testSave3(){ 
  /*   Session   */ 
  Session session = null; 
  Transaction transaction = null; 
   
  try { 
   /*  session   */ 
   session = HibernateUtils.getSession(); 
   transaction = session.beginTransaction(); 
    
   /*    */ 
   User user = new User(); 
   user.setUname("   "); 
   user.setBirthday(new Date()); 
    
   /** 
    *   User        uuid,     save  ,   User   Session   
    *     insert  ,  ID    。Session  existsInDatebase   false 
    */ 
   session.save(user); 
    
   /* user   session   ,  PersistenceContext EntityEntries     */ 
   session.evict(user); 
    
   /** 
    *       ,  Hibernate      , session insertions       user    insert 
    *    ,    entityEntries    existsInDatabase true,      evict   
    *  user session entityEntries    ,     existsInDatabase  ,    ,     
    */ 
   transaction.commit(); 
    
  } catch (Exception e) { 
   e.printStackTrace(); 
   transaction.rollback(); 
  } finally{ 
   HibernateUtils.closeSession(session); 
  } 
 } 
정지점 디 버 깅 통과 하기:
1.UUID 의 메 인 키 생 성 정책 을 사용 하기 때문에 save()방법 을 사용 하면 insert 문 구 를 보 내지 않 고 대상 을 session 관리 에 포함 시 킵 니 다.ID 가 생 성 되 었 고 데이터베이스 에 대응 하 는 데이터(즉,exists InDatabase 속성 값 은 false)가 없습니다.
2.evict()를 호출 한 후 user 대상 을 session 에서 쫓 아 냅 니 다.즉,PersistenceContext 의 Entity Entries 속성 에서 쫓 아 냅 니 다.
3.내 가 commt()방법 을 다시 호출 할 때,우 리 는 우리 의 데 이 터 를 저장 할 수 없다 는 것 을 알 게 될 것 입 니 다.처음에 우리 의 exists InDatabase 속성 은 false 였 기 때 문 입 니 다.즉,데이터베이스 에 대응 하 는 데이터 가 존재 하지 않 았 고,이어서 우 리 는 evict()를 호출 하여 Persistence Context 의 이미지 속성(exists InDatabase 속성 도 포함)을 모두 삭 제 했 습 니 다.그러나 actionQueue 의 임시 저장 데 이 터 는 삭제 되 지 않 았 다.commt()방법 만 호출 할 때 flush()방법 을 암시 적 으로 호출 합 니 다.이 방법 은 이전에 도 말 했 듯 이 actionQueue 의 임시 대상 을 insert 작업 을 한 다음 에 Persistence Context 의 exists InDatabase 속성 값 을 true 로 설정 하지만 유 감 스 럽 습 니 다.Persistence Context 에 exists InDatabase 속성 이 없 기 때문에 오류 가 발생 할 수 있 습 니 다.저장 할 수 없습니다.
이 를 위해,우 리 는 상기 절 차 를 개선 합 니 다.

/** 
  *   uuid       
  */ 
 public void testSave4(){ 
  /*   Session   */ 
  Session session = null; 
  Transaction transaction = null; 
   
  try { 
   /*  session   */ 
   session = HibernateUtils.getSession(); 
   transaction = session.beginTransaction(); 
    
   /*    */ 
   User user = new User(); 
   user.setUname("   "); 
   user.setBirthday(new Date()); 
    
   /** 
    *   User        uuid,     save  ,   User   Session   
    *     insert  ,  ID    。PersistenceContext  existsInDatebase   false 
    */ 
   session.save(user); 
   /** 
    * flush Hibernate     ,  user         , session  insertions  user   
    *   ,    PersistenceContext existsInDatabase    true 
    */ 
   session.flush(); 
   /* user   session   ,  PersistenceContext EntityEntries     */ 
   session.evict(user); 
    
   /** 
    *       ,  Hibernate      , session insertions      
    *   user  (  flush    ),       insert  ,     session  existsInDatabase    
    */ 
   transaction.commit(); 
    
  } catch (Exception e) { 
   e.printStackTrace(); 
   transaction.rollback(); 
  } finally{ 
   HibernateUtils.closeSession(session); 
  } 
 } 
주:수 정 된 프로그램 은 save 에 표 시 된 flush()방법 을 호출 하고 evict()방법 을 호출 합 니 다.
정지점 디 버 깅 통과 하기:
1.UUID 생 성 정책 이기 때문에 save 를 호출 한 후에 insert 문 구 를 보 내지 않 고 대상 을 session 관리 에 포함 시 킵 니 다.Persistence Context 의 exists InDatabase 속성 은 false 입 니 다.
2.save()를 호출 한 후에 우 리 는 flush()방법 을 호출 했다.이 방법 은 캐 시 를 청소 하 는 역할 을 한다.즉,insert 문 구 를 보 내 고 session 에 있 는 insertions 의 임시 대상 을 데이터베이스 에 삽입 한 다음 에 이 임시 집합 을 비우 고 PersistenceContext 에 있 는 exists Indatabase 속성 을 true 로 설정 하 는 것 이다.
3.flush()를 호출 한 후에 evict()방법 을 호출 합 니 다.user 대상 을 session 에서 제거 하 는 역할 을 합 니 다.즉,Persistence Context 의 Entity Entries 속성 을 제거 하 는 것 입 니 다.
4.evict()방법 을 호출 한 후에 commt()방법 을 호출 합 니 다.이 방법 은 암시 적 으로 flush()방법 을 먼저 호출 합 니 다.flush 의 역할 은 캐 시 를 제거 하 는 것 입 니 다.곧 session->insertions 임시 집합 중의 대상 insert 를 데이터베이스 에 호출 합 니 다.그러나 우 리 는 이전에 flush()방법 을 호출 했 습 니 다.(주:이 방법 을 호출 한 후에 임시 집합 을 비 웁 니 다)그래서 임시 집합 은 대상 이 전혀 없습니다.그래서 insert 문 구 를 내지 않 습 니 다.Persistence Context 의 exists In Database 상 태 를 업데이트 하지 않 습 니 다.성공 적 으로 제출 할 수 있 습 니 다.
사례
네 이 티 브 방식 의 메 인 키 생 성 전략 에서 evict()방법 을 사용 하 는 것 을 다시 고려 해 보 겠 습 니 다.

/** 
  *   native       
  */ 
 public void testSave5(){ 
  /*   Session   */ 
  Session session = null; 
  Transaction transaction = null; 
   
  try { 
   /*  session   */ 
   session = HibernateUtils.getSession(); 
   transaction = session.beginTransaction(); 
    
   /*    */ 
   User1 user = new User1(); 
   user.setUname("   "); 
   user.setBirthday(new Date()); 
    
   /** 
    *   User1        native,    Session.save() ,   insert  , 
    *          ID,  Session   ,   Session existsInDatabase   true,          
    *                  ,        save     
    */ 
   session.save(user); 
    
   /* user   session   ,  PersistenceContext EntityEntries     */ 
   session.evict(user); 
    
   /** 
    *       ,  Hibernate         session insertions    
    *     user  ,       insert  ,     session  existtsInDatabase    
    */ 
   transaction.commit(); 
    
  } catch (Exception e) { 
   e.printStackTrace(); 
   transaction.rollback(); 
  } finally{ 
   HibernateUtils.closeSession(session); 
  } 
 } 
디 버 깅 통과:
1.메 인 키 생 성 정책 이 native 이기 때문에 save 방법 을 호출 한 후에 insert 문 구 를 보 내 데이터베이스 에서 생 성 된 ID 로 되 돌려 주 고 대상 을 session 관리 에 포함 시 킵 니 다.Persistence Context 의 exists InDatabase 속성 을 true,즉 데이터베이스 에 해당 하 는 데 이 터 를 수정 하고 임시 집합 대상 을 비 웁 니 다.하지만 MySQL 격 리 단계 때문에 제출 하지 않 을 때 까지 데 이 터 를 볼 수 없습니다.
2.save 를 호출 한 후에 evict()방법 을 호출 하여 대상 을 session 에서 쫓 아 냅 니 다.즉,Persistence Context 의 Entity Entries 에서 쫓 아 냅 니 다.
3.evict()방법 을 호출 한 후에 commt()방법 을 호출 합 니 다.이 때 는 제출 한 것 을 성공 적 으로 저장 할 수 있 습 니 다.commt()를 호출 하기 전에 flush()방법 을 암시 적 으로 호출 합 니 다.즉,캐 시 를 정리 하고 임시 집합 에서 대상 insert 를 데이터베이스 에 찾 습 니 다.그러나 임시 집합 에 데이터 가 없 기 때문에 insert 문 구 를 보 내지 않 습 니 다.PersistenceContext 의 exists In Database 속성 을 업데이트 하지 않 습 니 다.
상기 몇 가지 사례 를 통 해 우 리 는 가끔 우리 가 표시 해 야 할 flush()방법 으로 캐 시 를 정리 해 야 한 다 는 것 을 알 수 있다.또한 위 에서 우리 도 문 제 를 발견 했다.그것 은 바로 우리 가 save()데 이 터 를 제출 하지 않 았 을 때 데이터 가 보이 지 않 았 다 는 것 이다.즉,데이터 뱅 크 의 격 리 경계 가 제한 되 었 다 는 것 이다.지금 우 리 는 MySQL 의 격 리 단 계 를 말한다.
1.MySQL 데이터베이스 의 현재 격 리 단계 보기:
select @@tx_isolation;

주:그림 에서 알 수 있 듯 이 MySQL 데이터베이스 의 기본 격 리 단 계 는 중복 읽 기 가능 합 니 다.즉,중복 읽 기 불가,즉 제출 해 야 읽 을 수 있 습 니 다.
2.MySQL 의 현재 격 리 단 계 를 수정 합 니 다.set transaction isolation level read uncommited;
총결산
이상 이 바로 본 논문 의 Hibernate 에 관 한 Session 입 니 다.flush 와 격 리 단계 코드 에 대한 자세 한 내용 은 모두 에 게 도움 이 되 기 를 바 랍 니 다.관심 이 있 는 친 구 는 본 사이트 의 다른 관련 주 제 를 계속 참고 할 수 있 습 니 다.부족 한 점 이 있 으 면 댓 글로 지적 해 주 십시오.본 사이트 에 대한 여러분 의 지지 에 감 사 드 립 니 다!

좋은 웹페이지 즐겨찾기