来自 数据库 2019-09-27 11:00 的文章
当前位置: 澳门三合彩票 > 数据库 > 正文

默认情况下如果执行一个事务中出现错误,事务

Use TestDB

Begin TransAction
    Insert Into Person(PersonId,PersonName)
                Values('1','Name1')
    Insert Into Person(PersonId,PersonName)
                Values('1','Name1')
    Insert Into Person(PersonId,PersonName)
                Values('3','Name3')
Commit TransAction
/*
    Select 一下 有'1','Name1'和'3','Name3',
    说明只有第二句的错误被取消了
*/

 

政工并发

对于sql.Tx对象,因为事情进度唯有三个三番五次,事务内的操作都以各种试行的,在开班下叁个数据库交互以前,必须先实现上三个数据库交互。举个例子上面包车型大巴例子:

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

调用了Query方法之后,在Next方法中取结果的时候,rows是尊崇了三个接二连三,再次调用QueryRow的时候,db会再从连接池收取二个新的一连。rows和db的连天两个能够存活,何况互相不影响。

可是,那样逻辑在事务管理中校会失灵:

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

tx实践了Query方法后,连接转移到rows上,在Next方法中,tx.QueryRow将尝试得到该连接进行数据库操作。因为还尚无调用rows.Close,由此底层的连年属于busy状态,tx是力不能够支再开展询问的。上面包车型地铁事例看起来有一点点傻,究竟涉及这样的操作,使用query的join语句就会逃脱这些主题材料。例子只是为了表明tx的接纳难题。

末段要小心的是:固然一个作业写了 Begin TransAction 而没写 Commit TransAction 或 Rollback TransAction 则相关操作的数量(只怕是表,恐怕是列,这自个儿还没测量试验。。。)会被锁住。。。而对此锁住的消除办法便是独立施行一下Commit TransAction 或 Rollback TransAction

澳门三合彩票 1;)

思想政治工作与连接

创办Tx对象的时候,会从连接池中抽出连接,然后调用相关的Exec方法的时候,连接如故会绑定在改事务管理中。在事实上的事务管理中,go恐怕创制分歧的连续,可是这一个别的连接都不属于该事情。举个例子地方例子中db创制的连年和tx的总是就不是二次事。

工作的连年生命周期从Beigin函数调用起,直到Commit和Rollback函数的调用截止。事务也提供了prepare语句的应用办法,可是须要接纳Tx.Stmt方法创立。prepare设计的当初的愿景是频仍实施,对于事情,有希望须要频仍实施同二个sql。但是无论常常的prepare和事务管理,prepare对于连日来的管制都有一些小复杂。由此私以为尽量幸免在事情中运用prepare形式。举例下边例子就便于造成错误:

tx, _ := db.Begin()defer tx.Rollback()stmt, _ tx.Prepare("INSERT ...")defer stmt.Close()tx.Commit()

因为stmt.Close使用defer语句,即函数退出的时候再清理stmt,可是实在推行进程的时候,tx.Commit就已经释放了延续。当函数退出的时候,再进行stmt.Close的时候,连接也是有被应用了。

Use TestDB
Begin Try
    Begin TransAction
        Insert Into Person(PersonId,PersonName)
                    Values('1','Name1')
        Insert Into Person(PersonId,PersonName)
                    Values('1','Name1')
        Insert Into Person(PersonId,PersonName)
                    Values('3','Name3')
    Commit TransAction
End Try
Begin Catch
    Rollback TransAction
End Catch
/*
    使用TryCatch来捕获异常。
    如果 TRY 块内生成的错误导致当前事务的状态失效,
    则将该事务归类为不可提交的事务。
    如果通常在 TRY 块外中止事务的错误在 TRY 内发生时,
    就会导致事务进入不可提交状态。
    不可提交的事务只能执行读操作或 ROLLBACK TRANSACTION。
    该事务不能执行任何可能生成写操作或 COMMIT TRANSACTION 的 Transact-SQL 语句。
    如果事务被分类为不可提交的事务,则 XACT_STATE 函数会返回值 -1。
*/

 

总结

