자바 프로그래머 는 어 리 석 은 새 부터 초보 까지 (76) 히 버 네 이 트 (18) 비관 적 자물쇠 와 낙관적 자물쇠 해결 hibenate 병행

8615 단어 Hibernate
자물쇠 (locking) 라 는 개념 은 우리 가 다 중 스 레 드 를 배 울 때 접촉 한 적 이 있다. 사실은 이곳 의 자물쇠 와 다 중 스 레 드 에서 동시 다발 적 인 자 물 쇠 를 처리 하 는 것 은 하나의 이치 이 고 모두 폭력 적 으로 자원 을 자신의 소유 로 돌 리 는 것 이다.여기 서 우리 가 자 물 쇠 를 사용 하 는 목적 은 일부 체 제 를 통 해 일부 데이터 가 특정한 조작 과정 에서 외부 에서 수정 되 지 않도록 하 는 것 이다. 이런 체 제 는 여기 서 이른바 '자물쇠' 이다. 즉, 우리 가 선택 한 목표 데이터 에 자 물 쇠 를 채 워 다른 프로그램 에 의 해 수정 되 지 않도록 하 는 것 이다.Hibernate 는 일반적으로 말 하 는 '비관 적 잠 금 (Pessimstic Locking)' 과 '낙관적 잠 금 (Optimistic Locking)' 두 가지 잠 금 메커니즘 을 지원 합 니 다.비관 적 인 자물쇠 (Pessimstic Locking) 비관 적 인 자 물 쇠 는 그 이름 처럼 그 는 데이터 베이스 에 있어 데이터 베 이 스 를 비관 했다. 그 는 그 가 조작 하 는 모든 프로그램 이 병행 할 수 있다 고 느 꼈 다.이 는 데이터 가 외부 (본 시스템 의 현재 다른 사무, 그리고 외부 시스템 에서 온 사무 처리 포함) 에 의 해 수정 되 는 것 에 대해 보수 적 인 태 도 를 가지 기 때문에 전체 데이터 처리 과정 에서 데 이 터 를 잠 금 상태 에 두 는 것 을 말한다.비관 적 인 자물쇠 의 실현 은 흔히 데이터 베이스 가 제공 하 는 자물쇠 체제 (데이터 베이스 층 이 제공 하 는 자물쇠 체제 만 이 데이터 방문 의 배타 성 을 진정 으로 확보 할 수 있다. 그렇지 않 으 면 본 시스템 에서 잠 금 체 제 를 실현 하 더 라 도 외부 시스템 이 데 이 터 를 수정 하지 않 을 것 이 라 고 보장 할 수 없다).데이터베이스 에 의존 하 는 전형 적 인 비관 적 인 잠 금 호출
select * from account wherename=”Erica” forupdate

이것
sql
문구 가 잠 겼 다
account
표 의 모든 검색 조건 에 부합 (
name=

Erica

) 의 기록.이번 트 랜 잭 션 을 제출 하기 전에 (트 랜 잭 션 을 제출 할 때 트 랜 잭 션 과정 에서 잠 금 을 풀 어 줍 니 다) 외부 에서 이 기록 을 수정 할 수 없습니다.
Hibernate
비관 적 인 자물쇠 도 데이터 베 이 스 를 바탕 으로 하 는 자물쇠 체제 로 이 루어 진다.
아래 코드 는 조회 기록 에 대한 잠 금 을 실현 합 니 다.
String hqlStr ="from TUser as user where user.name=‘Erica‘";
Query query = session.createQuery(hqlStr);
query.setLockMode("user",LockMode.UPGRADE); //   
List userList = query.list();//     ,    

query.setLockMode
검색 어 에서 특정 별명 에 대응 하 는 기록 에 잠 금 을 추가 합 니 다.
TUser
클래스 가 별명 을 지 정 했 습 니 다.

user

), 여기 가 바로 돌아 오 는 모든 것 이다.
user
기록 에 자 물 쇠 를 채우다.
운행 기 를 관찰 하 다
Hibernate
생 성
SQL
문장:
select tuser0_.id as id, tuser0_.name as name,tuser0_.group_id
as group_id, tuser0_.user_type as user_type, tuser0_.sex as sex
from t_user tuser0_ where (tuser0_.name=‘Erica‘ )for update

