美文网首页数据库
事务基本概念【转载】

事务基本概念【转载】

作者: elijah777 | 来源:发表于2019-06-19 23:43 被阅读0次

    事务基本概念

    1. 事务(Transaction)的四个属性(ACID)

    1. 原子性(Atomic)** 对数据的修改要么全部执行,要么全部不执行。
    2. 一致性(Consistent) 在事务执行前后,数据状态保持一致性。
    3. 隔离性(Isolated) 一个事务的处理不能影响另一个事务的处理。
    4. 持续性(Durable) 事务处理结束,其效果在数据库中持久化。

    2. 事务并发处理可能引起的问题

    1. 脏读(dirty read)**:一个事务读取了另一个事务尚未提交的数据,
    2. 不可重复读(non-repeatable read) :一个事务的操作导致另一个事务前后两次读取到不同的数据
    3. 幻读(phantom read) :一个事务的操作导致另一个事务前后两次查询的结果数据量不同。

    3. JDBC的事务支持

    JDBC对事务的支持体现在三个方面:

    1.自动提交模式(Auto-commit mode)

    Connection提供了一个auto-commit的属性来指定事务何时结束。 a.当auto-commit为true时,当每个独立SQL操作的执行完毕,事务立即自动提交,也就是说每个SQL操作都是一个事务。一个独立SQL操作什么时候算执行完毕。

    1.JDBC规范是这样规定的:对数据操作语言(DML,如insert,update,delete)和数据定义语言(如create,drop),语句一执行完就视为执行完毕。 2.对select语句,当与它关联的ResultSet对象关闭时,视为执行完毕。 3.对存储过程或其他返回多个结果的语句,当与它关联的所有ResultSet对象全部关闭,所有update count(update,delete等语句操作影响的行数)和output parameter(存储过程的输出参数)都已经获取之后,视为执行完毕。

    b. 当auto-commit为false时,每个事务都必须显示调用commit方法进行提交,或者显示调用rollback方法进行回滚。auto-commit默认为true。

    2.事务隔离级别(Transaction Isolation Levels)

    JDBC提供了5种不同的事务隔离级别,在Connection中进行了定义。 JDBC定义了五种事务隔离级别:

    TRANSACTION_NONE JDBC驱动不支持事务 TRANSACTION_READ_UNCOMMITTED 允许脏读、不可重复读和幻读。 TRANSACTION_READ_COMMITTED 禁止脏读,但允许不可重复读和幻读。 TRANSACTION_REPEATABLE_READ 禁止脏读和不可重复读,单运行幻读。 TRANSACTION_SERIALIZABLE 禁止脏读、不可重复读和幻读。

    3.保存点(SavePoint)

    JDBC定义了SavePoint接口,提供在一个更细粒度的事务控制机制。当设置了一个保存点后,可以rollback到该保存点处的状态,而不是rollback整个事务。

    Connection接口的setSavepoint和releaseSavepoint方法可以设置和释放保存点。 JDBC规范虽然定义了事务的以上支持行为,但是各个JDBC驱动,数据库厂商对事务的支持程度可能各不相同。如果在程序中任意设置,可能得不到想要的效果。为此,JDBC提供了DatabaseMetaData接口,提供了一系列JDBC特性支持情况的获取方法。比如,通过DatabaseMetaData.supportsTransactionIsolationLevel方法可以判断对事务隔离级别的支持情况,通过DatabaseMetaData.supportsSavepoints方法可以判断对保存点的支持情况。

    4. 事务隔离级别

    Read uncommit(读未提交) Read commit(读已提交) Repeatable read(可重复读) Serializable(序列化)

    a、读未提交 Read Uncommitted

    在该隔离级别,所有事务都可以看到其它事务未提交的内容数据。此隔离级别没有解决任何并发问题,不常用。

    Read Uncommitted是隔离级别最低的一种事务级别。在这种隔离级别下,一个事务会读到另一个事务更新后但未提交的数据,如果另一个事务回滚,那么当前事务读到的数据就是脏数据,这就是脏读(Dirty Read)。

    首先,我们准备好students表的数据,该表仅一行记录:

    mysql> select * from students;
    +----+-------+
    | id | name  |
    +----+-------+
    |  1 | Alice |
    +----+-------+
    1 row in set (0.00 sec)
    

    然后,分别开启两个MySQL客户端连接,按顺序依次执行事务A和事务B:

    时刻 事务A 事务B
    1 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
    2 BEGIN; BEGIN;
    3 UPDATE students SET name = 'Bob' WHERE id = 1;
    4 SELECT * FROM students WHERE id = 1;
    5 ROLLBACK;
    6 SELECT * FROM students WHERE id = 1;
    7 COMMIT;

    事务B 第一次读4的和第二次5读的数据不一致 脏数据

    当事务A执行完第3步时,它更新了id=1的记录,但并未提交,而事务B在第4步读取到的数据就是未提交的数据。

    随后,事务A在第5步进行了回滚,事务B再次读取id=1的记录,发现和上一次读取到的数据不一致,这就是脏读。

    可见,在Read Uncommitted隔离级别下,一个事务可能读取到另一个事务更新但未提交的数据,这个数据有可能是脏数据。

    b、读已提交 Read Committed

    在该隔离级别,一个事务只能读取其它事务已经提交的内容数据。此隔离级别解决了脏读,但没有解决不可重复读和幻读,是ORACLE的默认隔离级别。

    不可重复读是指,在一个事务内,多次读同一数据,在这个事务还没有结束时,如果另一个事务恰好修改了这个数据,那么,在第一个事务中,两次读取的数据就可能不一致。

    我们仍然先准备好students表的数据:

    mysql> select * from students;
    +----+-------+
    | id | name  |
    +----+-------+
    |  1 | Alice |
    +----+-------+
    1 row in set (0.00 sec)
    

    然后,分别开启两个MySQL客户端连接,按顺序依次执行事务A和事务B:

    时刻 事务A 事务B
    1 SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
    2 BEGIN; BEGIN;
    3 SELECT * FROM students WHERE id = 1;
    4 UPDATE students SET name = 'Bob' WHERE id = 1;
    5 COMMIT;
    6 SELECT * FROM students WHERE id = 1;
    7 COMMIT;

    事务B 读到两次3和6不同的数据

    当事务B第一次执行第3步的查询时,得到的结果是Alice,随后,由于事务A在第4步更新了这条记录并提交,所以,事务B在第6步再次执行同样的查询时,得到的结果就变成了Bob,因此,在Read Committed隔离级别下,事务不可重复读同一条记录,因为很可能读到的结果不一致。

    c、可重复读 Repeatable Read

    在该隔离级别,能保证一个事务之间的多个实例在并发下能读取同一数据。此隔离级别解决了脏读和不可重复读,是MYSQL的默认级别。

    在Repeatable Read隔离级别下,一个事务可能会遇到幻读(Phantom Read)的问题。

    幻读是指,在一个事务中,第一次查询某条记录,发现没有,但是,当试图更新这条不存在的记录时,竟然能成功,并且,再次读取同一条记录,它就神奇地出现了。

    我们仍然先准备好students表的数据:

    mysql> select * from students;
    +----+-------+
    | id | name  |
    +----+-------+
    |  1 | Alice |
    +----+-------+
    1 row in set (0.00 sec)
    

    然后,分别开启两个MySQL客户端连接,按顺序依次执行事务A和事务B:

    时刻 事务A 事务B
    1 SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
    2 BEGIN; BEGIN;
    3 SELECT * FROM students WHERE id = 99;
    4 INSERT INTO students (id, name) VALUES (99, 'Bob');
    5 COMMIT;
    6 SELECT * FROM students WHERE id = 99;
    7 UPDATE students SET name = 'Alice' WHERE id = 99;
    8 SELECT * FROM students WHERE id = 99;
    9 COMMIT;

    事务B在第3步第一次读取id=99的记录时,读到的记录为空,说明不存在id=99的记录。随后,事务A在第4步插入了一条id=99的记录并提交。事务B在第6步再次读取id=99的记录时,读到的记录仍然为空,但是,事务B在第7步试图更新这条不存在的记录时,竟然成功了,并且,事务B在第8步再次读取id=99的记录时,记录出现了。

    d、序列化 Serializable

    这是最高的隔离级别,在此隔离级别,事务事务之间只能顺序执行,使之没有任何冲突。序列化解决了脏读,不可重复读和幻读。 隔离级别越高,越能保证数据的完整性和一致性,但是对并发的效率就越低。因此并不是隔离级别越高越好,应根据具体的业务场景选用合适的事务隔离级别,如果没有特别重要的情景,一般都不会使用Serializable隔离级别。

    默认隔离级别

    如果没有指定隔离级别,数据库就会使用默认的隔离级别。在MySQL中,如果使用InnoDB,默认的隔离级别是Repeatable Read。

    2019/6/19晚 于成都
    文章内容参考与互联网博客以及廖师兄的文章

    参考内容:

    https://www.liaoxuefeng.com/wiki/1177760294764384/1179611198786848

    https://www.cnblogs.com/fjdingsd/p/5273008.html

    相关文章

      网友评论

        本文标题:事务基本概念【转载】

        本文链接:https://www.haomeiwen.com/subject/jrkrqctx.html