무지개곰
article thumbnail

Go 언어로 웹 서버를 생성하면 데이터를 저장하여야 하는 경우가 생깁니다. 이러한 경우 DB를 생성하여 데이터를 관리할 수 있습니다. 이번 시간에 Go로 작성된 웹 서버에서 mysql에 CRUD작업을 하는 방법을 기록하겠습니다.

예시 코드는 아래의 github 주소에 올려두었습니다.

https://github.com/rainbow96bear/golang_practice/blob/master/mysql_practice/mysql_practice.go

목차

기본 설정

Create

Read

Update

Delete


기본 설정

Go에서 mysql을 사용하기 위하여 'database/sql', 'github.com/go-sql-driver/mysql' 두 가지 패키지가 필요로 합니다.

'database/sql'은 기본 패키지이지만 'github.com/go-sql-driver/mysql'은 외부 패키지이므로 아래의 명령어를 통하여 받아줍니다.

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

패키지가 받아졌다면 import 해줍니다.


db연결

코드는 사람에 따라 다른 방식으로 작성할 수 있습니다. 저는 공부를 하며 파일 하나에 정리하기 위하여 아래와 같이 작성하였습니다.

var db *sql.DB

func main(){
	port := 8080
	var err error
	db, err = sql.Open("mysql", "root:1q2w3e4r!@tcp(localhost:3333)/Books")
	if err != nil {
		fmt.Println("DB 열기 실패 :", err)
	}
	defer db.Close()

	router := pat.New()

	router.Get("/Books", GetList)
	router.Post("/Books", CreateData)
	router.Put("/Books", UpdateData)
	router.Delete("/Books", DeleteData)
	fmt.Println(port, "포트 서버 생성")
	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), router))
}

mysql과 연결하기 위하여 'sql.Open()'을 사용하였습니다.

매개변수로 'mysql'과 'root:1q2w3e4r!@tcp(localhost:3333)/Books'를 주었습니다.

첫 번째 매개변수는 driver name으로 mysql을 사용한다는 것을 알려줍니다.

두 번째 매개변수는 사용할 계정의 ID, 비밀번호, 통신규약, 주소, 사용할 DataBase이름입니다.

저의 코드는 'root 계정을 사용하고 비밀번호는 1q2w3e4r!이며 tcp를 이용하여 localhost:3333과 통신하고 Books라는 Database를 사용한다'는 의미입니다.


Database와 table

이번 예시에서 사용하는 Database와 table의 구조입니다.

여러 개의 Database 중 저는 Books라는 Database를 사용하겠습니다. 

 

Create

mysql과 연결 설정이 위에서 마무리되었기에 데이터를 저장하는 Create 작업을 작성합니다.

func CreateData(w http.ResponseWriter, r *http.Request){
	var bookInfo BookInfo
	decoder := json.NewDecoder(r.Body)
	if err := decoder.Decode(&bookInfo); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	queryParams := r.URL.Query()
	bookInfo.Kind = queryParams.Get("kind")

	query := "INSERT INTO books (kind, title, author) VALUES (?, ?, ?)"
	_, execErr := db.Exec(query, bookInfo.Kind, bookInfo.Title, bookInfo.Author)
	if execErr != nil {
		http.Error(w, execErr.Error(), http.StatusInternalServerError)
		return
	}

	res := responseMsg{Status : http.StatusOK, Msg: "저장 완료"}
	responseJSON, err := json.Marshal(res)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write(responseJSON)
}

'POST 방식'으로 'JSON'으로 책에 대한 정보를 전달하고 'Query String'으로 책의 종류를 전달하였습니다. 

 

postman을 이용하여 json을 전달하였고 아래와 같은 응답을 받았습니다.

postman POST 요청과 응답

잘 저장된 것이 맞는지 mysql에서 'select * from books'를 사용하여 확인하였고 아래와 같이 저장된 것을 확인할 수 있었습니다.

저장된 결과


Read