여기, 이곳
Hibernate
데이터 베 이 스 를 사용 한
for update
자 구 는 비관 적 인 자물쇠 체 제 를 실현 하 였 다.
Hibernate 의 잠 금 모드 는 LockMode. NONE: 잠 금 장치 가 없습니다.LockMode. WRITE: Hibernate 는 Insert 와 Update 기록 에서 자동 으로 가 져 옵 니 다.LockMode. READ: Hibernate 는 기록 을 읽 을 때 자동 으로 가 져 옵 니 다.
상기 세 가지 잠 금 체 제 는 일반적으로 Hibernate 내부 에서 사용 합 니 다. 예 를 들 어 Hibernate 는 Update 과정 에서 대상 이 외부 에서 수정 되 지 않도록 save 방법 실현 에서 자동 으로 목표 대상 에 WRITE 잠 금 을 추가 합 니 다.LockMode. UPGRADE: 데이터베이스 의 for update 자 구 를 이용 하여 자 물 쇠 를 추가 합 니 다.LockMode. UPGRADE_NOWAIT: Oracle 의 특정한 실현, Oracle 의 for update nowait 자 구 를 이용 하여 잠 금 을 실현 합 니 다.위의 두 가지 잠 금 체 제 는 우리 가 응용 층 에서 비교적 자주 사용 하 는 것 이다. 잠 금 을 추가 하 는 것 은 보통 다음 과 같은 방법 으로 이 루어 진다. Criteria. setLockMode Query. setLockMode Session. lock
검색 이 시작 되 기 전에 (즉, Hiberate 가 SQL 을 생 성하 기 전에) 잠 금 을 설정 해 야 데이터베이스 잠 금 메커니즘 을 통 해 잠 금 처 리 를 할 수 있 습 니 다. 그렇지 않 으 면 데 이 터 는 for update 자 구 를 포함 하지 않 은 Select SQL 을 통 해 불 러 옵 니 다. 데이터베이스 잠 금 이라는 것 은 말 할 수 없습니다.
Hibernate 에서 비관 적 인 자 물 쇠 를 사용 하 는 것 은 매우 쉽 지만 실제 응용 에서 비관 적 인 자 물 쇠 는 거의 사용 되 지 않 는 다. 왜냐하면 이것 은 동시성 을 크게 제한 하고 데이터베이스 밑바닥 을 이용 하여 자 물 쇠 를 유지 하기 때문에 응용 프로그램의 효율 을 크게 떨 어 뜨 린 다.
다음은 hibenateAPI 에서 제공 하 는 get 방법 두 가 지 를 살 펴 보 겠 습 니 다.
Get(Classclazz,Serializable id,LockMode lockMode)
Get(Classclazz,Serializable id,LockOptionslockOptions )
get 방법의 세 번 째 인자 인 'lockMode' 나 'lockOptions' 를 볼 수 있 습 니 다. Hibernate 3.6 이상 버 전에 서' LockMode '는 사용 을 권장 하지 않 습 니 다.방법의 세 번 째 매개 변 수 는 비관 적 인 자 물 쇠 를 설정 하 는 데 사 용 됩 니 다. 세 번 째 매개 변 수 를 사용 한 후에 저희 가 보 내 는 SQL 문 구 는 'for update' 를 추가 하여 데이터 베 이 스 를 잠 그 는 데 사 용 됩 니 다.LockMode 매개 변 수 는 UPGRADE 옵션 을 선택 하면 비관 적 인 자물쇠 가 열 립 니 다.
낙관적 잠 금 (최 적 잠 금)
비관 적 인 자물쇠 에 비해 낙관적 인 자물쇠 체 제 는 더욱 느슨 한 잠 금 체 제 를 채택 했다.비관 적 인 잠 금 은 대부분 상황 에서 데이터 뱅 크 의 잠 금 체제 에 의 해 이 루어 져 작업 의 최대 독점 성 을 확보한다.그러나 이에 따 른 것 은 데이터베이스 성능 의 대량 지출 이다. 특히 긴 사무 에 있어 이런 지출 은 감당 할 수 없다.낙관적 인 자물쇠 메커니즘 이 어느 정도 에 이 문 제 를 해결 했다.낙관적 인 잠 금 은 대부분 데이터 버 전 (Version) 기록 체 제 를 바탕 으로 이 루어 진다.데이터 버 전 이란 무엇 입 니까?즉, 데이터 에 버 전 표 지 를 추가 하 는 것 이다. 데이터 베 이 스 를 바탕 으로 하 는 버 전 솔 루 션 에서 보통 데이터 베 이 스 를 위 한 'version' 필드 를 추가 하여 이 루어 진다.낙관적 잠 금 의 작업 원리: 데 이 터 를 읽 을 때 이 버 전 번 호 를 함께 읽 고 업데이트 할 때 이 버 전 번 호 를 1 로 추가 합 니 다.이때 제출 한 데이터 의 버 전 데 이 터 를 데이터베이스 테이블 에 대응 하 는 기 록 된 현재 버 전 정보 와 비교 하고 제출 한 데이터 버 전 번호 가 데이터베이스 테이블 의 현재 버 전 번호 보다 크 면 업데이트 한다. 그렇지 않 으 면 만 료 된 데이터 라 고 생각한다.
Hibernate 는 낙관적 인 자물쇠 에 3 가지 실현 을 제공 합 니 다.
1. version 기반
2. timestamp 기반
3. 남 겨 진 항목 에 낙관적 인 자 물 쇠 를 추가 합 니 다.
version 기반 낙관적 잠 금 설정:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC"-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
    <classname="com.bzu.hibernate.pojos.People"table="people">
        <idname="id"type="string">
            <columnname="id"></column>
            <generatorclass="uuid"></generator>
        </id>
      
        <!--version                -->
        <versionname="version"column="version"type="integer"></version>

        <propertyname="name"column="name"type="string"></property>
      
    </class>
