🚀
Growth log
  • About me
  • I LEARNED
    • General
      • 개발자 꿀팁
      • 그로스해킹 기초
      • 개발자에게 도메인 지식은 얼마나 중요할까?
      • DTO 논쟁에 대하여
      • MSA란?
    • Seminar
      • 테스트 커버리지 100% - SLASH 21
      • TDD가 실패하는 이유 - by 이규원님
      • 대규모 트래픽 애플리케이션 성능 튜닝 노하우 다 알려 드림|라인개발실록
      • 결제 시스템의 SDK와 API 디자인 - SLASH 21
    • Web
      • SOP와 CORS
    • Spring & OOP
      • DTO vs VO
    • Ruby On Rails
      • Rails lib 디렉토리에 대하여
      • Rails의 concerns란?
      • Rails에서의 GC 작동원리
      • Eager loading vs Lazy loading
      • Rails 환경 구성
      • ActionCable
      • 📔Perfect ruby on rails
        • MVC 패턴인 Rails
        • Ruby on Rails 기본 - 컨트롤러
        • Ruby on Rails 기본 - 뷰
        • Ruby on Rails 기본 - 모델
        • 스캐폴딩 기능을 사용한 Rails 개발 기초
        • 뷰 개발
        • 모델 개발
        • 모델 개발 - 낙관적 동시 실행 제어
        • 모델 개발 - 유효성 검사 구현
        • 모델 개발 - Association
        • 모델 개발 - 콜백
        • 모델 개발 - 마이그레이션
        • 모델 개발 - 데이터 초기화
        • 컨트롤러 개발 - 요청 정보 추출
        • 컨트롤러 개발 - 응답
        • 컨트롤러 개발 - 상태 관리
        • 라우팅 - RESTful
        • 라우팅 - RESTful 인터페이스의 사용자 정의화
        • 라우팅 - RESTful 하지 않은 라우트 정의
        • 테스트
        • 테스트 - 준비
        • 테스트 - Unit 테스트
        • 테스트 - Functional 테스트
        • 테스트 - Integration 테스트
        • 클라이언트 개발 - Sprockets vs Webpacker
        • 클라이언트 개발 - Sprockets
    • Node.js & Express
      • 기본 개념
      • npx
    • Programing Language
      • Java
        • JavaDoc에 대해
        • invocation에 대해서
        • 어노테이션
        • 추상클래스 & 인터페이스
        • Package
        • 오버로딩 vs 오버라이딩
      • Javascript
        • TCP School 훑어보기
          • 타입
          • 형 변환
          • 변수
          • 연산자
          • 반복문
          • 배열(array)
          • 함수
          • 함수 - 스코프와 호이스팅
          • 함수 - 매개변수와 인수
          • 함수 - 미리 정의된 전역 함수
          • 객체
          • 프로토타입
          • DOM
          • BOM - Window 객체
          • 이벤트(event)
      • Ruby
        • 📔퍼펙트 루비
    • DB
      • Redis
        • Redis 개요
      • Index(인덱스)?
      • DB Transaction & Lock
      • 동시성 제어에 관하여
      • Lock(잠금)이란?
      • ActiveRecord lock vs with_lock
      • Table lock vs Row lock
      • WHERE 1=1 구문에 대하여
      • COUNT(*) vs COUNT(indexed column)
      • 📕관계형 데이터베이스 실전입문
      • 📔SQL 첫걸음
      • 📔모두의 SQL
    • Design Patterns
      • Observer pattern
      • Flyweight pattern
      • Singleton pattern
    • OOP
      • 📔오브젝트
        • 6장 메시지와 인터페이스
      • 클래스간 관계 간단 정리
    • Regex
    • Collaboration
      • Git
      • Sourcetree
  • DAILY REVIEW
    • 2021
      • August
        • 2021-08-25(Wed)
        • 2021-08-23(Mon)
        • 2021-08-11(Wed)
        • 2021-08-04(Wed)
        • 2021-08-03(Tue)
        • 2021-08-02(Mon)
      • July
        • 2021-07-29(Thu)
        • 2021-07-26(Mon)
        • 2021-07-23(Fri)
        • 2021-07-22(Thu)
        • 2021-07-21(Wed)
        • 2021-07-20(Tue)
        • 2021-07-19(Mon)
        • 2021-07-15(Thu)
        • 2021-07-14(Wed)
        • 2021-07-13(Tue)
        • 2021-07-12(Mon)
      • June
        • 2021-06-05(Sat)
        • 2021-06-04(Fri)
        • 2021-06-03(Thu)
        • 2021-06-02(Wed)
        • 2021-06-01(Tue)
      • May
        • 2021-05-31(Mon)
        • 2021-05-29(Sat)
        • 2021-05-28(Fri)
        • 2021-05-27(Thu)
        • 2021-05-26(Wed)
        • 2021-05-25(Tue)
        • 2021-05-24(Mon)
        • 2021-05-22(Sat)
        • 2021-05-21(Fri)
        • 2021-05-20(Thu)
        • 2021-05-19(Wed)
        • 2021-05-18(Tue)
        • 2021-05-17(Mon)
        • 2021-05-15(Sat)
        • 2021-05-13(Thu)
        • 2021-05-12(Wed)
        • 2021-05-11(Tue)
        • 2021-05-10(Mon)
        • 2021-05-03(Mon)
      • April
        • 2021-04-30(Fri)
        • 2021-04-29(Thu)
        • 2021-04-28(Wed)
        • 2021-04-27(Tue)
        • 2021-04-26(Mon)
        • 2021-04-24(Sat)
        • 2021-04-23(Fri)
        • 2021-04-21(Wed)
        • 2021-04-20(Tue)
        • 2021-04-19(Mon)
        • 2021-04-18(Sun)
        • 2021-04-16(Fri)
        • 2021-04-15(Thu)
        • 2021-04-14(Wed)
        • 2021-04-12(Mon)
        • 2021-04-11(Sun)
        • 2021-04-09(Fri)
        • 2021-04-08(Thu)
        • 2021-04-06(Tue)
        • 2021-04-05(Mon)
        • 2021-04-04(Sun)
        • 2021-04-03(Sat)
        • 2021-04-02(Fri)
        • 2021-04-01(Thu)
      • March
        • 2021-03-29(Mon)
        • 2021-03-28(Sun)
        • 2021-03-26(Fri)
        • 2021-03-25(Thu)
        • 2021-03-24(Wed)
        • 2021-03-23(Tue)
        • 2021-03-22(Mon)
        • 2021-03-21(Sun)
        • 2021-03-20(Sat)
        • 2021-03-17(Wed)
        • 2021-03-16(Tue)
        • 2021-03-15(Mon)
        • 2021-03-12(Fri)
        • 2021-03-11(Thu)
        • 2021-03-10(Wed)
        • 2021-03-09(Tue)
        • 2021-03-08(Mon)
        • 2021-03-07(Sun)
        • 2021-03-05(Fri)
        • 2021-03-03(Wed)
        • 2021-03-02(Tue)
        • 2021-03-01(Mon)
      • Feb
        • 2021-02-26(Fri)
        • 2021-02-25(Thu)
        • 2021-02-24(Wed)
        • 2021-02-23(Tue)
        • 2021-02-22(Mon)
        • 2021-02-19(Fri)
        • 2021-02-18(Thu)
        • 2021-02-17(Wed)
        • 2021-02-16(Tue)
        • 2021-02-15(Mon)
        • 2021-02-14(Sun)
        • 2021-02-13(Sat)
        • 2021-02-12(Fri)
        • 2021-02-10(Wed)
        • 2021-02-09(Tue)
        • 2021-02-08(Mon)
        • 2021-02-07(Sun)
        • 2021-02-05(Fri)
        • 2021-02-03(Wed)
        • 2021-02-02(Tue)
        • 2021-02-01(Mon)
      • Jan
        • 2021-01-29(Fri)
        • 2021-01-28(Thu)
        • 2021-01-27(Wed)
        • 2021-01-26(Tue)
        • 2021-01-25(Mon)
        • 2021-01-23(Sat)
        • 2021-01-22(Fri)
        • 2021-01-20(Wed)
        • 2021-01-19(Tue)
        • 2021-01-18(Mon)
        • 2021-01-12(Tue)
        • 2020-01-11(Mon)
        • 2021-01-08(Fri)
        • 2021-01-07(Thu)
        • 2021-01-06(Wed)
        • 2021-01-05(Tue)
        • 2021-01-04(Mon)
        • 2021-01-01(Fri)
    • 2020
      • Dec
        • 2020-12-30(Thu)
        • 2020-12-25(Fri)
        • 2020-12-24(Thu)
        • 2020-12-23(Wed)
        • 2020-12-22(Tue)
        • 2020-12-21(Mon)
        • 2020-12-18 (Fri)
      • Nov
        • 2020-11-30(Mon)
        • 2020-11-28(Sat)
        • 2020-11-26(Thu)
        • 2020-11-25(Wed)
        • 2020-11-24(Tue)
        • 2020-11-23(Mon)
        • 2020-11-22(Sun)
        • 2020-11-20(Fri)
        • 2020-11-19(Thu)
        • 2020-11-18(Wed)
        • 2020-11-17(Tue)
        • 2020-11-14(Sat)
        • 2020-11-13(Fri)
        • 2020-11-12(Thu)
        • 2020-11-11(Wed)
        • 2020-11-09(Mon)
        • 2020-11-07(Sat)
        • 2020-11-05(Thu)
        • 2020-11-04(Wed)
        • 2020-11-03(Tue)
        • 2020-11-02(Mon)
    • Good article 아카이빙
