事务是数据库的一个非常重要的特性,尤其对于银行,支付系统,等等。
database/sql提供了事务处理的功能。通过Tx对象实现。db.Begin会创建tx对象,后者的Exec和Query执行事务的数据库操作,最后在tx的Commit和Rollback中完成数据库事务的提交和回滚,同时释放连接。

tx对象

我们在之前查询以及操作数据库都是用的db对象,而事务则是使用另外一个对象.
使用db.Begin 方法可以创建tx对象,tx对象也可以对数据库交互的Query,Exec方法
用法和我们之前操作基本一样,但是需要在查询或者操作完毕之后执行tx对象的Commit提交或者Rollback方法回滚。

一旦创建了tx对象,事务处理都依赖于tx对象,这个对象会从连接池中取出一个空闲的连接,接下来的sql执行都基于这个连接,知道commit或者Roolback调用之后,才会把这个连接释放到连接池。

在事务处理的时候,不能使用db的查询方法,当然你如果使用也能执行语句成功,但是这和你事务里执行的操作将不是一个事务,将不会接受commit和rollback的改变,如下面操作时:

tx,err := Db.Begin()
Db.Exec()
tx.Exec()
tx.Commit()

上面这个伪代码中,调用Db.Exec方法的时候,和tx执行Exec方法时候是不同的,只有tx的会绑定到事务中,db则是额外的一个连接,两者不是同一个事务。

事务与连接

创建Tx对象的时候,会从连接池中取出连接,然后调用相关的Exec方法的时候,连接仍然会绑定在该事务处理中。
事务的连接生命周期从Beigin函数调用起,直到Commit和Rollback函数的调用结束。

事务并发

对于sql.Tx对象,因为事务过程只有一个连接,事务内的操作都是顺序执行的,在开始下一个数据库交互之前,必须先完成上一个数据库交互。

rows, _ := db.Query("SELECT id FROM user")
for rows.Next() {
var mid, did int
rows.Scan(&mid)
db.QueryRow("SELECT id FROM detail_user WHERE master = ?", mid).Scan(&did) }

调用了Query方法之后,在Next方法中取结果的时候,rows是维护了一个连接,再次调用QueryRow的时候,db会再从连接池取出一个新的连接。rows和db的连接两者可以并存,并且相互不影响。

但是如果逻辑在事务处理中会失效,如下代码:

rows, _ := tx.Query("SELECT id FROM user")
for rows.Next() {
var mid, did int
rows.Scan(&mid)
tx.QueryRow("SELECT id FROM detail_user WHERE master = ?", mid).Scan(&did)
}

tx执行了Query方法后,连接转移到rows上,在Next方法中,tx.QueryRow将尝试获取该连接进行数据库操作。因为还没有调用rows.Close,因此底层的连接属于busy状态,tx是无法再进行查询的。

完整的小结

通过下面一个完整的例子就行更好的理解:

func doSomething(){
panic("A Panic Running Error")
} func clearTransaction(tx *sql.Tx){
err := tx.Rollback()
if err != sql.ErrTxDone && err != nil{
log.Fatalln(err)
}
} func main() {
db, err := sql.Open("mysql", "root:@tcp(127.0.0.1:3306)/test?parseTime=true")
if err != nil {
log.Fatalln(err)
} defer db.Close() tx, err := db.Begin()
if err != nil {
log.Fatalln(err)
}
defer clearTransaction(tx) rs, err := tx.Exec("UPDATE user SET gold=50 WHERE real_name='vanyarpy'")
if err != nil {
log.Fatalln(err)
}
rowAffected, err := rs.RowsAffected()
if err != nil {
log.Fatalln(err)
}
fmt.Println(rowAffected) rs, err = tx.Exec("UPDATE user SET gold=150 WHERE real_name='noldorpy'")
if err != nil {
log.Fatalln(err)
}
rowAffected, err = rs.RowsAffected()
if err != nil {
log.Fatalln(err)
}
fmt.Println(rowAffected) doSomething() if err := tx.Commit(); err != nil {
// tx.Rollback() 此时处理错误,会忽略doSomthing的异常
log.Fatalln(err)
} }

这里定义了一个clearTransaction(tx)函数,该函数会执行rollback操作。因为我们事务处理过程中,任何一个错误都会导致main函数退出,因此在main函数退出执行defer的rollback操作,回滚事务和释放连接。

如果不添加defer,只在最后Commit后check错误err后再rollback,那么当doSomething发生异常的时候,函数就退出了,此时还没有执行到tx.Commit。这样就导致事务的连接没有关闭,事务也没有回滚。

tx事务环境中,只有一个数据库连接,事务内的Eexc都是依次执行的,事务中也可以使用db进行查询,但是db查询的过程会新建连接,这个连接的操作不属于该事务。

