0


MySQL学习(六)事务的ACID特性及使用

1.事务的概念及特性

1.1 概念

(1)事务:指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部失败

ps:感觉就是字面意思,一件事

(2)事务的产生:尤其应用在诸如类似银行的业务上,比如A转账1000元钱给B,当A账户余额减少1000后,突然发生了故障,如服务器断开的情况,致使B的账户余额并未来得及增加1000,这并不是我们期望的结果,故而就有了事务的产生。

如果A账户余额增加的动作,和B账户余额减少的动作被定义为一个事务,那么,这两个动作,要么都成功,要么都失败。比如刚刚提到的,突然网中断未来得及执行第二个动作,那么最终结果是两个动作都不执行

所谓事务,就是属于完成同一事务的操作,要么全部执行,要么都不执行

(3)事务的四大特性——ACID

1.2 Atomic——原子性

业务动作(即事务)不可再分,业务动作对应的多条SQL语句看作一个整体,这几条语句要么都执行成功,要么都不执行,不存在某几句执行某几句不执行的情况

1.3 Consistency——一致性

事务的一致性是我们的最终目的,我们期望事务内相关联的数据始终保持一致性,而这一点,纯靠DBMS并不能完全实现,需要编程人员和JDBC共同实现

1.4 Isolation——隔离性

(1)概念

特指多用户场景下,并发控制的内容

当同时多个用户(JDBC中的Connection)操作同一批数据时,我们希望这些操作是相互隔离的,即互不影响,怎么做呢,只能通过破坏同时性,在极小的时间差内,让各个Connection排队解决(用户之间几乎感觉不到)

(2)不同的隔离级别

也就是说,要追求真正的隔离性,是以牺牲并发性为代价的。

据此,在纠结于隔离性和并发性之间,SQL标准制定了隔离级别

1)可串行化——serializable ,完全的追求隔离性,事务之间必须排队进行,严格保证了数据的正确性,同时,性能最差

2)快照读——snapshot read,消除了幻读,实则还并未在SQL标准中,所以mysql中的可重复读近似于快照读

3)可重复读——repeated read,保证了在一次事务中,只要我还未提交,我看到的某个数据就一直是这个数据,即使同时发生的事务B已经修改了该数据,而我这边是感受不到的

缺点:只能对表中已有数据进行保护,而对新插入进来的数据无法保证其可重复读,故而可能导致幻读(什么是幻读呢,幻读就是好像读到了个假数据)。

比如,事务A内容为将表中所有数据的年龄属性都更改为1,然后从查询返回所有数的查询结果,同时进行的事务B内容为插入一条新数据,当B提交后,A查询返回所有数的结果,其他数据的年龄都是1,而新插入的数据是一条例外数据,其年龄属性并没有更改为1,这就叫幻读

4)读已提交——read commited,能读到已经提交了的数据

缺点:不可重复读,就是说,在同一事务中,我多次读取同一个数据,可能读到的数据是不一样的,是被改动过了的

5)读未提交——read uncommited,追求并发性,性能好。但是我和你两个事务同时发生,即使你那边的数据还未提交,我这边也可以读到,相当于读到了脏数据

小小结:

1.5 durability——持久性

操作一旦提交,是不可逆的,是确确实实操作了的

1.6 ACID关系小结

2.事务的使用

2.1 Workbench客户端直接使用

start transaction; -- 事务的开始
-- 借书,先在book表中更新书籍数量,再在借阅记录表中增加借阅记录
update  books set count = count - 1 where bid = 1; 
insert into records (rid,bid) values (1,1); 
commit; -- 提交,只有执行提交这一句,事务动作才真正将结果持久化在硬盘上,如果不提交,更新的数据仍在内存中

【ps】不止是提交,我们也可以手动回滚操作,回滚是rollback

😅验证一波原子性:

在执行完方框内语句后,我们手动重启MySQL服务器,模拟故障:

结果发现,两个表中的数据都没有被修改!说明事务保护了原子性,网络中断导致第二句未执行,所以,执行过的第一句回退,也并未真正对表修改

😅对比一波原子性存在的意义:

2.2 JDBC中事务的使用

Connection中有一个autocomit属性,默认情况下,该属性为true,意思是自动提交每个sql语句,默认视作一个sql是一个事务

故而,如果我们想要让多个sql视为一个事务,我们需要先关闭autocomit,把它修改为false,最后在执行完事务里的sql后,再手动提交事务(commit())。

🥺先写个工具类,对MysqlDataSource类的对象进行初始设置

import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

/**
 * @author sunny
 * @date 2022/04/11 15:53
 **/
public class DBUtil {
    private static final DataSource dataSource;
    static {
        dataSource = new MysqlDataSource();
        String url = "jdbc:mysql://localhost:3306/book?useSSL=false&characterEncoding=utf-8&serverTimezone=Asia/Shanghai";
        ((MysqlDataSource) dataSource).setUrl(url);
        ((MysqlDataSource) dataSource).setUser("root");
        ((MysqlDataSource) dataSource).setPassword("123456");
    }

    public static Connection connection() throws SQLException {
        return dataSource.getConnection();
    }
}

💌然后,进行sql语句的编写和提交

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**事务
 * @author sunny
 * @date 2022/04/11 16:11
 **/
public class transaction_test1 {
    public static void main(String[] args) throws SQLException {
//        依旧以借书操作为例,先更新书籍数量,再新增一条借阅记录
        String sql1 = "update books set count = count - 1 where bid = 1";
        String sql2 = "insert into records (rid, bid) values (1, 1)";
        try(Connection c = DBUtil.connection()){
//            先将自动提交关闭
           c.setAutoCommit(false);
           try(PreparedStatement ps = c.prepareStatement(sql1)){
               ps.executeUpdate();
           }
           try(PreparedStatement ps = c.prepareStatement(sql2)){
               ps.executeUpdate();
           }
//           事务动作结束后,手动提交
            c.commit();
        }
    }
}

关键是下面截图中的两处:

🤨🤨🤨

最后的最后,了解事务,事务的ACID特性都是什么,以及客户端和JDBC两种方式使用事务

标签: 数据库

本文转载自: https://blog.csdn.net/m0_58652786/article/details/124068131
版权归原作者 ᝰꫛꪮꪮꫜ* 所有, 如有侵权,请联系我们删除。

“MySQL学习(六)事务的ACID特性及使用”的评论:

还没有评论