事务及四大特性

数据库事务确保操作的原子性、一致性、隔离性和持久性。文章讲解了事务的四大特性,以银行转账为例解释其作用,并讨论了MySQL中的事务处理、事务并发读问题及其隔离级别。在JDBC和Spring框架中如何处理事务也进行了说明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

什么是事务

数据库事务(Database Transaction),是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。

简单的说:事务就是将一堆SQL(通常是增删改操作)的执行绑在一起,要么都执行成功,要么都执行失败,即都执行成功才算成功,否则就会恢复到这堆SQL执行之前的状态。

下面以银行转账为例,张三转100块到李四的账户,这至少需要两条SQL语句:

给张三的账户减去100元;
update 账户表 set money=money-100 where name=‘张三’;

给李四的账户加上100元。
update 账户表 set money=money+100 where name=‘李四’;

如果在第一条SQL语句执行成功后,在执行第二条SQL语句之前,程序被中断了(可能是抛出了某个异常,也可能是其他什么原因),那么李四的账户没有加上100元,而张三却减去了100元。这肯定是不行的。

你现在可能已经知道什么是事务了吧!在上面整个转账过程中执行的所有SQL语句会在一个事务中,而事务中的多个操作,要么全都成功,要么全都失败,不可能存在成功一半的情况。

也就是说给张三的账户减去100元如果成功了,那么给李四的账户加上100元的操作也必须是成功的;否则,给张三减去100元以及给李四加上100元都是失败的。

事务的四大特性

事务的四大特性(ACID)是:
**(1)原子性(Atomicity):**原子是最小单元,不能再分割。事务中所有操作是不可再分割的原子单位。事务中所有操作要么全部执行成功,要么全部执行失败。

**(2)一致性(Consistency):**事务执行后,数据库状态与其它业务规则保持一致。如转账业务,无论事务执行成功与否,参与转账的两个账号金额之和应该是不变的。

**(3)隔离性(Isolation):**隔离性是指在并发操作中,不同事务之间应该隔离开来,使每个并发中的事务不会相互干扰。也就是说,在事中务查看数据更新时,数据所处的状态要么是另一事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看到中间状态的数据(但如果有等级,则会看到)。例如:在A事务中,查看另一B事务(正在修改张三的账户金额)中张三的账户金额,要查看到B事务之前的张三的账户金额,要么查看到B事务之后张三的账户金额。事务隔离性分等级。

**(4)持久性(Durability):**一旦事务提交成功,事务中所有的数据操作都必须被持久化到数据库中,即使提交事务后,数据库马上崩溃,在数据库重启时,也必须能保证通过某种机制恢复数据。

MySQL中的事务

在默认情况下,MySQL每执行一条SQL语句,都是一个单独的事务。如果需要在一个事务中包含多条SQL语句,那么需要开启事务和结束事务。

开启事务:start transaction;
结束事务:commit(提交事务)或rollback(回滚事务)。

在执行SQL语句之前,先执行strat transaction,这就开启了一个事务(事务的起点),然后可以去执行多条SQL语句,最后要结束事务,commit表示提交,即事务中的多条SQL语句所做出的影响会持久化到数据库中。或者rollback,表示回滚,即回滚到事务的起点,之前做的所有操作都被撤消了!

事务并发读问题

多个事务对相同的数据同时进行操作,这叫做事务并发。
在事务并发时,如果没有采取必要的隔离措施,可能会导致各种并发问题,破坏数据的完整性等。这些问题中,其中有三类是读问题,分别是:脏读、不可重复读、幻读。

**(1)脏读(dirty read):**读到另一个事务的未提交更新数据,即读取到了脏数据;
例如:A给B转账100元但未提交事务,在B查询后,A做了回滚操作,那么B查询到了A未提交的数据,就称之为脏读。

**(2)不可重复读(unrepeatable read):**读到另一个事务对同一记录的已提交更新数据。对同一记录的两次读取不一致,因为另一事务对该记录做了修改(是针对修改操作)。解决方法:对数据多读几次,得到最新数据结果。
例如:在事务1中,前后两次查询A账户的金额,在两次查询之间,另一事物2对A账户的金额做了修改,此种情况可能会导致事务1中,前后两次查询的结果不一致。这就是不可重复度。

**(3)幻读(虚读)(phantom read):**读到另一个事务对同一记录的已提交更新数据。对同一张表的两次查询不一致,因为另一事务插入了一条记录(是针对插入或删除操作);