</hibernate-mapping>

주: 실체 클래스 에 속성 version 추가 하 는 것 을 잊 지 마 세 요.
timestamp 기반 낙관적 잠 금 설정:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC"-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
    <classname="com.suxiaolei.hibernate.pojos.People"table="people">
        <id name="id"type="string">
            <column name="id"></column>
            <generator class="uuid"></generator>
        </id>
      
        <!--timestamp                -->
        <timestamp name="updateDate"column="updateDate"></timestamp>

        <propertyname="name"column="name"type="string"></property>


    </class>
</hibernate-mapping>

다음은 여러 개의 session 을 모 의 하여 version 기반 으로 테스트 를 진행 하 겠 습 니 다.
/*
         *     session  student   
         */
       
        Sessionsession1=sessionFactory.openSession();
        Session session2=sessionFactory.openSession();
        Studentstu1=(Student)session1.createQuery("from Student s wheres.name='tom11'").uniqueResult();
        Studentstu2=(Student)session2.createQuery("from Student s wheres.name='tom11'").uniqueResult();
       
        //   ,         
       System.out.println("v1="+stu1.getVersion()+"--v2="+stu2.getVersion());
       
        Transactiontx1=session1.beginTransaction();
       stu1.setName("session1");
        tx1.commit();
        //   ,         ,           
       System.out.println("v1="+stu1.getVersion()+"--v2="+stu2.getVersion());
       
        Transactiontx2=session2.beginTransaction();
       stu2.setName("session2");
        tx2.commit();

실행 결과:
Hibernate: insert into studentVersion (ver, name,id) values (?, ?, ?) Hibernate: select student0_.id as id0_, student0_.ver as ver0_, student0_.nameas name0_ from studentVersion student0_ where student0_.name='tom11' Hibernate: select student0_.id as id0_, student0_.ver as ver0_, student0_.nameas name0_ from studentVersion student0_ where student0_.name='tom11' v1=0--v2=0 Hibernate: update studentVersion set ver=?, name=? where id=? and ver=? v1=1--v2=0 Hibernate: update studentVersion set ver=?, name=? where id=? and ver=?Exception in thread "main" org.hibernate.StaleObjectStateException:Row was updated or deleted by another transaction (or unsaved-value mapping wasincorrect): [Version.Student#4028818316cd6b460116cd6b50830001]
두 번 째 '사용자' session 2 가 데 이 터 를 수정 할 때 기 록 된 버 전 번 호 는 session 1 에 의 해 업데이트 되 었 기 때문에 빨간색 이상 을 던 졌 습 니 다. 우 리 는 실제 응용 에서 이 이상 을 처리 할 수 있 습 니 다. 예 를 들 어 처리 과정 에서 데이터 베 이 스 를 다시 읽 는 동시에 현재 의 데이터 와 데이터 베 이 스 를 보 여 줌 으로 써 사용자 가 비교 할 수 있 도록 합 니 다.또는 디자인 프로그램 이 새로운 데 이 터 를 자동 으로 읽 습 니 다.

좋은 웹페이지 즐겨찾기