💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
# 使用 Perl 进行 SQLite 事务 > 原文: [http://zetcode.com/db/sqliteperltutorial/trans/](http://zetcode.com/db/sqliteperltutorial/trans/) 在本章中,我们将处理事务。 首先,我们提供一些基本定义。 然后,我们介绍 Perl 脚本,该脚本显示如何在 Perl DBI 中处理事务。 我们还将讨论自动提交模式,这对于理解事务是必不可少的。 ## 定义 事务是针对一个或多个数据库中数据的数据库操作的基本单位。 事务中所有 SQL 语句的影响可以全部提交给数据库,也可以全部回滚。 在自动提交模式中,更改立即生效。 要处理事务,我们要么关闭自动提交模式,要么使用`begin_work()`方法启动事务。 事务以`commit()`或`rollback()`方法结束。 默认情况下,数据库连接处于自动提交模式。 `AutoCommit`数据库句柄属性用于设置或读取自动提交模式。 当`AutoCommit`打开时,对`begin_work()`的调用将`AutoCommit`关闭。 `commit()`和`rollback()`方法重新打开`AutoCommit`。 如果关闭`AutoCommit`属性,然后再调用`begin_work()`方法,则会收到一条错误消息,提示我们已经在事务中。 在 SQLite 中,除`SELECT`以外的任何命令都将启动隐式事务。 同样,在事务中,诸如`CREATE TABLE` ...,`VACUUM`和`PRAGMA`之类的命令将在执行之前提交先前的更改。 手动事务以`BEGIN TRANSACTION`语句开始,并以`COMMIT`或`ROLLBACK`语句结束。 SQLite 支持三种非标准事务级别:`DEFERRED`,`IMMEDIATE`和`EXCLUSIVE`。 ## 例子 现在,我们将有一些可用于事务处理的脚本。 ```perl #!/usr/bin/perl use strict; use DBI; my $dbh = DBI->connect( "dbi:SQLite:dbname=test.db", "", "", { RaiseError => 1, AutoCommit => 0 }, ) or die $DBI::errstr; $dbh->do("DROP TABLE IF EXISTS Friends"); $dbh->do("CREATE TABLE Friends(Id INTEGER PRIMARY KEY, Name TEXT)"); $dbh->do("INSERT INTO Friends(Name) VALUES ('Tom')"); $dbh->do("INSERT INTO Friends(Name) VALUES ('Rebecca')"); $dbh->do("INSERT INTO Friends(Name) VALUES ('Jim')"); $dbh->do("INSERT INTO Friends(Name) VALUES ('Robert')"); $dbh->do("INSERT INTO Friends(Name) VALUES ('Julian')"); $dbh->disconnect(); ``` 我们创建一个`Friends`表,并尝试用数据填充它。 但是,正如我们将看到的,数据不会被提交。 ```perl { RaiseError => 1, AutoCommit => 0 }, ``` 我们已经将`AutoCommit`参数设置为 0。更改不会自动提交。 而且没有提交语句。 因此,更改不会写入数据库。 ```perl $ ./noautocommit.pl $ sqlite3 test.db SQLite version 3.7.7 2011-06-23 19:49:22 Enter ".help" for instructions Enter SQL statements terminated with a ";" sqlite> .tables Cars Images ``` 我们的数据库中没有`Friends`表。 在第二个示例中,我们将使用`commit()`方法将数据写入数据库。 ```perl #!/usr/bin/perl use strict; use DBI; my $dbh = DBI->connect( "dbi:SQLite:dbname=test.db", "", "", { RaiseError => 1, AutoCommit => 0}, ) or die $DBI::errstr; $dbh->do("DROP TABLE IF EXISTS Friends"); $dbh->do("CREATE TABLE Friends(Id INTEGER PRIMARY KEY, Name TEXT)"); $dbh->do("INSERT INTO Friends(Name) VALUES ('Tom')"); $dbh->do("INSERT INTO Friends(Name) VALUES ('Rebecca')"); $dbh->do("INSERT INTO Friends(Name) VALUES ('Jim')"); $dbh->do("INSERT INTO Friends(Name) VALUES ('Robert')"); $dbh->do("INSERT INTO Friends(Name) VALUES ('Julian')"); $dbh->commit(); $dbh->disconnect(); ``` 当关闭自动提交模式时,每个语句都在事务内,直到我们调用`commit()`方法为止。 ```perl $dbh->commit(); ``` 所有更改都将写入数据库。 ```perl sqlite> SELECT * FROM Friends; 1|Tom 2|Rebecca 3|Jim 4|Robert 5|Julian ``` 我们使用`sqlite3`命令行工具验证是否已写入更改。 当事务中存在错误时,将回滚事务,并且不会将任何更改提交到数据库。 ```perl #!/usr/bin/perl use strict; use DBI; my $dbh = DBI->connect( "dbi:SQLite:dbname=test.db", "", "", { RaiseError => 1, AutoCommit => 0}, ) or die $DBI::errstr; $dbh->do("UPDATE Friends SET Name='Thomas' WHERE Id=1"); $dbh->do("UPDATE Friend SET Name='Bob' WHERE Id=4"); $dbh->commit(); $dbh->disconnect(); ``` 在代码示例中,自动提交已关闭。 有两个语句构成一个事务。 第二个 SQL 语句中有错误。 因此,该事务将回滚。 ```perl $dbh->do("UPDATE Friend SET Name='Bob' WHERE Id=4"); ``` 表名称不正确。 数据库中没有`Friend`表。 ```perl $ ./rollingback.pl DBD::SQLite::db do failed: no such table: Friend at ./rollingback.pl line 15. DBD::SQLite::db do failed: no such table: Friend at ./rollingback.pl line 15. Issuing rollback() due to DESTROY without explicit disconnect() of DBD::SQLite::db handle dbname=test.db at ./rollingback.pl line 15. ``` 运行示例将显示此错误消息。 事务回滚。 ```perl $ sqlite3 test.db SQLite version 3.7.7 2011-06-23 19:49:22 Enter ".help" for instructions Enter SQL statements terminated with a ";" sqlite> SELECT * FROM Friends; 1|Tom 2|Rebecca 3|Jim 4|Robert 5|Julian sqlite> ``` 即使第一个`UPDATE`语句正确,在`Friends`表中也没有发生任何变化。 正如我们在教程中已经提到的那样,默认模式是自动提交。 在这种模式下,我们可以使用`begin_work()`方法开始新的事务,并使用`commit()`或`rollback()`完成它。 `begin_work()`方法将关闭自动提交,`commit()`和`rollback()`方法将重新打开自动提交。 ```perl #!/usr/bin/perl use strict; use DBI; my $dbh = DBI->connect( "dbi:SQLite:dbname=test.db", "", "", { RaiseError => 1, HandleError=>\&handle_error }, ) or die $DBI::errstr; $dbh->begin_work(); $dbh->do("UPDATE Friends SET Name='Thomas' WHERE Id=1"); $dbh->do("UPDATE Friend SET Name='Bob' WHERE Id=4"); $dbh->commit(); $dbh->do("INSERT INTO Friends(Name) VALUES('Ronald')"); $dbh->disconnect(); sub handle_error { my $error = shift; print "An error occurred in the script\n"; print "Message: $error\n"; return 1; } ``` 再次,我们有一个不正确的第二条 SQL 语句。 这次,我们没有明确关闭自动提交。 ```perl { RaiseError => 1, HandleError=>\&handle_error }, ``` 我们将把错误处理委托给`handle_error()`子例程。 ```perl $dbh->begin_work(); ``` 使用`begin_work()`方法,我们开始一个新事务。 自动提交已关闭。 ```perl $dbh->do("UPDATE Friends SET Name='Thomas' WHERE Id=1"); $dbh->do("UPDATE Friend SET Name='Bob' WHERE Id=4"); ``` 这两个语句构成一个事务。 第二个是不正确的。 ```perl sub handle_error { my $error = shift; print "An error occurred in the script\n"; print "Message: $error\n"; return 1; } ``` 当我们遇到错误时,将调用此子例程。 我们打印一条错误消息。 请注意,该脚本不会退出。 ```perl $dbh->do("INSERT INTO Friends(Name) VALUES('Ronald')"); ``` 事务已回滚,我们没有退出脚本。 它继续。 回滚后,自动提交已重新打开。 在`Friends`表中添加了新行。 ```perl $ ./rollingback2.pl An error occurred in the script Message: DBD::SQLite::db do failed: no such table: Friend ``` 我们可以从`the handle_error()`子例程中看到我们的自定义错误消息。 ```perl sqlite> SELECT * FROM Friends; 1|Thomas 2|Rebecca 3|Jim 4|Robert 5|Julian 6|Ronald ``` 一个新朋友被插入了表。 在 SQLite Perl 教程的这一部分中,我们处理了事务。