Powered by GitBook
On this page
  • 개념 정리
  • Table locks
  • Single-row locks
  • 사용
  • Table locks
  • Row locks
  • 참고

Was this helpful?

  1. I LEARNED
  2. DB

Table lock vs Row lock

실무에서 실수하지 않는 것이 목표이며, 시나리오 중심으로 개념을 공고히 합니다.

개념 정리

구문에 따라서 lock되는 데이터의 범위 & 양이 달라질 수 있다.

Table locks

  • 테이블 전체를 잠근다.

  • 데드락이 발생하지 않는다.

  • Row-level locking을 하더라도 조건 필드에 인덱스가 없으면 전체 테이블에 lock이 걸린다.

      • MySQL이 조회된 행을 기억하는 방법이 인덱스 범위를 기억하는 것이기 때문.

  • 많은 수의 Row-level locking을 시도할 때 Table locking이 더 효율적이라면, 전체 테이블에 lock이 걸릴 수도 있다. 이는 Lock Escalation 이라고 한다.

Single-row locks

  • 트랜잭션 격리 레벨에 따라 다르게 적용된다.

  • 데드락이 발생하지 않도록 주의해야한다. 특히 innoDB나 BDB 타입의 테이블들은 deadlock-free하지 않으므로 주의할 것.

사용

