본문 바로가기
nodejs

mikro-orm auto increment issue 등록 후기

by pius712 2024. 4. 17.

이슈등록: https://github.com/mikro-orm/mikro-orm/issues/5460

 

Mysql auto_increment_increment setting is not work. · Issue #5460 · mikro-orm/mikro-orm

Describe the bug If you set mysql variable auto_increment_increment to 2, When saving multiple entities, pk should be incremented by 2. However, if you use the following code in the MySqlDriver fil...

github.com

 

[ 문제 상황 ] 

사내에서 mikro-orm 을 Mysql 과 사용하고 있는데, 사내 db는  짝수 채번을 하고 있는데, 이상하게 mikro-orm 에서 여러 entity 를 영속화하면 pk 가 순차적으로 나오는 문제가 있었다. 

 

[ 이슈의 정체 ] 

JPA의 경우 ORM 채번을 할 때, 아래의 mysql ok packet 을 통해서 이루어진다. 

https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_basic_ok_packet.html

 

이후에 auto_increment 에 대한 설정 값을 요청하여서, 이를 기반으로 영속성 컨텍스트에 auto_increment pk 를 세팅을 하기 마련이다.

 

MySQL: OK_Packet

An OK packet is sent from the server to the client to signal successful completion of a command. As of MySQL 5.7.5, OK packets are also used to indicate EOF, and EOF packets are deprecated. if CLIENT_PROTOCOL_41 is set, the packet contains a warning count.

dev.mysql.com

 

단순 repository.save 호출을 한다고 가정하면, 아래의 패킷이 날아간다. 

1. begin 

2. insert into 'table' ('데이터')

3. commit

 

그리고 2번 패킷에서 OK packet 에 자세히 보면 아래와 같이 Last INSERT ID 라는 값이 내려온다. 

이 값을 기준으로 entity 에 id 를 세팅해준다. (참고로, commit 되기전에 db 에서는 채번이 되고, db 에서 한번 채번되는 경우에 tx 가 롤백이 되더라도 이후에 같은 값을 사용하지는 않는다 -> pk 는 항상 순차가 아닐 수도 있음)

 

사실 이런 부분은 mikro-orm 도 똑같을거라고 생각을 했는데, mikro-orm 자체가 어떤 특별한 재주를 부리는건 아닐거라서 MySQL 서버와의 통신을 통해서 채번한 결과를 사용하는건 당연해보였다. 

 

그런데, 아래와 같이 여러 개의 entity 를 저장하는 경우에 이상하게 pk 가 순차로 나왔다. (실제 코드는 아니고, 단순화하였다)

mysql 채번 결과를 바탕으로 entity 의 pk가 정해질 텐데,  pk가 순차적으로 생성되니 의아했다.

const result = await this.postRepository.save([
      new PostEntity('title'),
      new PostEntity('title2'),
      new PostEntity('title3'),
    ]);
    return result;
  }

@Injectable()
export class PostRepository {
  constructor(
    @InjectRepository(PostEntity)
    private readonly postRepository: EntityRepository<PostEntity>,
  ) {}

  async save(entity: PostEntity | PostEntity[]): Promise<PostEntity | PostEntity[]> {
    await this.postRepository.getEntityManager().persistAndFlush(entity);

    return entity;
  }
}

 

 

그래서, 해당 패킷이 어떻게 나가는지 wireshark 를 통해 패킷 분석을 해보았다 

wireshark 를 사용하여 packet 을 확인해보니 auto_increment 에 대한 쿼리가 패킷으로 잘 날아갔다. 

 

Ok packet이 잘 왔고, auto_increment 변수에 대한 값도 잘 조회하고 있었다. 

 

그런데 결과는 아래와 같았다. 

- entity: pk 는 1씩 증가

- tx commit 이후 db: db 레코드의 pk는 2씩 증가하고 있었다.

 

mikro-orm 버그가 확실해 보였고, 브레이크 포인트를 찍어서 확인을 해보았다. 

 

아래 코드에서 this.autoIncrementIncrement 필드에 1을 세팅하고 있는게 문제의 원인이었다.

mikro-orm 의 connection 은 mikro-orm/knex 라는 라이브러리를 통해 이루어지는데, 여기서 res는  Value 로 내려오는데,

할당 시에는 res?.auto_increment_increment 로 할당하고 있던게 문제였다.

async getAutoIncrementIncrement(ctx) {
        if (this.autoIncrementIncrement == null) {
            // the increment step may differ when running a cluster, see https://github.com/mikro-orm/mikro-orm/issues/3828
            const res = await this.connection.execute(`show variables like 'auto_increment_increment'`, [], 'get', ctx, { enabled: false });
            /* istanbul ignore next */
            this.autoIncrementIncrement = res?.auto_increment_increment ? +res?.auto_increment_increment : 1;
        }
        return this.autoIncrementIncrement;
    }

 

 

[ 후기 ] 

사실 팀 내에서 이 문제에 대해서 인지는 하고 있었고, 다른 방식으로 문제를 해결하고 있었다. 

그런데 시간이 나서, 트러블 슈팅을 해보았고 위와 같은 이슈가 있다는 것을 알게 되었던 것이다. 

 

그래서 이 부분에 대해서 이슈를 등록했고, 올라온지 몇시간도 안되어서 수정되었다.

 

사실 처음부터 pr 을 올릴까 말까 고민을 했는데, 

orm 특성상 driver 의 버전에 의해 생기는 버그일 수도 있다고 생각을 해서 pr 을 올리지 않고 상세하게 이슈 리포팅을 했다.

 
무지성 pr을 올릴걸하는 아쉬움이 남는다 ㅋㅋ

'nodejs' 카테고리의 다른 글

mikro orm의 request context 주저리  (0) 2024.02.18