我们先创建一个account表,以演示事务的四大特性:
create table account(
id char(36) primary key,
card_id varchar(20) unique,
name varchar(8) not null,
money float(10,2) default 0
);
insert into account
values('6ab71673-9502-44ba-8db0-7f625f17a67d','1234567890','张三',1000);
insert into account (id,card_id,name)
values('9883a53d-9127-4a9a-bdcb-96cf87afe831','0987654321','张三');
一.原子性(Atomicity)
化学中的原子指不可再分的基本微粒,数据库中原子性强调事务是一个不可分割的整体,事务开始后所有操作要么全部成功,要么全部失败,不可能停滞在中间某个环节。
如果事务执行过程中出错就会回滚到事务开始前的状态,所有的操作就像没有发生一样不会对数据库有任何影响。
当调用setAutoCommit()方法关闭自动提交后,开启一个事务,选择如下两条语句进行执行,最后调用commit()方法提交事务,但是其中第二条语句是有语法错误的,这时运行如下java代码,就算第一条语句是正确的,但是两条都无法执行,而是直接走catch代码块中的rollback语句回到事务开始前,然后报错。
package sql;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class Test{
public static void main(String[] args){
Connection connection=null;
Statement statement=null;
try {
Class.forName("com.mysql.jdbc.Driver");
connection=DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/venus","root","root");
connection.setAutoCommit(false);
statement=connection.createStatement();
statement.addBatch("update account set money=money-100 where card_id= '1234567890'");
statement.addBatch("update account set money=money+100 where ard_id= '0987654321'");
statement.executeBatch();
connection.commit();
} catch (Exception e) {
e.printStackTrace();
if (connection!=null) {
try {
connection.rollback();
} catch (Exception e1) {
e1.printStackTrace();
}
}
} finally {
if (statement!=null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection!=null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
二.一致性(Consistency)
事务必须使数据库从一个一致性状态变换到另一个一致性状态,即一个事务执行之前和执行之后都必须处于一致性状态。
拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还是5000,这就是事务的一致性。
也就是说在数据库中执行如下代码之后,第一条账户减少100元,第二条账户增加100元,最终总和还是1000元:
update account set money=money-100 where card_id= '1234567890';
update account set money=money+100 where card_id= '0987654321';
select * from account;
三.隔离性(Isolation)
当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转入钱。
假如在数据库中开启如下事务,并且不结束事务:
set autocommit=0;
update account set money=2000 where card_id='1234567890';
这时我们在刚才的java代码中执行,相当于开启另一个事务,这时会遇到如下情况:
因为数据库中开启的那个事务还没有关闭所以代码中的事务无法开启,所以程序一直在等待中,最后超时。
四.持久性(Durability)
一个事务一旦被提交,则对数据库的所有更新将被保存到数据库中,不能回滚。
我们在数据库中开启事务,然后进行操作,最后提交事务,这时再使用rollback回滚,会发现并不能回到事务开始之前。