go-sql-driver-mysql로 CURD 해보기
2021-03-27 22:27:45

소개

  • 순수 Go로 작성되어 있다.
  • 끊어진 커넥션 자동 연결 처리
  • 풀링 자동 지원 👏🏻

설치

1
go get github.com/go-sql-driver/mysql

연결

Open 함수는 연결에 대한 추상화만 하고 실제 연결은 쿼리가 실행될 때 된다고 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import (
"database/sql"
"time"
_ "github.com/go-sql-driver/mysql"
)

func getConnection() *sql.DB {
// 연결 형태 -> 사용자명:비번@프로토콜(주소:포트)/데이터베이스명
db, err := sql.Open("mysql", "root@tcp(localhost:3306)/test")
if err != nil || db.Ping() != nil { // 핑을 통해 네트워크 연결 및 DB 사용 가능한지 체크
panic(err)
}
db.SetConnMaxLifetime(time.Minute * 3) // 유휴 연결 시간 설정 (5분 미만으로 잡는 게 좋다고 함)
db.SetMaxOpenConns(10) // 최대 연결 수 설정
db.SetMaxIdleConns(10) // 최대 유휴 연결 수 설정
return db
}

CRUD

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// User - 쿼리 결과를 담을 구조체
type User struct {
id uint
name string
}

func main() { // 실행
fmt.Println("db crud")
users := findByAll()
fmt.Println("users", users)
user := findByOne(1)
fmt.Println("user", user)
lastId := save("sayMyName")
update(lastId, "Tom")
delete(lastId)
}

// 여러 행이 있는 select 쿼리의 경우
func findByAll() []User {
conn := getConnection() // 연결 객체
defer conn.Close() // 함수 종료 시 db 연결을 강제 끊는 것으로 연결 객체는 수명이 있고 많은 고루틴에 공유되도록 설계 되어 있다고 하니 굳이 종료를 할 필요는 없는듯..
rows, err := conn.Query("SELECT id, name FROM sample")
if err != nil {
panic(err)
}
defer rows.Close() // 함수 종료 시 닫아서 추가 열거를 방지
users := []User{}
user := User{}
for rows.Next() {
err := rows.Scan(&user.id, &user.name) // 쿼리문에서 가져오는 필드 수와 받는 수가 동일 해야 오류가 안 난다.
if err != nil {
panic(err)
}
if user.id == 1 {
user.name = "delryn"
}
users = append(users, user)
}
err = rows.Err() // 행을 반복하고 나서 오류 한번 더 확인
if err != nil {
panic(err)
}
return users
}

// 단일 행의 select 쿼리의 경우
func findByOne(id uint) User {
conn := getConnection()
defer conn.Close()
user := User{}
err := conn.QueryRow("SELECT id, name FROM sample WHERE id = ?", id).Scan(&user.id, &user.name) // 마찬가지로 필드 수와 받는 필드 수가 동일해야 함
if err != nil {
panic(err)
}
return user
}

// insert 쿼리 - 트랜잭션
func save(name string) int64 {
conn := getConnection()
defer conn.Close()
tx, err := conn.Begin() // 트랜잭션 시작
if err != nil {
tx.Rollback()
panic(err)
}
query := fmt.Sprint("INSERT INTO sample(`name`) VALUES ('", name, "')")
res, err := tx.Exec(query) // 쿼리 실행
if err != nil {
tx.Rollback() // 에러난 경우 롤백
panic(err)
}
lastId, err := res.LastInsertId() // 쓸 일은 없을 꺼 같은데 걍 마지막 insert id 가지고 옴
if err != nil {
tx.Rollback()
panic(err)
}
tx.Commit() // 정상 실행되었으면 커밋
return lastId
}

// update 쿼리의 경우도 동일하게 트랜잭션으로 시작, 실행 함수는 exec로 동일
func update(id int64, name string) {
conn := getConnection()
defer conn.Close()
tx, err := conn.Begin()
if err != nil {
tx.Rollback()
panic(err)
}
query := fmt.Sprint("UPDATE sample SET name = '", name, "' WHERE id = ", id)
_, err = tx.Exec(query)
if err != nil {
tx.Rollback()
panic(err)
} else {
tx.Commit()
}
}

// 삭제 쿼리도 뭐 똑같음...
func delete(id int64) {
conn := getConnection()
defer conn.Close()
tx, err := conn.Begin()
if err != nil {
tx.Rollback()
panic(err)
}
query := fmt.Sprint("DELETE FROM sample WHERE id = ", id)
_, err = tx.Exec(query)
if err != nil {
tx.Rollback()
panic(err)
}
tx.Commit()
}

참조

Prev
2021-03-27 22:27:45
Next