Table locks

사용 방법

READ lock인지 WRITE lock인지 설정할 수 있다.

-- MySQL
LOCK TABLES table_name [READ | WRITE];

Rails에서는 Table lock을 공식적으로 지원하지는 않는다. 그래서 아래처럼 직접 SQL문을 넣어줘야한다.

ActiveRecord::Base.transaction do
  ActiveRecord::Base.connection.execute('LOCK TABLES table_name READ')
  ...
end

사용 시나리오

Table lock은 전체 테이블에 대한 데이터 변경이 있을 경우 사용한다. 테이블을 제어하는 DDL 구문을 사용할 때 Lock이 걸린다고 하여 DDL Lock이라고도 한다.

운영 중인 테이블을 복제(CREATE SELECT)하거나 다른 테이블로 옮길 경우(INSERT SELECT) Transaction Isolation Level을 READ COMMITTED 변경하고 작업하기를 권장한다.

  • 그렇지 않으면 관련된 Table은 Exclusive Lock이 걸리고, 관련 Query들이 대기 상태로 빠지면서 시스템 장애가 발생할지도 모르기 때문.

Row locks

사용방

FOR UPDATE 를 붙여주면 Exclusive lock을 건다. 이 때 MySQL은 Row 전체에 lock을 거는 것이 아니라 인덱스에 건다고 하니 참고.

-- MySQL
SELECT * FROM table_name WHERE id=10 FOR UPDATE;

lock 모드를 SHARE MODE로 걸 수도 있다.

-- MySQL
SELECT * FROM table_name WHERE id=10 LOCK IN SHARE MODE

ActiveReocrd에서는 lock 구문이나 with_lock 구문을 이용하면, 위 FOR UPDATE SQL 구문을 생성해준다.

# lock
user = User.lock.find_by(id: params[:id])
user.reward = user.reward + params[:reward].to_i
user.save!

# with_lock
user = User.find_by(id: params[:id])
user.with_lock do
  user.reward = user.reward + params[:reward].to_i
  user.save!
end

사용 시나리오

특정 user의 reward 컬럼 값을 100만큼 증가시키는 API가 있다고 하자. 그리고 user.reward가 원래 0원인 상태에서 200원이 되도록 하기 위해 이 API를 동시에 2차례 호출한다고 생각해보자. 그리고 이 API 호출을 각각 1번 API 호출, 2번 API 호출로 명명해보겠다.

만약 이 API에 lock 처리가 되어있지 않은 상태라면, 이 1번 호출, 2번 호출이 동시에 진행되었을 때 문제가 생길 수 있다.

  • 1번 호출과 2번 호출에서 user 값을 read해올 때, 아직 update가 되기 전의 값을 read 해올 수 있기 때문.

  • 구체적으로는 user.reward를 0원으로 불러오고, 결과적으로 두 요청 모두 user.reward 값을 0원에서 100원으로 증가시킨 뒤 최종적으로 100원이 된 상태에서 user.save 를 호출하게 되어, 0원에서 200원이 되는 것이 아니라 0원에서 100원이 될 수 있다.

대신 Exclusive lock 처리를 하면, 1번 호출, 2번 호출이 동시에 진행되더라도 문제를 방지할 수 있다.

  • 1번 호출과 2번 호출에서 user 값을 read해올 때, 다른 호출에서 lock을 들고 있으면, lock이 풀릴 때까지 기다렸다가 값을 read해오기 때문에, 순차적으로 reward 값을 증가시킬 수 있기 때문이다.

참고

PreviousActiveRecord lock vs with_lockNextWHERE 1=1 구문에 대하여

Last updated 3 years ago

Was this helpful?

Scope of locks
MySQL locking - Table-Level Locking, Row-Level Locking, Optimistic Locking
https://www.sqlshack.com/locking-sql-server/
https://jupiny.com/2018/11/30/mysql-transaction-isolation-levels/
https://myinfrabox.tistory.com/75
https://stackoverflow.com/questions/24587403/rails-activerecord-how-can-i-lock-a-table-for-reading
https://suhwan.dev/2019/06/09/transaction-isolation-level-and-lock/
https://dev.mysql.com/doc/refman/8.0/en/lock-tables.html
http://labs.brandi.co.kr/2019/06/19/hansj.html
https://www.javatpoint.com/mysql-table-locking
https://xpertdeveloper.com/row-locking-with-mysql/