Go 语言的 database/sql
包提供了连接 sql 数据库或类 sql 数据库的泛用接口,但并不提供具体的数据库驱动程序,在使用它时,必须注入至少一个数据库驱动程序。
通过 MysqL -u root -p
命令进入数据库cmd,然后创建一个 go_MysqL 数据库:
CREATE DATABASE go_MysqL;
进入该数据库: USE go_MysqL;
创建 user 表:
CREATE table `user` { `uID` BIGINT(20) NOT NulL auto_INCREMENT, `name` VARCHAR(20) DEFAulT '', `phone` VARCHAR(20) DEFAulT '', PRIMARY KEY(`uID`)}ENGINE=InnoDB auto_INCREMENT=1 DEFAulT CHARSET=utf8mb4;
2. 下载 MysqL 的驱动程序$ go get -u github.com/go-sql-driver/MysqL
3. 使用 MysqL 驱动程序直接导入依赖包就可以了:
import ( "database/sql" _ "github.com/go-sql-driver/MysqL")
在以上语句中,github.com/go-sql-driver/MysqL
就是依赖包。因为没有直接使用该包中的对象,所以在导入包前面被架上了下划线。
database/sql
包中提供了 open()
函数用来连接数据库,其定义如下:
func Open(drivername, dataSourcename string) (*DB, error)
连接示例:
package mainimport ( "database/sql" _ "github.com/go-sql-driver/MysqL" "log")func main() { db, err := sql.Open("MysqL", "<user>:<password>@tcp(127.0.0.1:3306)/hello") if err != nil { log.Fatal(err) } defer db.Close()}
4. 初始化连接在用 open()
函数建立连接后,如果要检查数据源的名称是否合法,则可以调用 Ping
方法。 返回的 DB 对象可以安全地被多个 goroutine 同时使用,并且它会维护自身的闲置连接池。这样 Open 函数只需调用一次,因为一般启动后很少关闭 DB 对象。用 Open 函数初始化连接的示例代码如下:
package mainimport ( "database/sql" "fmt" _ "github.com/go-sql-driver/MysqL")var db *sql.DB// 定义一个初始化数据库的函数func initDB() (err error) { //连接数据库 db, err = sql.Open("MysqL", "root:a123456@tcp(127.0.0.1:3306)/go_MysqL") if err != nil { return err } // 尝试与数据库建立连接(校验dsn是否正确) err = db.Ping() if err != nil { return err } return nil}func main() { err := initDB() // 调用输出化数据库的函数 if err != nil { fmt.Printf("init db Failed,err:%v\n", err) return }}
其中,sql.DB
是一个数据库的 *** 作句柄,代表一个具有零到多个底层连接的连接池。它可以安全地被多个 goroutine同时使用。 database/sql
包会自动创建和释放连接,也会维护一个闲置连接的连接池。
首先定义一个结构体用来存储数据库返回的数据:
type User struct { UID int name string Phone string}
有两种查询方式:
queryRow()
进行单行查询query()
进行多行查询单行查询示例:
// 单行测试func queryRow() { var u User // 非常重要:确保queryRow之后调用Scan方法,否则持有的数据库链接不会被释放 err := db.queryRow("select uID,name,phone from `user` where uID=?", 1).Scan(&u.UID, &u.name, &u.Phone) if err != nil { fmt.Printf("scan Failed, err:%v\n", err) return } fmt.Printf("uID:%d name:%s phone:%s\n", u.UID, u.name, u.Phone)}
多行查询示例:
// 查询多条数据示例func querymultirow() { var u User rows, err := db.query("select uID,name,phone from `user` where uID > ?", 0) if err != nil { fmt.Printf("query Failed, err:%v\n", err) return } // 关闭rows释放持有的数据库链接 defer rows.Close() // 循环读取结果集中的数据 for rows.Next() { err := rows.Scan(&u.UID, &u.name, &u.Phone) if err != nil { fmt.Printf("scan Failed, err:%v\n", err) return } fmt.Printf("uID:%d name:%s phone:%s\n", u.UID, u.name, u.Phone) }}
(2)插、改、删使用 Exec()
方法
要了解预处理,需要首先了解普通@R_404_5967@的执行过程:
客户端对@R_404_5967@进行占位符替换,得到完整的@R_404_5967@;客户端发送完整的@R_404_5967@到 MysqL 服务器端;MysqL服务器端执行完整的@R_404_5967@,并将结果返给客户端。预处理的执行过程把@R_404_5967@分成两部分——命令部分与数据部分;把命令部分发送给 MysqL 服务器端, MysqL 服务器端进行sql预处理;把数据部分发送给 MysqL 服务器端, MysqL 服务器端对@R_404_5967@进行占位符替换;MysqL 服务器端执行完整的 sql 语句,并将结果返回给客户端为什么要预处理?预处理用于优化 MysqL 服务器重复执行 sql 语句的问题,可以提升服务器性能。提前让服务器编译,一次编译多次执行,可以节省后续编译的成本,避免sql注入问题。
Go 语言中 MysqL 的预处理在Go语言中, Prepare()
方法会将@R_404_5967@发送给 MysqL服务器端,返回一个准备好的状 态用于之后的查询和命令。返回值可以同时执行多个查询和命令。 Prepare()
方法的定义如下:
func (db *DB) Prepare(query string) (*Stmt, error)
预处理的示例代码:
// 预处理查询示例func preparequery() { stmt, err := db.Prepare("select uID,name,phone from `user` where uID > ?") if err != nil { fmt.Printf("prepare Failed, err:%v\n", err) return } defer stmt.Close() rows, err := stmt.query(0) if err != nil { fmt.Printf("query Failed, err:%v\n", err) return } defer rows.Close() // 循环读取结果集中的数据 var user User for rows.Next() { err := rows.Scan(&u.UID, &u.name, &u.Phone) if err != nil { fmt.Printf("scan Failed, err:%v\n", err) return } fmt.Printf("uID:%d name:%s phone:%s\n", u.UID, u.name, u.Phone) }}
用 Go 实现 MysqL 事务1. 什么是事务事务是一个最小的不可再分的工作单元。通常一个事务对应一个完整的业务(例如银行账户 转账业务,该业务就是一个最小的工作单元),同时这个完整的业务需要执行多次 DML ( INSERT、 UPDATE、 DELETE等)语句,共同联合完成。 例如,A转账给B,就需要执行两次 UPDATE *** 作。在 MysqL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务。 事务处理用来维护数据库的完整性,保证成批的@R_404_5967@要么全部执行,要么全部不执行。
2. 事务的 ACID 属性通常事务必须满足4个条件(ACID):原子性(Atomicity,或称不可分割性)、一致性 ( Consistency)、隔离性( Isolation,又称独立性)、持久性( Durability)事务的 ACID 属性。
3. 事务的相关方法Go 语言使用以下三个方法来实现 MysqL 中的事务 *** 作:
Begin()
方法用于开始事务:
func (db *DB) Begin() (*Tx, error)
Commit()
方法用于提交事务:
func (tx *Tx) Commit() error
Rollback()
方法用于回滚事务:
func (tx *Tx) Rollback() error
以下代码演示了一个简单的事务 *** 作,该事务 *** 作能够确保两次更新 *** 作要么同时成功,要么同时失败,不会有中间状态:
func transaction() { tx, err := db.Begin() // 开启事务 if err != nil { if tx != nil { tx.Rollback() // 回滚 } fmt.Printf("begin trans Failed, err:%v\n", err) return } _, err = tx.Exec("update user set username='james' where uID=?", 1) if err != nil { tx.Rollback() // 回滚 fmt.Printf("exec sql1 Failed, err:%v\n", err) return } _, err = tx.Exec("update user set username='james' where uID=?", 3) if err != nil { tx.Rollback() // 回滚 fmt.Printf("exec sql2 Failed, err:%v\n", err) return } err = tx.Commit() // 提交事务 if err != nil { tx.Rollback() // 回滚 fmt.Printf("commit Failed, err:%v\n", err) return } fmt.Println("exec transaction success!")}
sql 注入与防御在编写 sql 脚本时,尽量不要自己拼接 sql 语句。
针对sql注入问题,常见的防御措施有:
禁止将变量直接写入@R_404_5967@。对用户进行分级管理,严格控制用户的权限。对用户输入进行检查,确保数据输入的安全性。在具体检查输入或提交的变量时,对单引 号、双引号、冒号等字符进行转换或者过滤。对数据库信息进行加密。 总结以上是内存溢出为你收集整理的【Go】用 Go 访问 MySQL全部内容,希望文章能够帮你解决【Go】用 Go 访问 MySQL所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)