database/sql提供了事务管理的职能。通过Tx对象完结。db.Begin会创造tx对象,后面一个的Exec和Query实践职业的数据库操作,最终在tx的Commit和Rollback中做到数据库事务的交付和回滚,同时释放连接。

tx事务意况中,唯有三个数据库连接,事务内的Eexc都是各类实践的,事务中也足以运用db实行询问,可是db查询的进度会新建连接,那个再而三的操作不属于该职业。

至于database/sql和mysql的驱动,我们已经分三部分情节介绍了。下一节,将会对后面的剧情开展梳理计算,包含错误管理和注意事项的补充。

USE [TestDB]
GO
/****** 对象:  Table [dbo].[Person]    脚本日期: 11/23/2008 13:37:48 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Person](
    [PersonId] [nchar](18) NOT NULL,
    [PersonName] [nchar](20) NOT NULL,
 CONSTRAINT [PK_Person] PRIMARY KEY CLUSTERED 
(
    [PersonId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

澳门三合彩票 2;)

事务管理是数量的重大特征。尤其是对此某个支出系统,事务保障性对作业逻辑会有主要影响。golang的mysql驱动也卷入好了政工相关的操作。大家已经学习了db的Query和Exec方法管理查询和改换数据库。

Use TestDB
SET XACT_ABORT ON -- 打开
Begin TransAction
    Insert Into Person(PersonId,PersonName)
                Values('1','Name1')
    Insert Into Person(PersonId,PersonName)
                Values('1','Name1')
    Insert Into Person(PersonId,PersonName)
                Values('3','Name3')
Commit TransAction
/*
    当 SET XACT_ABORT 为 ON 时,
    如果执行 Transact-SQL 语句产生运行时错误,
    则整个事务将终止并回滚。 
    默认情况下它是OFF状态。
*/

总体回滚方法3:自定义错误变量

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.Exectx.Exectx.commit()

在tx中利用db是不对的:

tx, err := db.Begin()db.Exectx.Exectx.commit()

上述代码在调用db的Eexc方法的时候,tx会绑定连接到事情中,db则是特别的三个连连,两个不是同贰个业务。必要小心,Begin和Commit方法,与sql语句中的BEGIN或COMMIT语句未有关联。

私下认可情状下一旦进行贰个作业中现身错误,则只回滚错误操作语句(就是说那句不进行了,算不上回滚),错误处此前或现在的准确操作语句如故会被交付。如:

全部回滚的办法1:展开 XACT_澳门三合彩票,ABORT

实践

前方对作业解释了一群,说了那么多,其实还不比share的code。上边就事情的应用做简单的介绍。因为事情是单个连接,由此任何事务管理进度的产出了老大,都急需使用rollback,一方面是为了保险数据完整一致性,另一方面是释放职业绑定的连日。

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

大家定义了贰个clearTransaction函数,该函数会施行rollback操作。因为大家事务管理进程中,任何叁个荒谬都会招致main函数退出,由此在main函数退出实践defer的rollback操作,回滚事务和释放连接。

假诺不加多defer,只在结尾Commit后check错误err后再rollback,那么当doSomething爆发十分的时候,函数就淡出了,此时还未有执行到tx.Commit。那样就招致业务的接二连三未有休憩,事务也不曾回滚。

Use TestDB
Declare @tranError int -- 定义变量
Set @tranError=0
    Begin TransAction
        Insert Into Person(PersonId,PersonName)
                    Values('1','Name1')
            Set @tranError = @tranError + @@Error
        Insert Into Person(PersonId,PersonName)
                    Values('1','Name1')
            Set @tranError = @tranError + @@Error
        Insert Into Person(PersonId,PersonName)
                    Values('3','Name3')
            Set @tranError = @tranError + @@Error
    If @tranError = 0
        Commit TransAction
    Else
        Rollback TransAction
/*
    自定义一个变量来判断最后是否发生过错误。
*/

澳门三合彩票 3;)

一体回滚方法2:使用Try...Catch

 

漫天回滚方法3:自定义错误变量

 

全部回滚的点子1:展开 XACT_ABORT

整个回滚方法2:使用Try...Catch

本文由澳门三合彩票发布于数据库,转载请注明出处:默认情况下如果执行一个事务中出现错误,事务

关键词: