学习之前请自行安装 GO语言环境和MySQL数据库环境,编码推荐使用个Goland作为IDE,使用Navicat 作为数据库可视化工具。
1、新建数据库和数据库表
命令行:
mysql -uroot -p //连接数据库,接着需要输入密码
create database mytest; //创建数据库mytest
use mytest; //切换到新数据库
执行成功后,如图所示:
创建表:user
CREATE TABLE `user` (
`user_id` int(10) NOT NULL AUTO_INCREMENT,
`username` varchar(20) DEFAULT NULL,
`sex` varchar(20) DEFAULT NULL,
`email` varchar(20) DEFAULT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
执行成功后,如图所示,同时使用Navicat工具查看:
2、GO语言中MySQL驱动安装
分别执行如下命令行:
go get github.com/go-sql-driver/mysql
go get github.com/jmoiron/sqlx
下载完成后会在GO环境的GOPATH路径生成对应的文件。
注:请预先安装git,再执行以上命令,下载过程中可能很慢,会出现下载失败的问题,耐心等待一会,出现错误后多试两次。
3、测试连接MySQL
_"http://github.com/go-sql-driver/mysql" 这行不能省略,这是MySQL的驱动包,重点是加个下划线 _ ,用来初始化驱动。
数据库的连接信息,自己输入自己正确的信息,依次为
用户名:用户密码@tcp(127.0.0.1:3306)/数据库名
package main
import (
"fmt"
_ "github.com/go-sql-driver/mysql"
"github.com/jmoiron/sqlx"
)
func main() {
database, err := sqlx.Open("mysql", "root:******@tcp(127.0.0.1:3306)/mytest")
if err != nil {
fmt.Println("open mysql failed,", err)
return
}
fmt.Println(database)
}
以上代码,如果连接成功后打印数据连接的指针,如图所示:
4、操作数据库,基本的CRUD
(1)插入:插入一条用户信息
package main
import (
"fmt"
_ "github.com/go-sql-driver/mysql"
"github.com/jmoiron/sqlx"
)
//用户结构体type Users struct {
UserId int `db:"user_id"`
Username string `db:"username"`
Sex string `db:"sex"`
Email string `db:"email"`
}
//数据库指针var db *sqlx.DB
//初始化数据库连接,init()方法系统会在动在main方法之前执行。func init() {
database, err := sqlx.Open("mysql", "root:q1454739828@tcp(127.0.0.1:3306)/mytest")
if err != nil {
fmt.Println("open mysql failed,", err)
}
db = database
}
func main() {
sql := "insert into user(username,sex, email)values (?,?,?)"
value := [3]string{"user01", "man", "user01@163.com"}
//执行SQL语句r, err := db.Exec(sql, value[0], value[1], value[2])
if err != nil {
fmt.Println("exec failed,", err)
return
}
//查询最后一天用户ID,判断是否插入成功id, err := r.LastInsertId()
if err != nil {
fmt.Println("exec failed,", err)
return
}
fmt.Println("insert succ", id)
}
插入成功后,打印出一个编号。同时查看Navicat,确认插入成功。
(2)查询:查询user_id为2的用户信息
func main() {
var users []Users
sql := "select user_id, username,sex,email from user where user_id=? "
err := db.Select(&users, sql, 2)
if err != nil {
fmt.Println("exec failed, ", err)
return
}
fmt.Println("select succ:", users)
}
查询成功如果所示:
(3)更新:把user_id为2的用户的username修改为 "user002"
func main() {
//执行SQL语句sql := "update user set username =? where user_id = ?"
res, err := db.Exec(sql, "user002", 2)
if err != nil {
fmt.Println("exec failed,", err)
return
}
//查询影响的行数,判断修改插入成功row, err := res.RowsAffected()
if err != nil {
fmt.Println("rows failed", err)
}
fmt.Println("update succ:", row)
}
查询Navicat,确认修改成功:
(4)删除:删除user_id 为2的用户信息
func main() {
sql := "delete from user where user_id=?"
res, err := db.Exec(sql, 2)
if err != nil {
fmt.Println("exce failed,", err)
return
}
row, err := res.RowsAffected()
if err != nil {
fmt.Println("row failed, ", err)
}
fmt.Println("delete succ: ", row)
}
确认删除成功:
5、MySQL的事务
(1)基本概念
MySQL 事务主要用于处理操作量大,复杂度高的数据。比如说,在人员管理系统中,你删除一个人员,你既需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这样,这些数据库操作语句就构成一个事务!在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务。
事务处理可以用来维护数据库的完整性,保证成批的 SQL 语句要么全部执行,要么全部不执行。
事务用来管理 insert,update,delete 语句
一般来说,事务是必须满足4个条件(ACID)::原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)。原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
(2)基本操作Db.Begin() 开始事务
Db.Commit() 提交事务
Db.Rollback() 回滚事务
(3)代码
开启事务后,获取到conn,使用conn进行两个插入操作,分别插入两个用户的信息,在每一个可能出现异常的地方,进行回滚。之后执行conn.Commit()提交事务,此时插入操作才真正执行。
func main() {
//开启事务conn, err := db.Begin()
if err != nil {
fmt.Println("begin failed :", err)
return
}
//执行插入语句r, err := conn.Exec("insert into user(username, sex, email)values(?, ?, ?)", "user01", "man", "usre01@163.com")
if err != nil {
fmt.Println("exec failed, ", err)
conn.Rollback() //出现异常,进行回滚操作return
}
id, err := r.LastInsertId()
if err != nil {
fmt.Println("exec failed, ", err)
conn.Rollback()
return
}
fmt.Println("insert succ:", id)
r, err = conn.Exec("insert into user(username, sex, email)values(?, ?, ?)", "user02", "man", "user02@163.com")
if err != nil {
fmt.Println("exec failed, ", err)
conn.Rollback()
return
}
id, err = r.LastInsertId()
if err != nil {
fmt.Println("exec failed, ", err)
conn.Rollback()
return
}
fmt.Println("insert succ:", id)
conn.Commit()
}
执行正确:
先手动删除插入的两个记录,然后把第二个sql语句故意改错,查看事务是否真正管用。
把正确的属性名username改完错误的username2,然后运行代码。
r, err = conn.Exec("insert into user(username2, sex, email)values(?, ?, ?)", "user02", "man", "user02@163.com")
结果发现,事务确实开启,出现一个错误,插入直接回滚,一条都没有插入成功。
总结:
Go语言操作MySQL比较容易,和其他语言没有太大区别,就是过多的error处理很影响代码的美观性,真正使用的时候可以把error封装为对应的方法,如下代码所示。
func HandleError(err error, why string) {
if err != nil {
fmt.Println(why, err)
}
}