注意:mysql默认的是不允许出现脏读和不可重复读,所以在下面演示之前需要设置mysql允许出现脏读、不可重复读等。

set tx_isolation=‘read-uncommitted’;

事务隔离级别

事务隔离级别分四个等级,在相同数据环境下,对数据执行相同的操作,设置不同的隔离级别,可能导致不同的结果。不同事务隔离级别能够解决的数据并发问题的能力也是不同的。

set tx_isolation=‘read-uncommitted’;

1、READ UNCOMMITTED(读未提交数据)
安全级别最低, 可能出现任何事务并发问题(比如脏读、不可以重复读、幻读等)
性能最好(不使用!!)

2、READ COMMITTED(读已提交数据)(Oracle默认)
防止脏读,没有处理不可重复读,也没有处理幻读;
性能比REPEATABLE READ好

3、REPEATABLE READ(可重复读)(MySQL默认)
防止脏读和不可重复读,不能处理幻读问题;
性能比SERIALIZABLE好

4、SERIALIZABLE(串行化)
不会出现任何并发问题,因为它是对同一数据的访问是串行的,非并发访问的;
性能最差;

MySQL的默认隔离级别为REPEATABLE READ,即可以防止脏读和不可重复读。

设置隔离级别

0、MySQL查询当前的事务隔离级别

select @@tx_isolation;

1、MySQL设置事务隔离级别(了解)

(1) set tx_isolation=‘read-uncommitted’; 
安全性最差,容易出现脏读、不可重复读、幻觉读,但性能最高
(2) set tx_isolation=‘read-committed’;
安全性一般,可防止脏读,但容易出现不可重复读、幻觉读
(3) set tx_isolation=‘repeatable-read’;
安全性较好,可防止脏读、不可重复读,但是容易出现幻读
(4) set tx_isolation=‘serialiable’;
安全性最好,可以防止一切事务并发问题,但是性能最差。
一般不需要修改数据库默认的事务隔离级别!

2、JDBC设置事务隔离界别
JDBC中通过Connection提供的方法设置事务隔离级别:

Connection. setTransactionIsolation(int level)

参数可选值如下:

Connection.TRANSACTION_READ_UNCOMMITTED 1(读未提交数据)
Connection.TRANSACTION_READ_COMMITTED 2(读已提交数据)
Connection.TRANSACTION_REPEATABLE_READ 4(可重复读)
Connection.TRANSACTION_SERIALIZABLE 8(串行化)
Connection.TRANSACTION_NONE 0(不使用事务)
提示:在开发中,一般情况下不需要修改事务隔离级别

JDBC对数据库事务处理的支持

JDBC本身就提供了对数据库事务处理的支持,使用java.sql.Connection对象完成事务的提交。使用Connection提交数据库事务处理代码如下。
在这里插入图片描述
Connection类的setAutoCommit方法用于设置JDBC提交SQL语句的方式。设置为ture时,JDBC自动提交SQL语句,JDBC提交SQL语句的方式默认为true。设置为false时,SQL语句的提交由应用程序负责,应用程序必须调用commit方法,同时要在执行SQL语句异常处理块中调用rollback方法,对异常发生前进行的数据库进行回滚操作。
在企业级应用中,事务一般是并发执行的,当事务并发执行时,就会发生数据库数据同步的问题。

在Spring框架中调用事务处理

让Spring框架开始执行一个数据库事务时,需要分成三步走。第一步配置数据源DataSource;第二步声明事务管理TransactionManager类;第三步定义可以执行事务的DAO类。

第一步:配置数据源DataSource
需要让Spring框架知道数据库的位置及其连接方式,这个工作由DataSource完成。Spring框架通过DataSource连接数据库,DataSource既可以在Spring框架的配置文件中配置,也可以放在Bean类中配置。下面是在Spring配置文件中配置数据源的代码。
在这里插入图片描述
配置语句定义了MySQL数据库的URL地址、访问账户及访问密码。

第二步:声明事务管理TransactionManager
Spring 框架提供了PlatformTransactionManager作为事务管理类的顶层接口,声明了初始化事务、提交事务、回滚事务等接口。接口实现由具体的数据库驱动类实现。具体包括DataSourceTransactionManager、HibernateTransactionManager等实现类。本文主要用DataSourceTransactionManager来实现事务的管理。在Spring框架配置文件中配置DataSourceTransactionManager类。
在这里插入图片描述
声明DataSourceTransactionManager类,需要传入之前已声明的DataSource数据源。

第三步:定义可以执行事务的DAO类