Create를 하였다면 저장된 정보를 받아올 수 있어야 합니다. 데이터를 불러오는 Read 작업을 작성합니다.

func GetList(w http.ResponseWriter, r *http.Request){
	queryParams := r.URL.Query()
	kind := queryParams.Get("kind")

	query := "SELECT * FROM books WHERE kind = ?"
	rows, queryErr := db.Query(query, kind)
	if queryErr != nil {
		http.Error(w, queryErr.Error(), http.StatusInternalServerError)
		return
	}
	defer rows.Close()

	var data []BookInfo
	for rows.Next() {
		var d BookInfo
		if err := rows.Scan(&d.ID, &d.Kind, &d.Title, &d.Author); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		data = append(data, d)
	}

	w.Header().Set("Content-Type", "application/json")
	if err := json.NewEncoder(w).Encode(data); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

Create와는 다르게 'GET 방식'을 사용하였고 'Query String'으로 전달받은 kind 값을 가지는 데이터를 모두 받아옵니다.

 

postman을 이용하여 요청을 보내었고 아래와 같은 응답을 받았습니다.

postman GET 요청과 응답


Update

저장된 데이터를 수정하여야 하는 경우가 발생할 수 있습니다. 데이터를 수정하는 Update 작업을 작성합니다.

func UpdateData(w http.ResponseWriter, r *http.Request){
	var bookInfo BookInfo
	decoder := json.NewDecoder(r.Body)
	if err := decoder.Decode(&bookInfo); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	
	queryParams := r.URL.Query()
	bookInfo.ID, _ = strconv.Atoi(queryParams.Get("id"))
	bookInfo.Kind = queryParams.Get("kind")

	query := "UPDATE books SET kind = ?, title = ?, author = ? WHERE id = ?"
	_, execErr := db.Exec(query, bookInfo.Kind, bookInfo.Title, bookInfo.Author, bookInfo.ID)
	if execErr != nil {
		http.Error(w, execErr.Error(), http.StatusInternalServerError)
		return
	}

	res := responseMsg{Status : http.StatusOK, Msg: "수정 완료"}
	responseJSON, err := json.Marshal(res)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write(responseJSON)
}

Update의 경우 RESTful 방식인 'PUT 방식'을 사용하였고, 'JSON'을 통하여 수정할 내용을,  'Query String'을 사용하여 책의 종류와 DB에 저장된 정보의 id를 전달하였습니다.

 

postman을 이용하여 요청을 보내었고 아래와 같은 응답을 받았습니다.

postman PUT 요청과 응답

잘 수정된 것이 맞는지 mysql에서 'select * from books'를 용하여 확인하였고 아래와 같이 저장된 것을 확인할 수 있었습니다.

수정된 결과


Delete

필요가 없어진 데이터의 경우 삭제할 수 있어야 합니다. 데이터를 삭제하는 Delete 작업을 작성합니다.

func DeleteData(w http.ResponseWriter, r *http.Request){
	queryParams := r.URL.Query()
	id := queryParams.Get("id")

	query := "DELETE FROM books WHERE id = ?"
	_, execErr := db.Exec(query, id)
	if execErr != nil {
		http.Error(w, execErr.Error(), http.StatusInternalServerError)
		return
	}

	res := responseMsg{Status : http.StatusOK, Msg: "삭제 완료"}
	responseJSON, err := json.Marshal(res)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write(responseJSON)
}

Delete의 경우 RESTful 방식인 'DELETE 방식'을 사용하였고, 저장된 데이터를 구별할 수 있는 고유 값인 ID를 'Query String'을 통하여 전달하였습니다.

 

postman을 이용하여 요청을 보내었고 아래와 같은 응답을 받았습니다.

postman DELETE 요청과 응답

값이 잘 삭제되었는지 mysql에서 'select * from books'를 사용하여 확인하였고, 아래와 같이 삭제된 것을 확인할 수 있었습니다.

삭제된 결과

profile

무지개곰

@무지개곰

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!