Go基础之--操作Mysql(三)的更多相关文章

  1. Go语言基础之操作MySQL

    Go语言操作MySQL MySQL是常用的关系型数据库,本文介绍了Go语言如何操作MySQL数据库. Go操作MySQL 连接 Go语言中的database/sql包提供了保证SQL或类SQL数据库的 ...

  2. Go基础之--操作Mysql(一)

    关于标准库database/sql database/sql是golang的标准库之一,它提供了一系列接口方法,用于访问关系数据库.它并不会提供数据库特有的方法,那些特有的方法交给数据库驱动去实现. ...

  3. Go基础之--操作Mysql(二)

    在上一篇文章中主要整理了Golang连接mysql以及一些基本的操作,并进行了大概介绍,这篇文章对增删查改进行详细的整理 读取数据 在上一篇文章中整理查询数据的时候,使用了Query的方法查询,其实d ...

  4. python 操作 mysql基础补充

    前言 本篇的主要内容为整理mysql的基础内容,分享的同时方便日后查阅,同时结合python的学习整理python操作mysql的方法以及python的ORM. 一.数据库初探 在开始mysql之前先 ...

  5. Mysql的二进制安装和基础入门操作

    前言:Mysql数据库,知识非常的多,要想学精学通这块知识,估计也要花费和学linux一样的精力和时间.小编也是只会些毛皮,给大家分享一下~ 一.MySQL安装 (1)安装方式: 1 .程序包yum安 ...

  6. Mysql数据库的二进制安装和基础入门操作

    前言:Mysql数据库,知识非常的多,要想学精学通这块知识,估计也要花费和学linux一样的精力和时间.小编也是只会些毛皮,给大家分享一下~ 一.MySQL安装 (1)安装方式: 1 .程序包yum安 ...

  7. php最全基础,数组,函数,超全局变量,时间,回话,文件,php操作mysql

    共享一份学习php最全基础语法知识的笔记 原文链接:http://www.cnblogs.com/oscn/p/3607757.html:略有修改   http://www.cnblogs.com/l ...

  8. python接口自动化(三十八)-python操作mysql数据库(详解)

    简介 现在的招聘要求对QA人员的要求越来越高,测试的一些基础知识就不必说了,来说测试知识以外的,会不会一门或者多门开发与语言,能不能读懂代码,会不会Linux,会不会搭建测试系统,会不会常用的数据库, ...

  9. MySQL数据库的二进制安装、源码编译和基础入门操作

    一.MySQL安装 (1)安装方式: 1 .程序包yum安装 优点:安装快,简单 缺点:定死了各个文件的地方,需要修改里边的相关配置文件,很麻烦 2 .二进制格式的程序包:展开至特定路径,并经过简单配 ...

随机推荐

  1. BZOJ 4078: [Wf2014]Metal Processing Plant [放弃了]

    以后再也不做$World Final$的题了................ 还我下午 bzoj上TLE一次后就不敢交了然后去uva交 Claris太神了代码完全看不懂 还有一个代码uva上竟然WA了 ...

  2. 关于http与https之间的区别

    年前的时候进行了一家公司的电话面试两轮,视频面试一轮(已拿到offer),过程中遇到了一个关于http与https的问题,当时回答的并不好,今天将其进行了总结和整理,望读者喜欢: 前言 谷歌在2018 ...

  3. 10位时间戳转为C#格式时间

    /// <summary> /// 10位时间戳转为C#格式时间 /// </summary> /// <param name=”timeStamp”></p ...

  4. Redis 学习(一) —— 安装、通用key操作命令

    一.Redis介绍 1.介绍 通常,在系统中,我们会把数据交由数据库来存储,但传统的数据库增删查改的性能较差,且比较复杂.根据 80/20 法则,百分之八十的业务访问集中在百分之二十的数据上.是否可以 ...

  5. PyCharm安装及使用

    搭建环境 1.win10_X64,其他Win版本也可以. 2.PyCharm版本:Professional-2016.2.3. 搭建准备 1.到PyCharm官网下载PyCharm安装包.   Dow ...

  6. [Swift]UIKit学习之警告框:UIAlertController和UIAlertView

    Important: UIAlertView is deprecated in iOS 8. (Note that UIAlertViewDelegate is also deprecated.) T ...

  7. elasticsearch2.3.3安装

    本文来自我的github pages博客http://galengao.github.io/ 即www.gaohuirong.cn 摘要: 作者原来搭建的环境是0.95版本 现在升级到2.3.3版本, ...

  8. 阿里云Aliyun_server

    一.云概念 云主机是基于云计算平台的一种虚拟的主机服务器产品 云服务器(99.999%安全性,扩展性) 特点: 1.资源分配配置灵活,安全性能强. 2.优于VPS和独立服务器产品.通俗的理解: 云主机 ...

  9. ASP.NET根据当前时间获取,本周,本月,本季度等时间段

    DateTime dt = DateTime.Now; //当前时间 DateTime startWeek = dt.AddDays(1 - Convert.ToInt32(dt.DayOfWeek. ...

  10. Ecshop中transport和jquery不兼容的解决方案

    1.修改文件:/js/transport.js,在最底部增加代码 if (Object.prototype.toJSONString){ var oldToJSONString = Object.to ...