事务是指作为单个逻辑工作单元的一系列操作,要么完全地执行,要么完全地不执行。
简单来说,就是将一堆sql语句绑定到一起(通常是增删改操作),这些sql语句要么完全执行成功,要么完全执行失败。
事务有四大特性(ACID)
A-原子性(Atomicity),事务是作为一个不可分割的原子单位。事务中的操作要么完全的执行成功,要么完全的执行失败。
C-一致性(Consistency),事务执行前后,数据库中的数据的业务状态保持一致。例如:转账前后A账户和B账户的总金额保持一致。
I-隔离性(Isolation),事务之间的并发操作是相互隔离的,并发的事务并不会相互影响。
D-持久性(Durability),事务执行后,数据库中的数据必须立即持久化到硬盘中,即使数据库立即崩溃,也必须通过某种机制恢复数据。
通常我们执行的每一条sql语句都是一个单独事务,只不过数据库底层会帮我们自动开启和结束事务。
若一个事务中有多条sql语句,就需手动开启事务和结束事务。
开启事务:start transaction
结束事务:commit(提交),rollback(回滚)
在执行sql语句之前,
首先,start transaction开启事务,
然后,再执行sql语句,
最后,执行完sql语句后有两种选择
执行sql语句后再提交事务(commit),执行后的sql语句就会持久化到数据库中。
执行sql语句后再回滚事务(rollback),之前执行的sql语句都取消
事务在并发操作时,会导致一些并发读问题,常见的并发读问题,有以下3种。
1)脏读
读取到其他事务还未提交的数据。
提示:需将隔离级别设置为最低才能看到脏读现象 事务1:开启事务 A=A-100,B=B+100(未提交事务) 事务2:开启事务:查询B的账户新增了100,这个查询到的数据就是脏数据
举例:张三给李四转账100元,张三转账100后并没有提交事务,这时李四查询账户发现账户已新增100,就将货物交割了,这时张三再回滚
事务,就可以白嫖了一件货物。
2)不可重复读
指对同一记录的两次查询结果不同,就称之为不可重复读。
提示:需将隔离级别最低设置为read-commited(读已提交)才能看到不可重复读现象
事务1:开启事务
A第一次查询账户:1000
A第二次查询账户:900
事务2:开启事务
B=B-100
提交事务
两次查询的结果不同,是由于第二次查询读取到了其他事务对该记录操作后的数据
3)幻读(虚读)
幻读,又称之为虚读,是指对同一张表的两次查询结果不同,好像出现了幻觉似的,所以称之为幻读。
注意:幻读与不可重复读的区别,不可重复读针对的是同一条记录,幻读针对的是同一张表。
提示:需将隔离级别最低设置为repeatable read(可重复读)才能看到幻读现象
事务1:开启事务
第一次查询A表:10条记录
第二次查询A表:11条记录
事务2:开启事务
向A表种插入1条记录
提交事务
针对上述的3种并发读问题,这里设置了4种隔离级别
事务隔离级别分为4个等级,在相同的数据环境下,对数据执行相同的操作,设置不同的隔离级别,会导致不同的查询结果。
不同的事务隔离级别能够解决的事务并发读问题也不同
1)读未提交(read-uncommited)
特点:安全性最差,上述3种并发读问题都有可能出现,但是性能最好
2)读已提交(read-commited) ORACLE默认隔离级别
特点:安全性较差,可防止脏读,性能较好
3)可重复读(repeatable-read) MYSQL默认隔离级别
特点:安全性较好,可防止脏读,不可重复读,性能较差
4)串行化(serializable)
特点:事务变成的并行操作,可防止所有并发读问题,但是性能最差
1)mysql设置隔离级别
set tx_isolation='read-uncommitted';
2)JDBC设置隔离级别
Connection.setTransactionIsolation(int level);
参考数值:
Connection.TRANSACTION_READ_UNCOMMITED 1 (读未提交)
Connection.TRANSACTION_READ_COMMITED 2 (读已提交)
Connection.TRANSACTION_REPEATABLE_READ 4 (可重复读)
Connection.TRANSACTION_SERIALIZABLE 8 (串行化)
Connection.TRANSACTION_NONE 0 (不使用事务)
提示:在开发中一般不需要设置隔离级别