🍁为者常成,行者常至🍁
事务(Transaction)是数据库管理系统中的一个基本概念,它是由一组SQL语句组成的一个逻辑工作单元。事务具有四个基本特性,通常被称为ACID特性:
原子性(Atomicity): 事务是一个原子操作,要么全部执行成功,要么全部执行失败。如果事务中的任何一条语句失败,整个事务将被回滚(撤销),数据库状态将回到事务开始前的状态,不会保留中间状态。
一致性(Consistency): 事务执行前后,数据库从一个一致的状态变为另一个一致的状态。这意味着事务中的操作应满足数据库的约束和规则,以保持数据的完整性。
隔离性(Isolation): 多个事务可以并发执行,但它们应该相互隔离,一个事务的执行不应该影响其他事务。事务隔离性确保了在并发环境中事务之间的数据独立性。
持久性(Durability): 一旦事务成功提交,其对数据库的更改应该是永久性的,即使在系统发生故障或重新启动后也应该保持。持久性确保了事务的变更不会因为系统崩溃而丢失。
在数据库中,事务常常用于处理复杂的业务逻辑,确保数据库操作的原子性和一致性。事务的启动、提交和回滚通常由数据库管理系统提供的SQL语句或API进行控制。
如果没有使用事务,数据库可能会面临一致性和完整性的问题。通过一个简单的例子来说明事务的重要性,例如考虑以下两个步骤的操作,将从账户A向账户B转账100元,在未使用事务的情况:
如果在步骤1和步骤2之间发生了故障(例如,服务器崩溃),则数据库可能处于不一致的状态。账户A的余额已被减少,而账户B的余额尚未增加。这显然是非常不合理的,违反了数据库的一致性原则。
而在使用事务的情况下,使用了事务将步骤1和步骤2包装在一起。如果在步骤1和步骤2之间发生故障,事务将被回滚,数据库将回到事务开始前的状态。这确保了账户A和账户B的操作要么全部成功,要么全部失败,维护了数据库的一致性。
总体而言,使用事务可以确保一系列相关操作的原子性,从而防止数据库在故障或错误发生时出现不一致的状态。这种原子性是事务的一个关键特性,对于保障数据库的一致性非常重要。事务被 MySQL 编写者设计出来,本质就是为了当应用程序访问数据库的时候,事务能够简化我们的编程模型,不需要我们去考虑各种各样的潜在错误和并发问题。可以设想一下当我们使用事务时,要么提交,要么回滚。我们不需要去考虑网络异常,服务器宕机等等问题。因此事务本质上是为了应用层服务的,而不是伴随着数据库系统天生就有的。
事务的提交方式是指在数据库管理系统中,将事务的更改永久应用到数据库的方法。常见的事务提交方式包括显式提交和隐式提交:
显式提交(Explicit Commit):
COMMIT
。示例(使用 SQL):
-- 开始事务
START TRANSACTION;
-- 执行一系列 SQL 操作
-- 提交事务
COMMIT;
隐式提交(Implicit Commit):
示例(使用隐式提交的情况):
-- 开始事务(某些数据库系统中可能不需要显式开始事务)
-- 执行一系列 SQL 操作
-- 事务的提交在语句执行成功后自动发生,或者在连接关闭时发生
需要注意的是,并非所有的数据库系统都支持隐式提交。一些数据库系统(如 MySQL、PostgreSQL)默认使用显式提交方式,而另一些系统(如 Oracle)可能支持隐式提交,但也提供了显式控制的选项。
选择何种提交方式通常取决于应用程序的需求和开发者的偏好。在一些情况下,显式提交可以提供更精确的控制,而在另一些情况下,隐式提交可能更为方便。
事务在数据库中的常见操作方式包括事务的开始、提交和回滚。
开始事务(Start Transaction):
start transaction
或者数据库系统提供的类似命令来开始事务。示例:
start transaction;
在 MySQL 中,
begin
和start transaction
都用于开始一个事务。它们的作用是相同的,可以互换使用。上述两种方式的效果是一样的,它们都用于显式地开始一个事务。在开始事务后,可以执行一系列 SQL 操作,然后通过commit
提交事务,使之生效,或者通过rollback
进行回滚,取消事务中的所有更改。
需要注意的是,默认情况下,MySQL 处于自动提交(autocommit)模式,即每个 SQL 语句都会自动成为一个事务并提交。使用
begin
或start transaction
显式地开启事务后,需要手动进行提交或回滚。如果希望回到自动提交模式,可以使用SET AUTOCOMMIT = 1;
或者SET AUTOCOMMIT = ON;
。
提交事务(Commit Transaction):
commit
命令来提交事务。示例:
commit;
回滚事务(Rollback Transaction):
rollback
命令来回滚事务。示例:
rollback;
注意:一旦事务提交后,将无法再进行回滚。
创建事务保存点(Savepoint):
savepoint savepoint_name;
上述语法中,savepoint_name
是保存点的名称,可以根据需要进行命名。在创建保存点后,可以在事务执行的过程中的任何时刻使用 rollback to savepoint_name;
将事务回滚到指定的保存点,而不影响保存点之前的操作。最终,通过 commit;
提交整个事务。
需要注意的是,不是所有的数据库系统都支持保存点,因此在使用之前请查看具体数据库的文档以确保其支持。
假设有一个表 employees
存储员工信息,包含字段 employee_id
、employee_name
和 salary
。
现在,我们将在一个事务中尝试将 Alice 删除,并在出现错误时回滚事务。
假设有一个表 employees
存储员工信息,包含字段 employee_id
、employee_name
和 salary
。
在开启事务后,假设不小心删除掉所有数据后程序奔溃。
然后再次登录MySQL,查看表中数据。
从结果中可以看到,MySQL自动进行了回滚。
这些事务操作方式在数据库管理系统中是通用的,但具体的语法和支持程度可能因数据库系统而异。在使用事务时,开发者可以根据需要选择适当的操作方式,并确保在事务的范围内处理数据库操作。这有助于维护数据的一致性和可靠性。
事务隔离级别是数据库管理系统中用于控制并发访问的一个重要概念。它定义了一个事务对数据库中的数据所做的更改对其他事务的可见性程度。常见的事务隔离级别包括:
读未提交(Read Uncommitted): 允许一个事务读取另一个事务尚未提交的修改。这是最低的隔离级别,可能导致脏读(读取到未提交的数据)。
读提交(Read Committed): 保证一个事务只能读取到已经提交的其他事务的修改。这避免了脏读,但可能导致不可重复读(同一查询在不同时间点返回不同的结果)。
可重复读(Repeatable Read): 保证在同一事务中的多次查询返回相同的结果,即使其他事务提交了修改。这避免了脏读和不可重复读,但仍可能发生幻读(新增或删除的数据影响查询结果)。
串行化(Serializable): 最高的隔离级别,确保事务之间完全隔离,避免了脏读、不可重复读和幻读。这通常通过锁定数据库的某些部分来实现,但可能影响性能。
选择适当的事务隔离级别取决于应用程序的需求和性能考虑。在一些情况下,较低的隔离级别可能提高性能,但也增加了并发访问时数据不一致的可能性。在需要强一致性和数据完整性的情况下,可以选择较高的隔离级别。
在 MySQL 中,可以使用以下 SQL 语句来查看和设置事务隔离级别:
查看全局事务隔离级别:
show variables like 'tx_isolation';
执行上述 SQL 查询后,将返回一个包含当前全局事务隔离级别的结果集。
请注意,
tx_isolation
是 MySQL 中用于表示事务隔离级别的变量名。查询结果中会显示当前的全局事务隔离级别。如果你使用的是 MySQL 8.0 版本及以上,也可以使用以下 SQL 语句来查看全局事务隔离级别:
sql select @@global.tx_isolation;
查看当前隔离级别:
select @@tx_isolation;
在 MySQL 中,可以使用以下 SQL 语句来设置当前会话的事务隔离级别:
set [session | global] transaction isolation level [read uncommitted | read committed | repeatable read | serializable];
例如,如果你想将当前会话的隔离级别设置为 read committed
,可以执行以下 SQL 语句:
set session transaction isolation level read committed;
注意,这样的设置只会影响当前会话中的事务,并不会修改全局隔离级别。全局隔离级别是数据库服务器的默认隔离级别,通过修改配置文件或全局变量来设置。
如果你希望修改全局隔离级别,需要修改 MySQL 的配置文件,并在配置文件中设置transaction_isolation
参数。修改配置文件后,需要重启 MySQL 服务才能使更改生效。
总体而言,谨慎设置事务隔离级别,根据应用程序的需求和性能要求来调整。
读未提交(Read Uncommitted)是事务隔离级别中的最低级别。在这个级别下,一个事务可以读取另一个事务尚未提交的修改。这意味着在并发执行的多个事务中,一个事务可以看到其他事务正在进行的修改,即使这些修改还没有最终提交。
在 MySQL 中,你可以通过以下 SQL 语句将当前会话的事务隔离级别设置为读未提交:
set session transaction isolation level read uncommitted;
例如当我们有一个表,同时有两个用户在使用,当一个用户在开启事务后对表进行了修改,但是并没有提交事务,另一个用户就可以读取到已经修改过的数据。
注意,读未提交的隔离级别存在脏读(Dirty Read)的风险。脏读指的是一个事务读取了另一个事务未提交的数据,而当另一个事务最终回滚时,读取的数据就成了无效的数据。因此,使用读未提交隔离级别需要慎重考虑,并且在涉及到需要数据一致性和准确性的场景时可能不是最佳选择。
读提交(Read Committed)是数据库事务隔离级别中的一种,它要求一个事务只能读取到已经提交的其他事务的修改。这隔离级别解决了读未提交的脏读问题,但仍可能遇到不可重复读和幻读的情况。在 MySQL 中,可以通过以下 SQL 语句将当前会话的事务隔离级别设置为读提交:
set session transaction isolation level read committed;
如下一个例子,将会话设置为读提交,当其他用户开启事务后,对数据进行修改后没有提交,该会话读取不到别人修改后的数据,只有当其他用户提交事务后才可以查看到。
在读提交隔离级别下,事务只能读取到已经提交的修改,避免了脏读的问题。但仍可能遇到不可重复读和幻读的情况,这需要根据应用程序的需求来权衡选择适当的隔离级别。
可重复读(Repeatable Read)它确保在同一事务中的多次查询返回相同的结果,即使其他事务对数据进行了修改。这级别通过在事务期间创建一个一致的数据视图来实现,避免了不可重复读的问题。在 MySQL 中,可以通过以下 SQL 语句将当前会话的事务隔离级别设置为可重复读:
set session transaction isolation level repeatable read;
例如有两个事务 A 和 B,并且有一张账户表(Account):
事务 A 开始执行,并将用户 UserA 的账户余额减少100元:
-- 事务 A
start transaction;
update Account set balance = balance - 100 where id = 1;
-- 此时,Balance 变为 900
在可重复读隔离级别下,即使事务 A还未提交,事务 B 在同一事务中的查询仍然会看到一致的数据视图:
-- 事务 B
begin;
select * from Account;
-- 此时,Balance 为 1000(尚未提交的修改对事务 B 不可见)
现在,如果事务 A提交:
-- 事务 A 提交
commit;
再次查询的结果仍然是一致的:
-- 事务 B 再次查询
select * from Account;
-- 此时,Balance 为 1000(已经提交的修改对事务 B 仍不可见,因为在可重复读隔离级别下,使用的是之前创建的一致性数据视图)
可重复读隔离级别保证了在同一事务中的多次查询返回相同的结果,但仍可能存在幻读的问题,具体取决于数据库系统的实现。
幻读(Phantom Read)是在事务中可能出现的一种并发现象,其中一个事务在读取一组数据后,另一个事务在相同的条件下插入了新的数据,导致第一个事务再次读取时出现额外的数据行(“幻行”),从而产生了幻读。
串行化(Serializable)是数据库事务隔离级别中的最高级别,它要求事务之间完全隔离,确保不会发生并发冲突,从而避免了脏读、不可重复读和幻读的问题。在串行化隔离级别下,事务按照严格的先后顺序依次执行,不允许并发执行。在 MySQL 中,可以通过以下 SQL 语句将当前会话的事务隔离级别设置为串行化:
set session transaction isolation level serializable;
例如有两个事务 A 和 B,并且有一张账户表(Account):
事务 A 开始执行,并将用户 UserA 的账户余额减少100元:
-- 事务 A
start transaction;
update Account set balance = balance - 100 where id = 1;
-- 此时,Balance 变为 900
在串行化隔离级别下,如果事务 B 尝试执行对同一记录的修改,它会被阻塞,直到事务 A 提交:
-- 事务 B
start transaction;
update Account set balance = balance + 50 where id = 1;
-- 在串行化隔离级别下,事务 B 会被阻塞,直到事务 A 提交
只有在事务 A 提交后,事务 B 才能继续执行。串行化隔离级别确保了事务的严格顺序执行,从而避免了并发冲突的问题。然而,由于串行执行可能导致性能降低,应该谨慎使用,并在确实需要最高隔离级别的情况下选择。
在数据库和事务处理的上下文中,一致性(Consistency)是指事务将数据库从一个一致性状态转移到另一个一致性状态的过程。一致性确保事务操作不会破坏数据库的完整性和业务规则。具体来说,一致性要求事务在执行结束时,数据库必须仍然保持一致的状态,即满足预定义的业务规则和约束。
一致性的目标包括以下方面:
完整性约束: 数据库中定义的各种约束条件必须得到维护,例如唯一性约束、主键约束等。
业务规则: 数据库中的业务规则必须在事务执行完毕后仍然得到满足。
外键关系: 如果数据库中存在外键关系,一致性要求在事务结束时这些外键关系依然成立。
用户定义的规则: 一些业务系统可能有特定的一致性规则,事务执行后必须满足这些规则。
在事务中,一致性是ACID(原子性、一致性、隔离性、持久性)事务特性之一。这意味着即使在并发环境中,多个事务并发执行,它们的最终结果仍然要保持数据库的一致性状态。
一致性是在事务提交时维持的,如果事务执行期间发生了错误或违反了约束,系统应该回滚事务,以保持一致性。一致性的实现通常依赖于数据库管理系统提供的事务隔离级别、约束、触发器等机制。
文章围绕事务展开,对事务的概念以及操作进行介绍。总的来说,事务是数据库管理系统中的一组操作,它们被视为一个不可分割的工作单元,要么全部执行成功,要么全部回滚到初始状态。事务具有四个基本特性,即原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability),通常缩写为ACID。原子性确保事务中的所有操作要么全部成功,要么全部失败回滚;一致性要求事务使数据库从一个一致状态转移到另一个一致状态;隔离性保证并发执行的事务互相不影响,防止出现并发问题;持久性确保事务一旦提交,其影响将永久保存在数据库中。事务的隔离级别包括读未提交、读提交、可重复读和串行化,不同级别在一致性和并发性能之间存在权衡。维护事务的一致性是数据库操作的关键目标,通过锁定、MVCC、事务日志等机制来实现。
而事务的隔离级别越严格,安全性越高,但数据库的并发性能也就越低,往往需要在两者之间找一个平衡点。如下表:
隔离级别 | 特点 |
---|---|
读未提交(Read Uncommitted) | 允许脏读,提高了并发性能,但牺牲了数据的一致性和安全性。 |
读提交(Read Committed) | 避免了脏读,但仍可能发生不可重复读和幻读。提供了一定的一致性,但并发性能相对较高。 |
可重复读(Repeatable Read) | 避免了脏读和不可重复读,但仍可能发生幻读。提供了更高的一致性,但对并发性能的影响较大。 |
串行化(Serializable) | 提供了最高级别的一致性,避免了脏读、不可重复读和幻读,但对并发性能影响最大,可能导致性能下降。 |
最后,码文不易,如果文章对你有帮助的话,就麻烦动动发财的小手点个👍呗😄!感谢支持。