import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
"time"
)

func InitDB() *sql.DB {
dsn := fmt.Sprintf("%s:%s@(%s)/%s?charset=%s&parseTime=true&loc=Local",
"root", "123456", "127.0.0.1:3306", "gintest", "utf8")

if conn, err := sql.Open("mysql", dsn); err != nil {
panic(err.Error())
} else {
conn.SetConnMaxLifetime(7 * time.Second) //設置空閑時間,這個是比mysql 主動斷開的時候短
conn.SetMaxOpenConns(10)
conn.SetMaxIdleConns(10)
return conn
}
}

sql.Open 方法開始連接數據庫,第一個參數為所要連接的數據庫類型。第二個參數為dsn,可以理解為連接數據庫的參數信息。

這里在連接以后,又對連接進行了三個設置。

conn.SetConnMaxLifetime 為設置連接的空閑時間,為什么要設置這個參數以及該設置多少是有講究的。

有的MySQL服務器為了性能考慮,會設置主動斷開空閑連接的,默認8個小時,但是一般的dba不會設置那么長,很有可能會設置10秒或者更短,所以這個參數要設置的更短,這個參數可以登錄MySQL 服務器執行show global variables like '%timeout%'; 來查看,有個wait_timeout 值,這里的值要設置比這個值更短。

conn.SetMaxOpenConns(10) 和conn.SetMaxOpenConns(10) 這兩個方法會初始化一個連接池,保證池子里會有足夠的連接,這個值要設置多少需要根據應用的并發情況。

但是SetMaxIdleConns 的值不要小于SetMaxOpenConns 設置的值,否則會導致頻繁的創建連接。

官方的解釋為

db.SetMaxIdleConns() is recommended to be set same to db.SetMaxOpenConns(). When it is smaller than SetMaxOpenConns(), connections can be opened and closed much more frequently than you expect

這里還有個需要注意的是,在import 時,有個_ "github.com/go-sql-driver/mysql" 這行代碼不能缺,該代碼會執行一下init方法,初始化一些變量,如果沒有這行的話,會由于一些變量未被初始化而panic.

一般情況下,我們會將數據庫連接對象放到一個全局的變量中,然后將不同的數據庫操作封裝到dao中。

在項目目錄下再創建一個global目錄,再創建一個global.go文件, 在該文件中定義一些需要全局使用的變量.

package global

import "database/sql"

var (
Mysql *sql.DB
)

之后在main.go中進行mysql變量的初始化

package main

import (
"github.com/gin-gonic/gin"
"yyxtest/db"
"yyxtest/global"
"yyxtest/handlers"
)

func main() {
r := gin.Default()
global.Mysql = db.InitDB()
userv1_h := handlers.UserV1{}
userv1 := r.Group("/user/v1")
{
userv1.GET("/check", userv1_h.CheckUsers)
}
r.Run(":8080")
}

global.Mysql = db.InitDB() 這行代碼為初始化全局的Mysql 對象, 之后我們創建一個dao文件夾,再創建一個userdao.go文件,這里封裝數據庫的查詢. 先寫一個查詢所有記錄的函數。

事先準備一個表,并插入幾條數據

idnameage
1楊彥星18
2飯團兒1
3aaa100
4bbb22
5ccc19
635
746

數據查詢

在userdao.go中寫入以下代碼,

package dao

import "yyxtest/global"

type user struct {
ID int json:"id" Name string json:"name" Age int json:"age" } func GetAllUsers() []user { rows, err :=global.Mysql.Query("select * from user_infos") if err != nil{ return nil } var persons = make([]user, 0) for rows.Next() { var a user err := rows.Scan(&a.ID, &a.Name, &a.Age) if err != nil { return nil } persons = append(persons, a) } return persons }

GetAllUsers 函數執行select * from user_infos, 并且將該查詢結果返回[]user 的結構體, 接下來再編寫路由處理類, userv1_h.CheckUsers

在handler 文件夾中再創建一個userv1.go

package handlers

import (
"github.com/gin-gonic/gin"
"yyxtest/dao"
)

type UserV1 struct {}

func (UserV1) CheckUsers(c *gin.Context) {
users := dao.GetAllUsers()
if users == nil{
c.JSON(200, gin.H{"error": 1, "msg": "查詢失敗"})
}
c.JSON(200, gin.H{"error":0, "msg":"查詢成功", "users": users})
}

運行服務,如果沒有什么意外的話將可以正常的請求到數據

SQL注入的問題

如果在進行數據庫的查詢時,沒有對用戶的輸入進校驗,而是完全的進行字符串拼接,將會導致SQL注入的問題發生,如以下的代碼

func GetUser(name string) (user, error)  {
sqlstr := fmt.Sprintf("select * from user_infos where name='%s'", name) row := global.Mysql.QueryRow(sqlstr) var u user err := row.Scan(&u.ID, &u.Name, &u.Age) if err != nil { return user{}, err } return u, nil }

sqlstr 直接進行字符串拼接將會導致注入問題。

正確的做法應該是使用點位符

插入數據

插入數據也比較簡單,使用Exec函數 ,在userdao.go中寫入以下代碼

func InsertUser(name string, age int) error  {
exec, err := global.Mysql.Exec("INSERT into user_infos(name, age) values (?,?)", name, age)
if err != nil {
return err
}
_, err = exec.LastInsertId()
if err != nil {
return err
}
return nil
}

在處理類中寫入以下代碼

func (UserV1) AddUser(c *gin.Context)  {
name := c.Query("name")
age := c.Query("age")
age_i, err:=strconv.Atoi(age)
if err!=nil{
c.JSON(200, gin.H{"error": 1, "msg": "age 參數不正確"})
}else{
err = dao.InsertUser(name, age_i)
if err!= nil{
c.JSON(200, gin.H{"error": 2, "msg": err.Error()})
}else{
c.JSON(200, gin.H{"error": 1, "msg": "插入成功"})
}
}

}

MySQL的初步使用還是比較簡單的,只是在初始化的時候定義好相應的對象,但是MySQL是個博大精深的數據庫,入門很簡單,但是想要深入還是需要很多的內功修煉的,之后再深入一些事務相關的查詢。

文章轉自微信公眾號@序語程言

上一篇:

在 .NET 和 Python 中創建了相同的 API — 哪個性能更好

下一篇:

使用FastAPI與aiohttp進行SSE響應開發
#你可能也喜歡這些API文章!

我們有何不同?

API服務商零注冊

多API并行試用

數據驅動選型,提升決策效率

查看全部API→
??

熱門場景實測,選對API

#AI文本生成大模型API

對比大模型API的內容創意新穎性、情感共鳴力、商業轉化潛力

25個渠道
一鍵對比試用API 限時免費

#AI深度推理大模型API

對比大模型API的邏輯推理準確性、分析深度、可視化建議合理性

10個渠道
一鍵對比試用API 限時免費