概述
通常的观点认为,事务仅与数据库相干。
将一堆的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指令,要么全都执行胜利,若因为某个起因其中一条指令执行有谬误,则撤销先前执行过的所有指令。更简答的说就是:要么全副执行胜利,要么撤销不执行。