DAO提供了应用程序访问数据源必要的接口和方法,接口和方法的具体实现细节,程序并不需要了解。
在这里插入图片描述
CourseTransactio类实现了CourseDao接口,CourseDao是访问mooc数据库的顶层接口,接口提供了mooc数据库表的增删改查操作。CourseTransactio主要实现了CourseDao类的buyCourse,实现学生购买课程事务。购买课程事务涉及到更新teacher表,在student_course表增加一条购买记录,更新student表的余额字段数据库操作,这些操作需要进行连续处理,中间不能中断出错,如果出错则需要做回滚处理。 因此,buyCourse方法采用数据库事务进行处理。

事务处理从TransactionDefinition开始,前面我们谈到了事务的隔离级别,TransactionDefinition就是用来定义事务隔离级别的。DefaultTransactionDefinition表示使用数据库的默认隔离级别,对大部分数据库而言,默认隔离级别是TRANSACTION_READ_COMMITTED。

当TransactionDefinition 创建后,可以通过调用 getTransaction方法开始事务,该方法会返回 TransactionStatus 的一个实例。 TransactionStatus 用于追踪当前的事务状态,如果后面的SQL语句都运行成功,可以使用 TransactionManager 的 commit() 方法来提交这个事务,否则使用 rollback() 方法来回滚整个操作。

完整的配置文件代码。
在这里插入图片描述

学生实体类代码。
在这里插入图片描述
老师实体类代码。
在这里插入图片描述
student表映射到学生实体类。
在这里插入图片描述
teacher表映射到老师实体类。
在这里插入图片描述
测试类代码。
在这里插入图片描述

其他资料:
https://www.cnblogs.com/takumicx/p/9998844.html
https://www.cnblogs.com/jifengblog/p/9240478.html

### 数据库事务的ACID特性详解 #### 原子性 (Atomicity) 原子性指的是数据库事务是一个不可分割的工作单元。这意味着在一个事务中,所有涉及的操作要么全部完成,要么完全不执行。如果事务中的任何一条语句执行失败,则整个事务会被撤销,数据库状态会恢复到事务开始之前的状态[^3]。 ```sql START TRANSACTION; UPDATE accounts SET balance = balance - 100 WHERE account_id = 1; UPDATE accounts SET balance = balance + 100 WHERE account_id = 2; COMMIT; ``` 在这个例子中,如果第一条 `UPDATE` 执行成功,但第二条由于某种原因失败了,那么整个事务将会被回滚,两条更新都不会生效。 --- #### 一致性 (Consistency) 一致性确保事务执行前后,数据库始终处于一致的状态。这种状态不仅指数据本身的完整性约束(如外键、唯一性等),还意味着事务不会破坏系统的规则或逻辑。换句话说,只有那些能够使数据库保持有效状态的事务才能被执行并提交[^3]。 例如,在银行转账过程中,资金总数必须始终保持不变。如果某个账户扣款后未正确转入另一账户,则违反了一致性原则。 --- #### 隔离性 (Isolation) 隔离性保证在并发环境中运行的多个事务互不影响。即使有多个线程同时操作同一份数据,每个事务看到的数据视图应该是独立且完整的。如果没有良好的隔离机制,可能会引发诸如 **脏读**、**不可重复读** 或者 **幻读** 的问题[^1]。 常见的隔离级别包括: - **READ UNCOMMITTED**: 允许读取尚未提交的数据变更。 - **READ COMMITTED**: 只允许读取已提交的数据。 - **REPEATABLE READ**: 确保在同一事务内多次查询相同的结果集。 - **SERIALIZABLE**: 提供最高级别的隔离,强制事务串行化执行。 --- #### 持久性 (Durability) 持久性表示一旦事务成功提交,其对数据库所做的更改将是永久保存下来的,即便发生系统崩溃或其他异常情况也不会丢失这些修改。为了实现这一点,通常会在事务日志中记录每一步操作细节,以便必要时可以重新应用它们[^2]。 ```sql -- 使用二阶段提交协议增强持久性保障 BEGIN DISTRIBUTED TRANSACTION; INSERT INTO orders(order_id, customer_id) VALUES(1, 'cust_001'); INSERT INTO order_details(order_detail_id, product_id, quantity) VALUES(1, 'prod_001', 5); PREPARE TRANSACTION 'trans_order'; COMMIT PREPARED 'trans_order'; ``` 在这里,“准备”阶段将变化写入磁盘上的临时文件;随后,“提交预处理”命令正式确认改动成为最终版本。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值