Fork me on GitHub Fork me on Gitee

JDBC(二)事务

JDBC(二)事务

特点:要么都执行、要么都不执行。

ACID原则:保证数据的安全。

开启事务
事务提交   commit()
事务回滚   rollback()
关闭事务
    
转账
A:1000
B:1000
A(900) --(100)--> B(1100)

搭建一个环境

CREATE TABLE account(
	id INT PRIMARY KEY AUTO_INCREMENT,
	`name` VARCHAR(40),
	money FLOAT
);

INSERT INTO account (`name`,money) VALUES('A',1000);
INSERT INTO account (`name`,money) VALUES('B',1000);
INSERT INTO account (`name`,money) VALUES('C',1000);

SELECT * FROM account;

image-20200418162411178

设计实验:让A给B转账。

当我制造错误时:如 int i = 1/0;

运行结果为

image-20200418164439173

且数据库未发生变化

image-20200418164639468

当去掉错误时:

运行结果为

image-20200418164740939

且数据库发生了变化

image-20200418164806009

实验代码为:

public class TestJDBC4 {

    @Test
    public void test() {
        //配置信息
        String url = "jdbc:mysql://localhost:3306/jdbc?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false";
        String username = "root";
        String password = "123456";
        String jdbc = "com.mysql.cj.jdbc.Driver";

        Connection connection = null; //提高作用域

        try {
            //1.加载驱动
            Class.forName(jdbc);
            //2.连接数据库,代表数据库 DrierManager驱动管理者
           connection = DriverManager.getConnection(url, username, password);
            //3.通知数据库开启事务---即不让数据库自动提交
            connection.setAutoCommit(false);
            //4.编写SQL并执行
            String sql = "update account set money = money-100 where name='A'";
            connection.prepareStatement(sql).executeUpdate();
            //制造错误
            // int i = 1/0;
            //编写SQL并执行
            String sql2 = "update account set money = money+100 where name='B'";
            connection.prepareStatement(sql2).executeUpdate();
            //5.事务提交
            connection.commit();
            System.out.println("success");
        } catch (Exception e) {
            try {//6.如果出现异常,就通知数据库回滚事务
                connection.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
            e.printStackTrace();
        }finally {
            try {//7.关闭连接
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

ACID的详细描述:

下述内容转载自博文:https://www.jianshu.com/p/fc8a654f2205

Atomicity原子性 :一个事务要么全部提交成功,要么全部失败回滚,不能只执行其中的一部分操作,这就是事务的原子性

|

Consistency一致性 :事务的执行不能破坏数据库数据的完整性和一致性,一个事务在执行之前和执行之后,数据库都必须处于一致性状态。

如果数据库系统在运行过程中发生故障,有些事务尚未完成就被迫中断,这些未完成的事务对数据库所作的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,也就是不一致的状态

|

Isolation隔离性 :事务的隔离性是指在并发环境中,并发的事务时相互隔离的,一个事务的执行不能不被其他事务干扰。不同的事务并发操作相同的数据时,每个事务都有各自完成的数据空间,即一个事务内部的操作及使用的数据对其他并发事务时隔离的,并发执行的各个事务之间不能相互干扰。

在标准SQL规范中,定义了4个事务隔离级别,不同的隔离级别对事务的处理不同,分别是:未授权读取,授权读取,可重复读取和串行化

1、读未提交(Read Uncommited),该隔离级别允许脏读取,其隔离级别最低;比如事务A和事务B同时进行,事务A在整个执行阶段,会将某数据的值从1开始一直加到10,然后进行事务提交,此时,事务B能够看到这个数据项在事务A操作过程中的所有中间值(如1变成2,2变成3等),而对这一系列的中间值的读取就是未授权读取

2、授权读取也称为已提交读(Read Commited),授权读取只允许获取已经提交的数据。比如事务A和事务B同时进行,事务A进行+1操作,此时,事务B无法看到这个数据项在事务A操作过程中的所有中间值,只能看到最终的10。另外,如果说有一个事务C,和事务A进行非常类似的操作,只是事务C是将数据项从10加到20,此时事务B也同样可以读取到20,即授权读取允许不可重复读取。

3、可重复读(Repeatable Read)

就是保证在事务处理过程中,多次读取同一个数据时,其值都和事务开始时刻是一致的,因此该事务级别禁止不可重复读取和脏读取,但是有可能出现幻影数据。所谓幻影数据,就是指同样的事务操作,在前后两个时间段内执行对同一个数据项的读取,可能出现不一致的结果。在上面的例子中,可重复读取隔离级别能够保证事务B在第一次事务操作过程中,始终对数据项读取到1,但是在下一次事务操作中,即使事务B(注意,事务名字虽然相同,但是指的是另一个事务操作)采用同样的查询方式,就可能读取到10或20;

4、串行化

是最严格的事务隔离级别,它要求所有事务被串行执行,即事务只能一个接一个的进行处理,不能并发执行。

|

Durability持久性

一旦事务提交,那么它对数据库中的对应数据的状态的变更就会永久保存到数据库中。--即使发生系统崩溃或机器宕机等故障,只要数据库能够重新启动,那么一定能够将其恢复到事务成功结束的状态

作者:老城底
链接:https://www.jianshu.com/p/fc8a654f2205
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

posted on 2020-04-18 17:18  mellisa&myt  阅读(98)  评论(0编辑  收藏  举报