Go语言操作MySQL数据库
MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件。 Go语言MySQL包 使用第三方开源的mysql库: github.com/go-sql-driver/mysql (MySQL驱动) github.com/jmoiron/sqlx (基于MySQL驱动的封装) 通过如下命令,保存下载第三方库: go get github.com/go-sql-driver/mysql go get github.com/jmoiron/sqlx 创建数据库、数据表 在MySQL下创建 oldboy库: mysql> CREATE DATABASE IF NOT EXISTS oldboy DEFAULT CHARSET utf8 COLLATE utf8_general_ci; 在oldboy库中创建student表。 mysql> use oldboy; mysql> CREATE TABLE IF NOT EXISTS `student`( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(100) NOT NULL, `sex` varchar(40) NOT NULL, `age` int(11) DEFAULT NULL, `course` varchar(100) NOT NULL, PRIMARY KEY (`id`) )ENGINE=InnoDB DEFAULT CHARSET=utf8; MySQL连接池 数据库连接使用datebase/sql Open函数进行连接,用户应该通过db.Ping()函数来检查数据库是否实际可用。 package main import ( "fmt" _ "github.com/go-sql-driver/mysql" "github.com/jmoiron/sqlx" ) func main() { //DB, err := sqlx.Open("数据库类型", "用户名:密码@tcp(地址:端口)/数据库名") DB, err := sqlx.Open("mysql", "root:root@tcp(127.0.0.1:3306)/oldboy") if err != nil { fmt.Println("Open mysql failed,", err) } err = DB.Ping() if err != nil { fmt.Println("Ping mysql failed,", err) } else { fmt.Println("MySQL client success") } } 连接池配置 配置连接池有两个的函数: 设置最大数据库连接:使用 db.SetMaxOpenConns(n int) 函数设置打开数据库的最大连接数。包含正在使用的连接和连接池的连接。如果你的函数调用需要申请一个连接,并且连接池已经没有了连接或者连接数达到了最大连接数。此时的函数调用将会被block,直到有可用的连接才会返回。设置这个值可以避免并发太高导致连接mysql出现too many connections的错误。该函数的默认设置是0,表示无限制。 设置最大空闲连接:使用db.SetMaxIdleConns(n int) 函数设置连接池中的保持连接的最大连接数。默认也是0,表示连接池不会保持释放会连接池中的连接的连接状态:即当连接释放回到连接池的时候,连接将会被关闭。这会导致连接再连接池中频繁的关闭和创建。 插入操作 建议使用结构化操作,不推荐使用直接拼接sql语句的方法。 package main import ( "fmt" _ "github.com/go-sql-driver/mysql" "github.com/jmoiron/sqlx" ) type Student struct { Id int `db:"id"` Name string `db:"name"` Sex string `db:"sex"` Age int `db:"age"` Course string `db:"course"` } var Db *sqlx.DB func init() { database, err := sqlx.Open("mysql", "root:root@tcp(127.0.0.1:3306)/oldboy") if err != nil { fmt.Println("open mysql failed,", err) return } Db = database } func main() { r, err := Db.Exec("insert into student(name, sex, age, course)values(?, ?, ?, ?)", "张三", "男", 18, "Golang") if err != nil { fmt.Println("exec failed, ", err) return } id, err := r.LastInsertId() if err != nil { fmt.Println("exec failed, ", err) return } fmt.Println("insert succ:", id) } 查询操作 package main import ( "fmt" _ "github.com/go-sql-driver/mysql" "github.com/jmoiron/sqlx" ) type Student struct { Id int `db:"id"` Name string `db:"name"` Sex string `db:"sex"` Age int `db:"age"` Course string `db:"course"` } var Db *sqlx.DB func init() { database, err := sqlx.Open("mysql", "root:root@tcp(127.0.0.1:3306)/oldboy") if err != nil { fmt.Println("open mysql failed,", err) return } Db = database } func main() { var student []Student err := Db.Select(&student, "select id, name, sex, age, course from student where course=?", "Golang") if err != nil { fmt.Println("exec failed, ", err) return } fmt.Println("select succ:", student) } 修改操作 package main import ( "fmt" _ "github.com/go-sql-driver/mysql" "github.com/jmoiron/sqlx" ) type Student struct { Id int `db:"id"` Name string `db:"name"` Sex string `db:"sex"` Age int `db:"age"` Course string `db:"course"` } var Db *sqlx.DB func init() { database, err := sqlx.Open("mysql", "root:root@tcp(127.0.0.1:3306)/oldboy") if err != nil { fmt.Println("open mysql failed,", err) return } Db = database } func main() { res, err := Db.Exec("update student set name=? where course=?", "李四", "Golang") 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) } 删除操作 package main import ( "fmt" _ "github.com/go-sql-driver/mysql" "github.com/jmoiron/sqlx" ) type Student struct { Id int `db:"id"` Name string `db:"name"` Sex string `db:"sex"` Age int `db:"age"` Course string `db:"course"` } var Db *sqlx.DB func init() { database, err := sqlx.Open("mysql", "root:root@tcp(127.0.0.1:3306)/oldboy") if err != nil { fmt.Println("open mysql failed,", err) return } Db = database } func main() { res, err := Db.Exec("delete from student where name=?", "李四") if err != nil { fmt.Println("exec failed, ", err) return } row, err := res.RowsAffected() if err != nil { fmt.Println("rows failed, ", err) } fmt.Println("delete succ: ", row) } 修改和删除操作都比较简单,同插入数据类似,只是使用RowsAffected来获取影响的数据行数。 MySQL事务 MySQL 事务主要用于处理操作量大,复杂度高的数据。 在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务。 事务处理可以用来维护数据库的完整性,保证成批的 SQL 语句要么全部执行,要么全部不执行。 事务用来管理 insert,update,delete 语句 一般来说,事务是必须满足4个条件(ACID):原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)。 Go语言MySQL事务应用包与函数: 1) import ("github.com/jmoiron/sqlx") 2) conn, err := Db.Begin() 开始事务 3) conn.Commit() 提交事务 4) conn.Rollback() 回滚事务 事务应用 package main import ( "fmt" _ "github.com/go-sql-driver/mysql" "github.com/jmoiron/sqlx" ) type Student struct { Id int `db:"id"` Name string `db:"name"` Sex string `db:"sex"` Age int `db:"age"` Course string `db:"course"` } var Db *sqlx.DB func init() { database, err := sqlx.Open("mysql", "root:root@tcp(127.0.0.1:3306)/oldboy") if err != nil { fmt.Println("open mysql failed,", err) return } Db = database } func main() { conn, err := Db.Begin() if err != nil { fmt.Println("begin failed :", err) return } r, err := Db.Exec("insert into student(name, sex, age, course)values(?, ?, ?, ?)", "王五", "男", 18, "Golang") 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 = Db.Exec("insert into student(name, sex, age, course)values(?, ?, ?, ?)", "赵六", "男", 18, "Linux、Python、Java") 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() } 查看MySQL: mysql> select id,name,sex,age,course from student; +----+--------+-----+------+-----------------------+ | id | name | sex | age | course | +----+--------+-----+------+-----------------------+ | 2 | 王五 | 男 | 18 | Golang | | 3 | 赵六 | 男 | 18 | Linux、Python、Java | +----+--------+-----+------+-----------------------+ 2 rows in set (0.00 sec) Go语言操作mysql除使用 github.com/go-sql-driver/mysql第三方开源的mysql库外还可以使用github.com/jinzhu/gorm包,GORM是使用Go语言开发的友好的ORM库。 安装 go get -u github.com/jinzhu/gorm 通用数据库接口sql.DB 从*gorm.DB连接获取通用数据库接口*sql.DB // 获取通用数据库对象`*sql.DB`以使用其函数 db.DB() // Ping db.DB().Ping() 连接池 db.DB().SetMaxIdleConns(10) db.DB().SetMaxOpenConns(100) 复合主键 将多个字段设置为主键以启用复合主键 type Product struct { ID string `gorm:"primary_key"` LanguageCode string `gorm:"primary_key"` } 日志 Gorm有内置的日志记录器支持,默认情况下,它会打印发生的错误 // 启用Logger,显示详细日志 db.LogMode(true) // 禁用日志记录器,不显示任何日志 db.LogMode(false) // 调试单个操作,显示此操作的详细日志 db.Debug().Where("name = ?", "jinzhu").First(&User{}) 自定义日志 参考GORM的默认记录器如何自定义 https://github.com/jinzhu/gorm/blob/master/logger.go db.SetLogger(gorm.Logger{revel.TRACE}) db.SetLogger(log.New(os.Stdout, " ", 0)) 架构 Gorm使用可链接的API,*gorm.DB是链的桥梁,对于每个链API,它将创建一个新的关系。 db, err := gorm.Open("postgres", "user=gorm dbname=gorm sslmode=disable") // 创建新关系 db = db.Where("name = ?", "jinzhu") // 过滤更多 if SomeCondition { db = db.Where("age = ?", 20) } else { db = db.Where("age = ?", 30) } if YetAnotherCondition { db = db.Where("active = ?", 1) } 当我们开始执行任何操作时,GORM将基于当前的*gorm.DB创建一个新的*gorm.Scope实例 // 执行查询操作 db.First(&user) 并且基于当前操作的类型,它将调用注册的creating,updating,querying,deleting或row_querying回调来运行操作。