MySQL 本身的相關知識:
http://www.runoob.com/mysql/mysql-transaction.html
https://blog.longwin.com.tw/2006/03/innodb_transaction_2006/
https://xyz.cinc.biz/2013/05/mysql-transaction.html
Golang 操作相關知識:
https://ithelp.ithome.com.tw/articles/10207409
https://segmentfault.com/a/1190000003036452
https://www.jianshu.com/p/bc8120bec94e
http://hopehook.com/2017/08/21/golang_transaction/
https://www.cnblogs.com/hupengcool/p/4143238.html
https://www.kancloud.cn/liupengjie/go/570128
* 事務處理 ( transaction )
tx, err := db.Begin()
...
...
...
tx.Commit()
* tx对象
一般查询使用的是db对象的方法,事务则是使用另外一个对象。sql.Tx对象。使用db的Begin方法可以创建tx对象。tx对象也有数据库交互的Query,Exec和Prepare方法。用法和db的相关用法类似。查询或修改的操作完毕之后,需要调用tx对象的Commit提交或者Rollback方法回滚。
一旦创建了tx对象,事务处理都依赖与tx对象,这个对象会从连接池中取出一个空闲的连接,接下来的sql执行都基于这个连接,直到commit或者rollback调用之后,才会把连接释放到连接池。
在事务处理的时候,不能使用db的查询方法,虽然后者可以获取数据,可是这不属于同一个事务处理,将不会接受commit和rollback的改变,一个简单的事务例子如下:
tx, err := db.Begin()
tx.Exec(query1)
tx.Exec(query2)
tx.Commit()
在tx中使用db是错误的:
tx, err := db.Begin()
db.Exec(query1)
tx.Exec(query2)
tx.commit()
上述代码在调用db的Eexc方法的时候,tx会绑定连接到事务中,db则是额外的一个连接,两者不是同一个事务。需要注意,Begin和Commit方法,与 sql 语句中的 BEGIN 或 COMMIT 语句没有关系。
關於事務的相關細節應該詳閱
https://www.jianshu.com/p/bc8120bec94e
涉及到 Transaction 事务、tx对象、事务与连接、事务并发、实践。
* 如果在rows遍历结束之前退出循环,必须手动关闭Resultset,并且接收error。
for rows.Next() {
// ...
break; // whoops, rows is not closed! memory leak...
}
// do the usual "if err = rows.Err()" [omitted here]...
// it's always safe to [re?]close here:
if err = rows.Close(); err != nil {
// but what should we do if there's an error?
log.Println(err)
}
* 如果id为1的不存在,err为sql.ErrNoRows,一般应用中不存在的情况都需要单独处理。此外,Query返回的错误都会延迟到Scan被调用,所以应该写成如下代码:
var name string
err = db.QueryRow("select name from users where id = ?", 1).Scan(&name)
if err != nil {
if err == sql.ErrNoRows {
// there were no rows, but otherwise no error occurred
// 把空结果当做Error处理是为了强行让程序员处理结果为空的情况
} else {
log.Fatal(err)
}
}
fmt.Println(name)
https://blog.csdn.net/jesseyoung/article/details/40398321
https://studygolang.com/articles/5402
go官方仅提供了database package,database package下有两个包sql,sql/driver。这两个包用来定义操作数据库的接口,这就保证了无论使用哪种数据库,他们的操作方式都是相同的。
但go官方并没有提供连接数据库的driver,如果要操作数据库,还需要第三方的driver 包,最常用的有:
https://github.com/Go-SQL-Driver/MySQL支持database/sql,全部采用go写。
https://github.com/ziutek/mymysql 支持database/sql,也支持自定义的接口,全部采用go写。
推荐使用前者,因为前者的效率更高一点,二者效率的对比可参考benchmark测试结果:https://github.com/go-sql-driver/sql-benchmark
go连接其他主流数据库的驱动介绍可参考:
https://code.google.com/p/go-wiki/wiki/SQLDrivers
user:password@tcp(localhost:5555)/dbname?charset=utf8&autocommit=true
user:password@tcp([de:ad:be:ef::ca:fe]:80)/dbname?charset=utf8mb4
golang 的 包 還不支援 MySQL 8 以上的一個新特性,所以需要如下措施:
https://blog.pilipala.co/articles/2019/02/14/1550128481833
mysql 在 8.0 之后将用户使用的 plugin 更新成 caching_sha2_password。而在之前用的是 mysql_native_password。
在 MySQL 內
use mysql;
select user,host,plugin from user;
可以看到相關資訊
接著利用修改密碼的語法順便將 root 從 caching_sha2_password 改回到 mysql_native_password
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password';
最後需要再將 golang 內的連結語法加上一個參數 &allowNativePasswords=true
user:password@tcp([de:ad:be:ef::ca:fe]:80)/dbname?charset=utf8mb4&allowNativePasswords=true