Java开发工程师(Web方向) - 03.数据库开发 - 第4章.事务

第4章--事务

事务原理与开发

事务Transaction:

什么是事务?

事务是并发控制的基本单位,指作为单个逻辑工作单元执行的一系列操作,且逻辑工作单元需满足ACID特性。

i.e. 银行转账:开始交易;张三账户扣除100元;李四账户增加100元;结束交易。

事务的特性:ACID

原子性 Atomicity:整个交易必须作为一个整体来执行。(要么全部执行,要么全部不执行)

一致性 Consistency:整个交易总体资金不变

隔离性 Isolation:

case1: 若张三给李四转账过程中,赵五给张三转账了200元。两个交易并发执行。

T1   T2

读取张三余额100;

读取张三余额100;

给李四转账100,

更新张三余额为0;

交易结束                  赵五转入200,

更新张三余额为300

交易结束

case2: 脏读:张三给别人转账100之后张三存钱200,存钱后转账由于系统原因失败回滚。

读取一个事务未提交的更新

T1 T2

读取张三余额100

(转账) 更新张三余额0

读取张三余额0

T1 Rollback() (存钱) 更新张三余额200

T2结束(张三账户余额为200)

case3: 不可重复读:同一个事务,两次读取同一数值的结果不同,成为不可重复读。

T1张三读取自己余额为100;T2读取张三余额100;T2存钱更新为300;T1张三读取余额为300。T1中两次读取张三余额即为不可重复读。

case4: 幻读:两次读取的结果包含的行记录不一样。

T1读取所有用户(张三、李四);T2新增用户赵五;T1读取所有用户(3个);T1/T2结束。T1中两次读取的结果中行记录数不同,称为幻读。

需要避免上述cases的产生

隔离性:交易之间相互隔离,在一个交易完成之前,不能受到其他交易的影响

持久性 Durability:整个交易过程一旦结束,无论出现任何情况,交易都应该是永久生效的

使用JDBC进行事务控制:

Connection类中

.setAutoCommit():开启事务(若为false,则该Connection对象后续的sql都将作为事务来处理;若为true,则该Connection对象后续的所有sql都将作为单独的语句执行(默认为true))

.commit():事务被提交,即事务生效并结束

.rollback():回滚,回退到事务开始之前的状态

i.e.

ALTER TABLE user ADD Account int;
UPDATE User SET Account = 100 WHERE id = 1;
UPDATE User SET Account = 0 WHERE id > 1;

实现ZhangSi(1)给LiSan(2)转账的过程:

(非事务:)

