共计 3147 个字符,预计需要花费 8 分钟才能阅读完成。
概述
通常的观点认为,事务仅与数据库相干。
将一堆的 SQL 语句绑定在一起执行,后果是要么全都执行胜利(都胜利才算胜利), 要么全都执行失败(有一个失败就按全失败来解决)!
事务的例子
转账,张三 (1000 元) 给李四 (1000 元) 转账 100 元
开启事务
张三账户减去 100 元:
update 账户表 set money=money-100 where name=’ 张三 ’;
–900
李四账户上加 100 元:
update 账户表 set money=money+100 where name=’ 李四 ’;
–1000
完结事务 提交 / 回滚
个性
(1)原子性
事务中的所有操作都是一个整体,不能被宰割,要么全副执行胜利, 要么全都执行失败。
(2)一致性
在事务执行前后的业务数据之和,是保持一致的。
举例
转账,张三 (1000 元) 给李四 (1000 元) 转账 100 元。
开启事务
张三 (1000 元)-100 元 =900 元
李四 (1000 元)+100 元 =1100 元
完结事务:提交 / 回滚
不论事务最初是提交了,还是回滚了,张三和李四的账户金额之和,在转账前,转账后是保持一致的!
(3)隔离性
在事务并发时,多个事务之间是具备隔离性的,在一个事务中看不到另一个事务正在进行的数据状态。
(4)持久性
事务提交后,在事务中对数据的更新会长久的保留到数据库中。
在事务提交之前,事务中执行的操作,并没有真正的更新到数据库。
举例
开始事务
张三 (1000 元) 给李四 (1000 元) 转账 500 元
张三 (1000 元)-500 元 =500 元
李四 (1000 元)-500 元 =1500 元
完结事务: 提交 / 回滚
在事务提交执行,张三减去 500 元,以及李四加上 500 元,其实并没有真正批改张三和李四的账户金额,只是在日志中记录了,未来如果事务提交了,在事务提交后,才会真正的刀数据库中,更新张三账户金额为 500 元,更新李四账户金额为 1500 元!
MySQL 中的事务
1. 默认状况下,MySQL 中的每一条 SQL 都是一个事务!
2. 每次在执行 SQL 语句之前,会默认开启事务,在执行这条 SQL 语句之后,会主动提交事务。
3. 如果须要让两条或者两条以上的 SQL 语句在一个事务中执行,须要再执行之前开启事务,在最初一条 SQL 语句执行实现后,立刻完结事务。
开启事务:start transaction;
完结事务:commit(提交)/rollback(回滚);
如果事务汇总的所有 SQL 语句都执行胜利了,最初咱们能够提交事务;
如果事务中的 SQL 语句有一条执行失败,就按全副失败来解决,最初咱们会回滚 (撤销) 事务;
示例
演示 A 账户给 B 账户转账
(1) 开启事务
start transaction
(2)A 账户减去 100 元
update acc set money=money-100 where name=’A’; — 900 元
(3)B 账户加上 100 元
upadate acc set money+100 where name=’B’; — 1100 元
(4) 查问 A,B 的账户金额 (在不同的 cmd 窗口进行查看)
select * from acc;
(5) 将事务回滚(撤销), 将事务提交
rollback;/commit;
并发读问题
多个事务对雷同数据进行操作,这叫做事务并发。
在事务并发时,如果没有采取必要的隔离措施,可能会导致各种并发问题,毁坏数据的完整性等。这些问题中,其中三类是读问题,别离是:脏读,不可反复读,幻读。
(1)脏读
在一个事务中,读取到另外一个事务为提交更新的数据,称之为脏读。
举例
A(买家)B(卖家)
A 转账给 B 100 元
开启事务:
A-100=900 元
B+100=1100 元
此时没有提交事务。。。
B 在另外一个事务中查问到账户减少了 100 元, 也就是 1100 元。因为 MySQL 默认不容许呈现脏读, 所以要想演示脏读景象,必须将 mysql 的事务隔离级别设置为最低。
set tx_isolation = ‘read-uncommitted’;
(2)不可反复读
在一个事务中对同一数据的两次查问后果不统一,是因为另一个事务对该数据进行了批改操作!
举例
事务一:在事务中查问 A 账户的余额
第一次查问:select * from acc where name=’A’; — 1000
第二次查问:select * from acc where name=’A’; — 900
事务二:A 给 B 转账 100 元
update acc set money = money-100 where name ‘A’
…
提交事务
(3)幻读
在一个事务中对同一张表的两次查问后果不统一,是因为有另一个事务对表进行了插入或者删除操作!
举例
事务一:
第一次:select * from acc where id=3; 不存在
插入一条 id 为 3 的记录:insert into acc value(2,’C’,2000);– 插入失败
第二次:select * from acc where id=3;– 已存在
事务二:
插入了一条 id 为 3 的记录:insert into acc value(3,’C’,3000);
提交了事务
隔离级别
read uncommitted(读未提交数据)
安全性最差, 不能避免任何的并发读问题, 但性能最高,不举荐应用。
red committed(读已提交数据)
Oracle 默认的隔离级别
安全性比 ’ 读未提交 ’ 好,能够避免脏读,但不能避免不可反复读,也不能避免幻读,性能比 ’ 读未提交 ’ 差。
repeatable read(可反复读)
MySQL 默认的隔离级别
安全性比 ’ 读已提交 ’ 好,能够避免脏读,不可反复读,但不能避免幻读,性能比 ’ 读已提交 ’ 差。
因为 mysql 默认的隔离级别不容许呈现脏读和不可反复读,因而要想要在 mysql 中演示这两个景象,必须要设置 mysql 的隔离级别为最低级别,也就是 ’ 读未提交 ’。
serializable(串行化)
安全性最好,能够避免脏读,不可反复读,幻读,性能最差,也不举荐应用!
设置隔离级别
因为数据库有本人默认的事务隔离级别,咱们不须要去设置
mysql 中设置事务的隔离级别
查问以后应用的事务隔离级别:
select @@tx_isolation
设置事务的隔离级别:
set tx_isolation=’read-uncommitted’ 设置隔离级别为 ’ 读未提交 ’
set tx_isolation=’read-conmmitted’ 设置隔离级别为 ’ 读已提交 ’
set tx_isolation=’repeatable-read’ 设置隔离级别为 ’ 能够反复读 ’
set tx_isolation=’serialiable’ 设置隔离级别为 ’ 串行化 ’
JDBC 中设置事务的隔离级别
JDBC 中通过 Connection 提供的办法设置事务隔离级别:
Connection.setTransactionIsolation(int level)
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 也是在执行 SQL 语句之前,默认开启事务,执行之后,立刻提交事务!
因而想要在 JDBC 中,将两条或者以上的 SQL 语句放在一个事务中执行,须要敞开主动提交事务!
conn.setAutoCommit(false);
小结
事务就是一组原子操作单元,从数据库的角度说,就是一组 SQL 指令,要么全都执行胜利,若因为某个起因其中一条指令执行有谬误,则撤销先前执行过的所有指令。更简答的说就是:要么全副执行胜利,要么撤销不执行。