Spanner 커밋 타임스탬프 기능을 사용하여 JDBC로 변경 로그 만들기

이 문서에서는 커밋 타임스탬프 기능을 사용하여 데이터베이스 레코드가 변경된 날짜와 시간을 추적하는 방법을 설명합니다. 레코드를 변경하는 트랜잭션이 많은 대규모 데이터베이스가 있고 데이터 세트의 변경사항을 캡처하려는 경우 커밋 타임스탬프 기능으로 이 작업을 간소화할 수 있습니다.

이 문서에서는 일련의 코드 샘플을 통해 기존 데이터 조작 언어(DML)를 다시 작성하여 변경 로그를 만드는 방법을 보여줍니다. 이 문서는 Cloud Spanner 커밋 타임스탬프를 사용하여 Go로 변경 로그 만들기에서 더 나아가 Java 및 JDBC를 사용하는 메서드를 설명합니다. 로직은 Spanner 클라이언트 객체가 아닌 SQL로 표현됩니다.

테이블 작동 방식

msgs라는 사실 테이블과 msg_history라는 기록 테이블이 있다고 가정하겠습니다. 사실 테이블이 수정될 때마다 레코드를 msg_history 테이블에 동시에 저장하려고 합니다. 나중에 감사 또는 이벤트 소스와 같은 다른 용도로 기록 테이블의 콘텐츠를 사용할 수 있습니다.

msgs 테이블에는 트랜잭션 ID(id)와 메시지(msg)로 표현되는 사실이 포함됩니다. 테이블을 만드는 데 사용되는 데이터 정의 언어(DDL) 문은 다음과 같습니다.

CREATE TABLE msgs (
    id INT64,
    msg STRING(MAX),
) PRIMARY KEY (id)

msg_history 테이블에는 트랜잭션 기록이 있습니다. 기록 테이블을 만드는 DDL은 다음과 같습니다. ts 열은 커밋 타임스탬프를 저장합니다.

CREATE TABLE msgs_history (
    id INT64,
    ts TIMESTAMP OPTIONS (allow_commit_timestamp=true),
    previous_msg STRING(MAX)
) PRIMARY KEY (ts, id)

예시

사실 테이블에만 기록하지 않고 동일한 트랜잭션의 기록 테이블에 작업을 수행해야 합니다. Spanner의 JDBC 드라이버는 표준 JDBC 작업인 트랜잭션의 시작과 끝 선언을 지원합니다.

1단계: 삽입 작업 재작성

첫 번째 단계는 다음 양식에서 insert 작업을 다시 작성하는 것입니다.

insert into msgs (id, msg) values (1, 'a real msg')
  • 다음과 같이 삽입을 변경합니다.

    insert into msgs_history (id, previous_msg, ts) values (1, Null, PENDING_COMMIT_TIMESTAMP());
    insert into msgs (id, msg) values (1, 'a real msg');
    

    자바 코드는 다음과 같습니다.

    // insert into history
    stmt.executeUpdate(
        "insert into msgs_history (id, previous_msg, ts)"
            + " values (1, Null, PENDING_COMMIT_TIMESTAMP())");
    // insert into real table
    stmt.executeUpdate("insert into msgs (id, msg)" + " values (1, 'a real msg')");
    conn.commit();
    

2단계: 업데이트 작업 재작성

다음으로, 다음 양식에서 update 작업을 다시 작성합니다.

update msgs set msg = 'new message' where id = 1
  • 다음과 같이 업데이트를 변경합니다.

    insert msgs_history (id, previous_msg, ts) values ((select id from msgs where id =1 ), (select msg from msgs where id = 1), PENDING_COMMIT_TIMESTAMP());
    update msgs set msg = 'new message' where id = 1;
    

    자바 코드는 다음과 같습니다.

    // insert into historystmt.executeUpdate(
        "insert msgs_history (id, previous_msg, ts)"
            + " values  ((select id from msgs where id =1),"
            + " (select msg from msgs where id = 1), PENDING_COMMIT_TIMESTAMP())");
    // update into fact table
    stmt.executeUpdate("update msgs set msg = 'new message' where id = 1");
    conn.commit();
    

3단계: 삭제 작업 재작성

마지막으로, 다음 양식에서 delete 작업을 다시 작성합니다.

delete from msgs where id = 1
  • 다음과 같이 삭제를 변경합니다.

    insert msgs_history (id, previous_msg, ts) values ((select id from msgs where id =1 ), (select msg from msgs where id = 1), PENDING_COMMIT_TIMESTAMP());
    delete from msgs where id = 1;
    

    자바 코드는 다음과 같습니다.

    // insert into history
    stmt.executeUpdate(
        "insert msgs_history (id, previous_msg, ts)"
            + " values  ((select id from msgs where id =1),"
            + " (select msg from msgs where id = 1), PENDING_COMMIT_TIMESTAMP()) ");
    // delete from real table
    stmt.executeUpdate("delete from msgs where id = 1");
    conn.commit();
    

기록 테이블 사용

  • 다음과 같이 변경 내역에 액세스합니다.

    select id,msg,current_timestamp() as ts
    from msgs where id = 1
    union all
    select id,previous_msg, ts as msg
    from msgs_history where id = 1 order by ts desc
    

    결과는 다음과 유사합니다.

    id    msg             ts
    1     new message     2020-02-07T07:44:10.24833726Z
    1     a real msg      2020-01-14T10:07:20.137935Z
    1                     2020-01-14T10:07:20.070374Z
    

다음 단계