public static void TransferNonTransaction() {
    Connection conn = null;
    PreparedStatement ptmt = null;

    try {
        conn = DriverManager.getConnection(DB_URL, USER_NAME, PASSWORD);
        String sql = "UPDATE User SET Account = ? WHERE userName = ? AND id = ?;";
        // transfer 100 from ZhangSi(1) to LiSan(2)
        ptmt = conn.prepareStatement(sql);
        ptmt.setInt(1, 0);
        ptmt.setString(2, "ZhangSi");
        ptmt.setInt(3, 1);
        ptmt.execute();

        ptmt.setInt(1, 100);
        ptmt.setString(2, "LiSan");
        ptmt.setInt(3, 2);
        ptmt.execute();
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        try {
            if (conn != null) conn.close();
            if (ptmt != null) ptmt.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

执行完第一个ptmt.execute()后,数据库中ZhangSi的Account=0, LiSan的Account=0;

出现了一个中间状态,对于整个业务逻辑的实现是不可接受的。如果此时程序崩溃了将不可挽回。

(事务:)

public static void TransferByTransaction() {
    Connection conn = null;
    PreparedStatement ptmt = null;
    try {
        conn = DriverManager.getConnection(DB_URL, USER_NAME, PASSWORD);

        // Using Transaction mechanism
        conn.setAutoCommit(false);
        String sql = "UPDATE User SET Account = ? WHERE userName = ? AND id = ?;";
        ptmt = conn.prepareStatement(sql);
        ptmt.setInt(1, 0);
        ptmt.setString(2, "ZhangSi");
        ptmt.setInt(3, 1);
        ptmt.execute();

        ptmt.setInt(1, 100);
        ptmt.setString(2, "LiSan");
        ptmt.setInt(3, 2);
        ptmt.execute();

        // Commit the transaction
        conn.commit();

    } catch (SQLException e) {
        // if something wrong happens, rolling back
        if(conn != null) {
            try {
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        }
        e.printStackTrace();
    } finally {
        try {
            if (conn != null) conn.close();
            if (ptmt != null) ptmt.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

若在第一个ptmt.execute()时断点,并查询数据库,结果为事务执行之前的状态,并不是中间状态。

直到conn.commit()方法执行完毕,事务中的所有操作在数据库中才有效。

Connection类中的检查点功能:

.setSavePoint():在执行过程中创建保存点,以便rollback()可以回滚到该保存点

.rollback(SavePoint savePoint):回滚到某个检查点

i.e.

public static void rollbackTest() {
    Connection conn = null;
    PreparedStatement ptmt = null;
    // save point
    Savepoint sp = null;
    try {
        conn = DriverManager.getConnection(DB_URL, USER_NAME, PASSWORD);

        conn.setAutoCommit(false);
        String sql = "UPDATE User SET Account = ? WHERE userName = ? AND id = ?;";
        ptmt = conn.prepareStatement(sql);
        ptmt.setInt(1, 0);
        ptmt.setString(2, "ZhangSi");
        ptmt.setInt(3, 1);
        ptmt.execute();
        // create a save point
        sp = conn.setSavepoint();

        ptmt.setInt(1, 100);
        ptmt.setString(2, "LiSan");
        ptmt.setInt(3, 2);
        ptmt.execute();

        // throw an exception manually for the purpose of testing
        throw new SQLException();

    } catch (SQLException e) {
        // if something wrong happens, rolling back to the save point created before
        // and then transfer the money to Guoyi(3)
        if(conn != null) {
            try {
                conn.rollback(sp);
                System.out.println("Transfer from ZhangSi(1) to LiSan(2) failed;\n"
                        + "Transfer to GuoYi(3) instead");

                // other operations
                ptmt.setInt(1, 100);
                ptmt.setString(2, "GuoYi");
                ptmt.setInt(3, 3);
                ptmt.executeQuery();
                conn.commit();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        }

        e.printStackTrace();
    } finally {
        try {
            if (conn != null) conn.close();
            if (ptmt != null) ptmt.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

事务的隔离级别:4个级别

读未提交(read uncommited):可能导致脏读

读提交(read commited):不可能脏读,但是会出现不可重复读

重复读(repeatable read):不会出现不可重复读,但是会出现幻读

串行化(serializable):最高隔离级别,不会出现幻读,但严格的并发控制、串行执行导致数据库性能差

N.B. 1. 事务隔离级别越高,数据库性能越差,但对于开发者而言编程难度越低。

2. MySQL默认事务隔离级别为重复读 repeatable read

JDBC设置隔离级别:

Connection对象中,

.getTransactionIsolation();

.setTransactionIsolation();

死锁分析与解决

时间: 2024-10-25 18:52:29

Java开发工程师(Web方向) - 03.数据库开发 - 第4章.事务的相关文章

Java开发工程师(Web方向) - 03.数据库开发 - 第1章.JDBC

第1章--JDBC JDBC基础 通过Java Database Connectivity可以实现Java程序对后端数据库的访问 一个完整的数据库部署架构,通常是由客户端和服务器端两部分组成 客户端封装数据库请求,并发送给服务器端,服务器端执行完毕后将结果返回给客户端 常见客户端工具: MySQL Workbench(图形化工具操作简单,但只能实现简单的查询) JDBC(驱动程序jar包) 命令行工具(直接敲入SQL语句进行查询) 市面上多种数据库不尽相同,学习成本高,数据库迁移的移植性 --

Java开发工程师(Web方向) - 03.数据库开发 - 期末考试

期末考试 编程题 本编程题包含4个小题,覆盖知识点从基础的JDBC.连接池到MyBatis. 1(10分) 有一款在线教育产品"天天向上"主要实现了在手机上查看课程表的功能.该产品的后端系统有一张保存了所有客户课程信息的数据库表,表结构如下: 请使用JDBC编写一段程序,实现读取用户名为"ZhangSan"的同学的所有课程名称,输出到控制台终端. 答: 数据库: /usr/local/mysql/bin ./mysql -u root -p mysql> CR

Java开发工程师(Web方向) - 04.Spring框架 - 第2章.IoC容器

第2章.IoC容器 IoC容器概述 abstract: 介绍IoC和bean的用处和使用 IoC容器处于整个Spring框架中比较核心的位置:Core Container: Beans, Core, Context, SpEL 为上层AOP/Aspects/Instrumentation/Messaging提供支持 IoC容器的用途: 创建对象的依赖,最后组装成所需的业务对象 容器通过业务对象和配置(application-context.xml; xxxController.java)-->生

Java开发工程师(Web方向) - 04.Spring框架 - 第3章.AOP技术

Spring框架 - AOP概述 笔记https://my.oschina.net/hava/blog/758873Spring框架 - AOP使用 笔记https://my.oschina.net/hava/blog/758881 AOP技术单元测试 返回 本次得分为:7.00/7.00, 本次测试的提交时间为:2017-09-11, 如果你认为本次测试成绩不理想,你可以选择再做一次. 1 单选(2分) 如下关于AOP的描述中错误的是: 得分/总分 A. AOP可以对代码进行解耦: B. A

Java开发工程师(Web方向) - 01.Java Web开发入门 - 第4章.Maven

第4章--Maven Maven实战 Java Web应用的部署: 手动式: 编译:javac -cp $CATALINA_HOME/lib/servlet-api.jar web-inf/classes/package/NoodlesServlet.java 打包:jar cvf Restaurant.war . 移动:mv Restaurant.war .../webapps/ 项目复杂时:比如项目文件很多 -- IDE如eclipse --> IDE式:(如eclipse) 下载第三方依赖

Java开发工程师(Web方向) - 01.Java Web开发入门 - 第6章.蜂巢

第6章--蜂巢 蜂巢简介 网站开发完,就需要测试.部署.在服务器上运行. 网易蜂巢: 采用Docker容器化技术的云计算平台 https://c.163.com 容器管理:容器可被视作为云主机的服务器 服务管理:服务可由多个容器组成,可以有多个副本 镜像仓库:可快速创建容器和服务 后端服务:blahblahblah 特点: 保证环境一致: 实际中开发环境.测试环境.生产环境等会不大相同 环境差异可能会导致业务代码运行得到不同结果 蜂巢底层采用Docker容器:把业务代码和运行环境打包成为一个镜像

Java开发工程师(Web方向) - 02.Servlet技术 - 期末考试

Servlet课程考试 Servlet课程考试 Servlet课程考试 总分:55分 限定时间:120分钟 进入考试 答案已成功提交!请耐心等待成绩公布 Servlet课程考试: 1(12分) 简单谈一下你理解的Servlet是什么,以及Servlet的工作原理. Servlet即Server Applet,是在服务器端运行的程序.一个Servlet对象实际上就是一个Java类. 浏览器在与服务器通信时,浏览器先向服务器发出请求,该请求被Servlet容器解析并发送给对应Servlet对象后,由

Java开发工程师(Web方向) - 01.Java Web开发入门 - 第3章.Servlet应用

第3章.Servlet应用 转发与重定向 过滤器与监听器 Servlet并发处理

Java开发工程师(Web方向) - 01.Java Web开发入门 - 第2章.HTTP协议简介

第2章--HTTP协议简介 HTTP协议简介 Abstract: HTTP协议的特性,HTTP请求/响应的过程,HTTP请求/响应的报文格式等知识,最后会演示如何通过Chrome提供的开发者工具,去跟踪调试一次HTTP请求. HTTP protocol: 请求响应式协议: client -->  server : HTTP 请求 client <--  server : HTTP 响应 一个HTTP请求和一个HTTP响应 -->  一次HTTP事务 任意两次HTTP事务都是indepen