mysql for update deadlock

mysql db 를 사용하는 api server(golang) 에서 2개의 insert 요청 발생중 deadlock 이 발생했다.
Error 1213 (40001): Deadlock found when trying to get lock

InnoDB 인덱스는 행 사이에는 gap 이라는 빈 구간이 있다.
a행 - (gap) - b행 - (gap) - c행

다음과 같은 A,B 양쪽에서 insert 하기전 존재 여부를 판단하기 위해 for update 로 gap lock 을 획득하려고 했다. 
A: SELECT d FOR UPDATE -> 없음 -> gap lock 획득 
B: SELECT e FOR UPDATE -> 없음 -> gap lock 획득 (gap lock 끼리는 공존)
A: INSERT or UPDATE d -> B 의 gap lock 에 막혀 대기
B: INSERT or UPDATE e -> A 의 gap lock 에 막혀 대기
서로를 기다리는 데드락 상태가 된다.
InnoDB 기본설정에 innodb_deadlock_detect=ON 있어 데드락을 감지하고 한쪽을 롤백시킨다.

User (부모 테이블) - UserResource (자식 테이블)  있다고 했을때

// 있으면 update 없으면 insert
func saveUserResource(tx *gorm.DB, userID uint64, val int64) error {
        // 수정 전 - 자식 테이블에 아직 없는 행을 잠그면 데드락 발생할 수 있다.
        // var userRC entity.UserResource
        // err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).Where("`user_id`=?", userID).Take(&userRC).Error

        // 수정 후
        // 항상 존재하는 부모 users 행을 PK 로 잠가 같은 사용자의 저장을 줄 세운다 (record lock).
        if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).
                Model(&entity.User{}).
                Select("`id`").
                Where("`id`=?", userID).
                Take(&entity.User{}).Error; err != nil {
                return err // 부모가 없으면 ErrRecordNotFound
        }
        // 자식 행은 잠금 없이 조회한다. 부모 잠금 덕분에 같은 사용자의 다른 저장은 여기 들어오지 못하고 기다린다.
        var userRC entity.UserResource
        err := tx.Where("`user_id`=?", userID).Take(&userRC).Error
        if errors.Is(err, gorm.ErrRecordNotFound) {
                return tx.Create(&entity.UserResource{UserID: userID, Val: val}).Error
        } else if err != nil {
                return err
        }
        return tx.Model(&userRC).Update("val", val).Error
}

jcode profile error

언제부턴가 어떤 앱을 사용중에도 cmd+; 또는 cmd+' 를 누르면 사용하다 갑자기 다음과 같은 터미널 에러 창이 뜬다.

Last login: Wed Oct 21 16:16:42 on ttys002
[ysoftman] load /etc/profile
ysoftman - ~/.profile loaded
bash: line 0: exec: env: not found

Ghostty failed to launch the requested command:
/usr/bin/login -flp ysoftman
  Runtime: 59 ms

Press any key to close the window.

https://jcode.sh/ (rust 로 만든 수십개 에이전트를 병렬로 돌려도 느려지지 않는 coding agent tool) 를 설치하고 잊고 있었다.
jcode 를 설치하면 아마 자동으로 jcode 가 실행되도록 단축키 설정(~/.jcode/config.toml)을 한것으로 보인다.

# 단축 변경 적용하기
# jcode setup-hotkey
[launch_hotkeys]
enabled = true

[[launch_hotkeys.entries]]
chord = "cmd+;"
dir = "/Users/ysoftman/workspace/myenv"
label = "myenv"
self_dev = false

[[launch_hotkeys.entries]]
chord = "cmd+'"
dir = "$HOME"
label = "home"
self_dev = false

jcode 실행이 login -l 옵션으로 ~/.profile 을 읽었는데 PATH 변수가 이전 $PATH 보전을 하지 않고 다음과 같이 설정돼 /usr/bin/env 를 찾지 못하고 있었다.
~/.vector 를 보니 2023년에 생성된 예전 흔적으로 다음 줄을 삭제하니 에러없이 jcode 가 실행된다.
export PATH=/Library/Apple/usr/bin:/Users/ysoftman/.vector/bin

bun fmt

웹 프로젝트에서 포맷팅을 주로 biome를 사용하고 있었고, biome 이 html 포맷만 지원이 안돼 prettier 를 사용하고 있었다.
그런데 bun fmt , bun lint 기능이 2026년 10월 12일에 추가되었다.
아직 main 브랜치에만 머지된 상태다.
bun 빌드/런타임으로만 쓰고 있었는데 이번에 변경해 봐야겠다.
bun main 브랜치 빌드해 biome, prettier 와 벤치마크 해보니 bun fmt 가 가장 빠르다.
lint 도 eslint 보단 확실히 빠르고 oxlint, biome 와 파일 종류와 크기에 따라 약간의 차이가 났다.


bun 이 rust 로 새로 구현하고 부터 같은 rust 계열의 oxfmt/lint, biome 툴들과 경쟁이 붙는것 같다.
사용자 입장에선 성능만 좋으면 포맷,린트,빌드,런타임까지 bun 하나로 처리되니 좋을 것 같다.
biome, oxfmt/lint 가 단순히 포맷터,린터 기능에만 머문다면 bun에 밀릴지도...

Prev