# Gin(五):连接MySQL 之前我们完成了注册,接下来要完成登录功能,但是有个问题,我们的数据没有持久化,无法得知有哪些用户注册了,这样就无法在登录时进行校验。 所以接下来我们要将数据持久化,也就是存储到数据库中,这里使用 `MySQL` # 建立数据库 首先我们要新建一个库,用来存放项目数据,建立一个名为 `ginhello` 的库。 ```mysql create database ginhello; ``` 当我们建立好数据库时,就可以通过 `Goland`进行数据库连接和使用。 选择 `Goland` 右侧的 `Database`,,点击 + 号,选择 `MySQL`。填写相关信息,账户名,密码,要连接的数据库库名等信息,进行连接。 之后我们就可以通过 `Goland` 的图形化界面去新建立表。 右键选择刚刚连接的 `ginhello` ,`new` , `table` 然后填写字段名称和属性。下面给出建表语句。 ```mysql create table user( id int auto_increment primary key, email varchar(30) not null, password varchar(40) not null ) comment '用户表'; ``` # 连接数据库 数据库的表已经建立成功,那么省下来就该与我们的 Gin 建立联系,通过代码连接到数据库。 新建文件夹 `initDB` 新建 `initDB.go`。 ```go package initDB import ( "database/sql" _ "github.com/go-sql-driver/mysql" "log" ) var Db *sql.DB func init() { var err error Db, err = sql.Open("mysql", "root:1234@tcp(127.0.0.1:3306)/ginhello") if err != nil { log.Panicln("err:", err.Error()) } Db.SetMaxOpenConns(10) Db.SetMaxIdleConns(10) } ``` 首先新建一个全局变量`sql.DB`方便我们后期调用,然后通过 `sql.Open`对数据进行连接。`SetMaxOpenConns` 是对 最大链接数的设置 `SetMaxIdleConns` 是设置最大空闲链接数 经过简单的设置,我们的程序就可以连接到数据库。 # 增加用户 当数据库连接上时,就可以完善我们的注册功能。 修改 `userModel.go` 对 `user` 添加新的方法。 ```go func (user *UserModel) Save() int64 { result, e := initDB.Db.Exec("insert into ginhello.user (email, password) values (?,?);", user.Email, user.Password) if e != nil { log.Panicln("user insert error", e.Error()) } id, err := result.LastInsertId(); if err != nil { log.Panicln("user insert id error", err.Error()) } return id } ``` 该方法是对 `user` 类型进行添加的方法,最后返回一个新增行id > **小提示** 在编写 `SQL` 语句时,通过`ctrl+enter` 快捷键组合,选择 `Edit Mysql Fragment` ,会在编辑器下方重写打开一个编辑界面用来写SQL,并且带有自动提示,提示内容和我们链接的数据库相关。 最后修改 `UserRegister` 方法,当数据校验合格的时候进行存储。 ```go func UserRegister(context *gin.Context) { var user model.UserModel if err := context.ShouldBind(&user); err != nil { context.String(http.StatusBadRequest, "输入的数据不合法") log.Panicln("err ->", err.Error()) } id := user.Save() log.Println("id is ", id) context.Redirect(http.StatusMovedPermanently, "/") } ``` 当都写完的时候就可以运行我们的测试 `TestUserPostForm` 和 `TestUserPostFormEmailErrorAndPasswordError` 两个测试用例。 测试可以正常通过,此时检测我们的数据库。打开 `User` 表,里面只会有一条信息。 此时我们的注册也就完成了。 # 登录 接下来快速完成登录功能。 具体的前端代码请看 [Github](https://github.com/youngxhui/GinHello/tree/gin_db/templates)下面贴出来具体的后端代码 我们要根据 `Email` 和 `Password` 校验用户数据是否正确。 `userModel.go` 根据 `Email` 查询代码,该文件其他代码也有略微变化,请注意查看。 ```go func (user *UserModel) QueryByEmail() UserModel { u := UserModel{} row := initDB.Db.QueryRow("select * from user where email = ?;", user.Email) e := row.Scan(&u.Id, &u.Email, &u.Password) if e != nil { log.Panicln(e) } return u } ``` 通过对比页面上传入的密码和数据库中的密码是否一致来确定用户是否可以登录。 `userHandler.go` ```go func UserLogin(context *gin.Context) { var user model.UserModel if e := context.Bind(&user); e != nil { log.Panicln("login 绑定错误", e.Error()) } u := user.QueryByEmail() if u.Password == user.Password { log.Println("登录成功", u.Email) context.HTML(http.StatusOK, "index.tmpl", gin.H{ "email": u.Email, }) } } ``` 每当一个功能编写完成的时候,切记要写上单元测试,这将会帮助我们在日后的项目中更加完善。 用户登录测试。 # 总结 本节通过链接数据库,完成了数据库的增加和查询功能,并且完成了注册和登录的相关功能。