golang으로 회원가입 기능을 구현하면서, 중간에 에러가 발생했을 시 지금까지의 쿼리를 전부 다 ROLLBACK 하도록 만들어야 했다.
데이터베이스에 연결하고 트랜잭션을 생성하는 것은 GO 사이트에 있는 코드를 참고하였다.
package main
import (
"database/sql"
"log"
_ "github.com/go-sql-driver/mysql"
)
func main() {
// sql.DB 객체 생성
db, err := sql.Open("mysql", "root:pwd@tcp(127.0.0.1:3306)/testdb")
if err != nil {
log.Fatal(err)
}
defer db.Close()
// 트랜잭션 시작
tx, err := db.Begin()
if err != nil {
log.Panic(err)
}
defer tx.Rollback() //중간에 에러시 롤백하도록 defer 한다
// INSERT 문 실행
_, err = tx.Exec("INSERT INTO test1 VALUES (?, ?)", 15, "Jack")
if err != nil {
//에러메시지를 출력하고 panic() 호출.
//panic()은 defer를 실행한다.
log.Panic(err)
}
_, err = tx.Exec("INSERT INTO test2 VALUES (?, ?)", 15, "Data")
if err != nil {
log.Panic(err)
}
// 트랜잭션 커밋
err = tx.Commit()
if err != nil {
log.Panic(err)
}
}
참고 : http://golang.site/go/article/109-MySql-%EC%82%AC%EC%9A%A9---%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98
예제로 배우는 Go 프로그래밍 - MySql 사용 - 트랜잭션
MySql 트랜잭션 복수 개의 SQL 문을 하나의 트랜잭션으로 묶기 위하여 sql.DB의 Begin() 메서드를 사용한다. 트랜잭션은 복수 개의 SQL 문을 실행하다 중간에 어떤 한 SQL문에서라도 에러가 발생하면 전체 SQL문을 취소하게 되고 (이를 롤백이라 한다), 모두 성공적으로 실행되어야 전체를 커밋하게 된다. Begin() 메서드는 sql.Tx 객체를 리턴하는데, 이 Tx 객체로부터 Tx.Exec() 등을 실행하여 트랜잭션을 수행한 후, 마지막에
golang.site
하지만 문제는 저기 있는 코드를 참고해서 이리 바꿔보고 저리 바꿔봐도 중간에 에러가 발생하면 롤백처리가 되지 않았다.
Rollback(), Commit() 메서드 구현을 잘못했나하는 생각이 들어서 tx.Exec("rollback;") 까지 넣어보았지만 적용되지 않았다(...) 그 뒤로 계속 코드를 바꿔보았지만 실패...
코드의 문제가 아니라 데이터베이스 문제일 거라는 생각이 들었고 set autocommit = false; 로 설정해봐도 소용이 없었다.
아니, 도대체 뭐가 문제지? 라는 생각이 들 때쯤 스토리지 엔진(데이터베이스 엔진) 이라는 것을 알게 되었다.
스토리지 엔진 (데이터베이스 엔진)
스토리지 엔진은 실질적으로 데이터의 변경을 수행하는 데이터베이스 서버의 구성요소이다. 엔진은 여러 종류가 있고 코딩의 목적에 따라서 특정 엔진을 선택할 수 있다.
MySQL의 엔진 종류는 아래 쿼리를 통해 확인할 수 있다.
위와 같이 총 8개의 엔진을 지원하고 있으며, 플러그인이 가능한 성격이기 때문에 엔진이 바뀌었다고 해서 구현된 코드를 변경하거나 할 일이 없다. Comment 필드에서 해당 엔진에 대한 설명을 볼 수 있지만, 대표적으로 MyISAM과 InnoDB를 비교해보도록 하겠다.
1. MyISAM (마이아이삼?? 아이에스에이엠?? 아이샘?? ????)
Feature | Support |
Transaction | No |
Locking granularity | Table |
storage limit | 256TB |
보다시피 트랜잭션을 지원하지 않는다!!!!
아무리 set autocommit = false; 로 설정하고 rollback을 해도 이미 수행된 쿼리는 commit이 되어 되돌릴 수가 없다.
그래서 안되는 거였다. 아무리 해도 안되더라니.
단순 읽기 작업이나 변경이 없는 테이블에 insert하는데 속도가 빠르다고 한다. 또한 Table 단위로 locking를 하기 때문에 쓰고 변경하는 작업에 느리다.
2. InnoDB
Feature | Support |
Transactions | Yes |
Locking granularity | Row |
storage limit | 64TB |
InnoDB는 트랜잭션을 지원하기 때문에, start transaction; 후 rollback으로 데이터를 되돌릴 수 있다.
row 단위로 로킹하기 때문데 다수 사용자의 동기적 수행에 장점을 가지고, 대량의 데이터를 처리하는데 유리하다고 한다.
엔진을 InnoDB로 변경한 후, golang tx.Rollback() 이 잘 적용된 것을 확인하였다!!!!
엔진은 테이블 생성 시 쉽게 설정할 수 있고, 아래 쿼리로도 설정할 수 있다.
CREATE TABLE tb_name(no INT) ENGINE = INNODB;
혹시 트랜잭션 처리를 계속 했는데도 자동으로 커밋되는 경우, 스토리지 엔진을 한 번 확인해보자.
스토리지 엔진 및 각 엔진에 대한 자세한 설명을 보고 싶다면 아래 MySQL doc 을 참고.
참고 : https://dev.mysql.com/doc/refman/8.0/en/pluggable-storage-overview.html
dev.mysql.com
'프로그래밍 > Go' 카테고리의 다른 글
[AWS Mediaconvert] go SDK 로 mediaconvert job 실행하기 (1) | 2022.10.15 |
---|---|
[채팅-2] go elastic search client (0) | 2021.04.29 |
[채팅-1] go의 라우터, 미들웨어, 컨트롤러 (0) | 2021.04.28 |
[golang] api 메모리 누수 처리하기 (0) | 2020.10.18 |
[golang] 포인터와 주소값 (0) | 2020.01.27 |