首先简单介绍一下数据库事务这一概念,事务:对数据库的一系列操作都可以称之为事务,但是与正常的数据库操作(增删改查这类的)的不同的是,事务的操作具有完整性,并且在一个事务的最后,需要一个commit或者rollback来结束一个事务。而在commit之前,之前所有的操作命令其实都没有“真正”意义上的写入数据库中,与之对应的而如果使用了rollback,则这次的事务之前做的所有操作都会撤销,数据库会回滚到事务开始之前的状态。之所以这么做是因为如果对数据库进行一系列的操作时如果中途出错,但是出错前的命令都已经执行了,这时候我们其实是希望这一系列有错误的操作不要执行的,因为很有可能会污染我们的数据库,如果不能回退到操作之前的状态我们就需要手动去恢复数据库,这个代价就太高了。
接下来以一段golang的代码为例子,使用的数据库是mysql,使用的go语言驱动是go-sql-driver(需要注意的是在mysql中只有innoDB引擎建立的数据库和表格才支持事务操作):
func ExcSql(querys []string) error {
db := GetLink()//建立数据库连接,不同数据库有不同实现
tx, err := db.Begin()//打开一个事务并依次执行querys中的所有语句,如果任一语句出错将会回退
if err != nil {
log.Fatal(err)
}
for i := 0; i < len(querys); i++ {
if query[i] == "" {
continue
}
_, _err := tx.Exec(query[i])
if _err != nil {
log.Fatal(_err)
tx.Rollback()
return _err
}
}
tx.Commit()
db.Close()
return err
}
可以看到代码中先打开一个数据库连接,然后开启一个事务tx,在事务中我们依次用tx.Exec执行传入的sql语句,如果某一句出错,我们就回退。看上去是很不错的,但是在实际测试中才发现,并不是所有的sql语句都可以回退的!尤其是和表格相关的,比如:
CREATE TABLE
test_table(
test
INT(10) NULL
);
!#@!¥#@%(故意加的错误语句)
INSERT test_table SET test = 1;
INSERT test_table SET test = 2;
按照事务的理解,当执行到我们故意设置的错误语句时,会报错然后我们的事务会执行回退,所以之前的创建表格操作不会执行,但是实际上并不是这样,”test_table”表格还是会被创建出来。至于原因,就是因为创建表格的操作不支持回退!!!同样的还有修改表格ALERT TABLE这种。
为了进一步查明原因同时排除go-sql-driver驱动的原因,我也尝试在数据库中直接操作,但是得到的结果都是一样的,和table相关的操作均不能回退。所以归根到底,我认为还是因为innoDB引擎本身就不支持的缘故。当然如果有人知道更深层次的原因,也欢迎讨论。