首页 > 其他分享 >第十八章《JDBC》第3节:事务处理

第十八章《JDBC》第3节:事务处理

时间:2023-01-03 11:33:28浏览次数:61  
标签:语句 事务 JDBC 第十八章 回滚 事务处理 提交 SQL 执行

​事务是数据库学科中非常重要的机制,它是保证底层数据完整的重要手段,没有事务支持的数据库都是非常脆弱的,本小节将讲解MySQL事务处理的基本技术和以及JDBC的事务支持方法。

18.3.1事务的概念和MySQL事务支持

事务是由一步或几步数据库操作序列组成的逻辑执行单元,这系列操作要么全部执行,要么全部放弃执行,一般而言,一段程序中可能包含多个事务。事务具备4个特性:原子性(Atomicity)、一致性(Consistency)、 隔离性(Isolation)和持续性(Durability),这4个特性也简称为ACID性。​

  • 原子性(Atomicity):事务是应用中最小的执行单位,就如原子是自然界的最小颗粒,具有不可再分的特征一样,事务是应用中不可再分的最小逻辑执行体。​
  • 一致性(Consistency):事务执行的结果,必须使数据库从一个一致性状态,变到另一个一致性状态。当数据库只包含事务成功提交的结果时,数据库处于一致性状态。如果系统运行发生中断,某个事务尚未完成而被迫中断,而该未完成的操作对数据库所做的修改已被写入数据库,此时数据库就处于一种不正确的状态。比如银行在两个账户之间转账:从A账户向B账户转入1000元,系统先减少A账户的1000元,然后再为B账户增加1000元。如果全部执行成功,数据库处于一致性状态,如果仅执行完A账户金额的修改,而没有增加B账户的金额,则数据库就处于不一致性状态。因此,一致性是通过原子性来保证的。​
  • 隔离性(Isolation):各个事务的执行互不干扰,任意一个事务的内部操作对其他并发的事务都是隔离的。也就是说,并发执行的事务之间不能看到对方的中间状态,并发执行的事务之间不能互相影响。​
  • 持续性(Durability):持续性也称为持久性(Persistence),指事务一旦提交, 对数据所做的任何改变都要记录到永久存储器中,通常就是保存进物理数据库。​

通常情况下,数据库的事务有以下几种可能性:​

  • 一组DML语句,经过这组DML语句修改后的数据将保持一致性。​
  • 一条DDL语句。​
  • 一条DCL语句。​

当事务所包含的全部数据库操作都成功执行后,应该提交事务以使这些修改生效。事务提交有显式提交和自动提交两种方式。所有执行DDL或DCL语句都是自动提交的,在MySQL的默认情况下DML语句也是自动提交的,但程序员可以人为的设置DML为显式提交,也就是手动提交方式。​

当事务所包含的任意一个数据库操作执行失败后,应该回滚事务,使该事务中所做的修改全部失效。事务回滚有也两种方式:显式回滚和自动回滚。显示回滚是调用rollback命令完成的,而自动回滚是在系统出错或强行退出的情况下完成的。​

之前讲过,MySQL在默认情况下对DML语句是自动提交的,如果希望改成显式提交可以调用以下命令完成:​

set autocommit=0​

如果程序员不想改变默认的事务自动提交方式,但又希望某一次执行语句时能够达到首动听提交的效果,可以使用MySQL提供的start transaction 或begin两个命令,它们都表示临时性地开始一次事务, 处于start transaction或begin后的DML语句不会立即生效,除非使用commit显式提交事务,例如下SQL代码将不会对数据库有任何影响。​

begin;​
insert into users values ('12307','张三','男','1999-03-02','13800099000');​
insert into users values ('12308','李四','男','1999-06-12','13833445566');​
insert into users values ('12309','王五','男','1999-09-22','18823455432');​
rollback;​

之所以上面这段代码不会对数据库有任何影响,就是因为begin命令之后的DML语句已经不再是自动提交,必须调用commit命令显式提交,而以上代码的最末尾调用的是rollback命令完成回滚,这使得数据库又回到了原先的状态。需要注意:无论是提交还是回滚,都会使当前的事务结束。​

除此之外,MySQL还提供了savepoint来设置事务的中间点,这个中间点相当于一个标记,程序员可以让事务回滚到指定的中间点,而不是回滚全部事务。下面的SQL语句设置了一个中间点a:​

savepoint a;​

一旦设置了中间点后,就可以使用rollback回滚到指定中间点,回滚到指定中间点的代码如下:​

rollback to a;​

需要注意:普通的提交、回滚都会结束当前事务,但回滚到指定中间点因为依然处于事务之中,所以不会结束当前事务。​

18.3.2 JDBC的事务支持

JDBC连接也提供了事务支持,JDBC连接的事务支持由Connection提供,Connection 默认打开自动提交模式,在这种情况下,每条SQL语句一旦执行,便会立即提交到数据库,永久生效,无法对其进行回滚操作。程序员可以调用Connection的setAutoCommit()方法来关闭自动提交模式,代码如下:​

con.setAutoCommit (false);​

相应的,Connection接口的getAutoCommit()方法可以返回该连接的自动提交模式。​

一旦事务开始之后,程序可以像平常一样创建Statement对象,创建了Statement 对象之后,可以执行任意多条DML语句,如下代码所示: .​

stm.executeUpdate(sql1);​
stm.executeUpdate(sql2);​
stm.executeUpdate(sql3);​

.上面这些SQL语句虽然被执行了,但这些SQL语句所做的修改不会生效,因为事务还没有结束。如果所有的SQL语句都执行成功,程序可以调用Connection的commit()方法来提交事务,代码如下:​

con.commit() ;​

如果任意一条SQL语句执行失败,则应该用Connection的rollback()方法来回滚事务,代码如下:​

con.rollback();​

实际上,当程序执行时出现一个未处理的SQLException 异常时,系统将会非正常退出,事务也会自动回滚。但如果程序捕获了该异常,则需要在异常处理块中显式地回滚事务。下面的【例18_07】展示了程序在出现没有捕获的异常时系统自动回滚的效果。​

【例18_07 自动回滚事务】

Exam18_07.java​

import java.sql.*;
public class Exam18_07 {
public static void main(String[] args) throws Exception{
Connection con = Util1.getConneciton();//用Util1的方法获得Connection对象
con.setAutoCommit(false);//关闭自动提交
Statement stm = con.createStatement();
stm.executeUpdate("insert games value(7,'五子棋','棋牌')");
//下面这条语句无法执行成功并产生异常,因为主键冲突
stm.executeUpdate("insert games value(7,'中国象棋','棋牌')");//①;
con.commit();//提交事务
Util1.close(null,stm,con);//释放资源
}
}

【例18_07】中的Connection对象con被设置为关闭自动提交事务,程序中执行了两条插入数据的SQL语句,但第二条SQL语句因主键冲突不能执行成功,因此会产生异常,而main()方法并未捕获这个异常,这样事务会自动回滚,因而两条SQL语句都不会生效。在执行完本例后,读者查询games表会发现程序中试图插入的两条数据并未出现在数据库中。​

Connection也提供了设置中间点的方法,如表18-6所示。​

表18-6 Connection设置中间点的方法​

方法​

功能​

Savepoint setSavepoint()​

在当前事务中创建一个未命名的中间点,并返回代表该中间点的Savepoint对象​

Savepoint setSavepoint(String name) ​


在当前事务中创建一个具有指定名称的中间点,并返回代表该中间点的Savepoint对象。​

通常来说,设置中间点时没有太大的必要指定名称,因为Connection回滚到指定中间点时并不是根据名字回滚的,而是根据中间点对象回滚的,Connection 提供了rollback(Savepoint savepoint)方法回滚到指定中间点。​

18.3.3批量更新

JDBC还提供了一个批量更新的功能,使用批量更新时,多条SQL语句将被作为一批操作被同时被执行。使用批量更新也需要先创建一个Staterment对象,然后利用该对象的addBatch()方法将多条SQL语句同时收集起来,最后调用executeLargeBatch()或executeBatch()方法同时执行这些SQL语句。只要批量操作中任何一条SQL语句影响的记录条数可能超过Integer.MAX_ VALUE,就应该使用executeLargeBatch(方法,而不是executeBatch()方法。下面的代码展示了如何执行批量更新。​

Statement stm = con.createStatement() ;​
//使用Statement同时收集多条SQL语句​
stm.addBatch(sql1) ;​
stm.addBatch (sql2) ;​
stmt.addBatch(sql3) ;​
//同时执行所有的SQL语句​
stmt. executeLargeBatch();​

执行executeLargeBatch()方法将返回一个long[]数组,因为使用Statement执行DDL、DML语句都将返回一个long值,而执行多条DDL、DML语句将会返回多个long值,多个long值就组成了这个long[]数组。如果在批量更新的addBatch()方法中添加了select查询语句,程序将直接出现错误。​

为了让批量操作可以正确地处理错误,必须把批量执行的操作视为单个事务,如果批量更新在执行过程中失败,则让事务回滚到批量操作开始之前的状态。为了达到这种效果,程序应该在开始批量操作之前先关闭自动提交,然后开始收集更新语句,当批量操作执行结束后,提交事务并恢复之前的自动提交模式。下面的【例18_08】展示了如何使用JDBC的批量更新。​

【例18_08 批量更新】

Exam18_08.java​

import java.sql.*;

public class Exam18_08 {
public static void main(String[] args) {
Connection con = null;
Statement stm = null;
try {
con = Util1.getConneciton();//用Util1的方法获得Connection对象
con.setAutoCommit(false);//关闭自动提交
stm = con.createStatement();
//一组SQL语句
String[] sqls = {
"insert games value(7,'五子棋','棋牌')",
"insert games value(8,'中国象棋','棋牌')",
"insert games value(9,'消消乐','益智')"
};
//用循环的形式把要执行的SQL语句收集起来
for (String sql : sqls) {
stm.addBatch(sql);
}
//同时执行所有的SQL语句
stm.executeLargeBatch();
//提交修改
con.commit();
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
Util1.close(null,stm,con);//释放资源
}catch (SQLException e){
e.printStackTrace();
}
}
}
}

执行完【例18_08】的案例代码后,读者再查询games表会看到表中新增加了3条数据,但再次执行这个程序会引发异常,这是因为产生了主键冲突。

本文字版教程还配有更详细的视频讲解,小伙伴们可以点击这里观看。

标签:语句,事务,JDBC,第十八章,回滚,事务处理,提交,SQL,执行
From: https://blog.51cto.com/mugexuetang/5984799

相关文章

  • 第十八章《JDBC》第4节:数据库连接池
    ​数据库连接的建立及关闭是极耗费系统资源的操作,在多层结构的应用环境中,这种资源的耗费对系统性能影响尤为明显。通过DriverManager获得的数据库连接,一个数据库连接对象均......
  • JDBC
    1.JDBC概述在开发中我们使用的是java语言,那么势必要通过java语言操作数据库中的数据1.1JDBC概念JDBC就是使用Java语言操作关系型数据库的一套API全称:(JavaDat......
  • SpringBoot中使用JDBC(扩展:关于java中的jdbc、数据库驱动、数据库连接池的学习与理解)
    SpringBoot中使用JDBC:https://huaweicloud.csdn.net/63876ea0dacf622b8df8bf7d.html?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7E......
  • ShardingJDBC
    分库分表概念垂直角度(表结构不一样,大结构分多个小结构)垂直分表:将一个表字段拆分多个表,每个表存储部分字段好处:避免IO时锁表的次数,分离热点字段和非热点字段,避免......
  • jmeter jdbc报错Cannot load JDBC driver class 'com.mysql.jdbc.Driver
    下载驱动包mysql-connector-java-5.1.31并放到lib\ext下备注,此驱动包要根据mysql的版本来此版本下载地址 https://pan.baidu.com/s/1-51qV0XPExnOYewz3A1unw 提取......
  • dremio jdbc 客户端简单说明
    dremiojdbc客户端实际上包含了基本上两大类,一个是传统jdbc的,一个是基于apachearrowflightsqljdbc的当前主要说明传统jdbc客户端的,内部上dremio基于了calcite的......
  • JDBC
    JDBC简介javadatabaseconnectivity就是用java语言操作关系型数据库的一套API。jdbc本质就是sun公司定义的一套操作所有关系型数据库的规则,即接口。各个数据库厂商去......
  • 通过JDBC操作数据库时出现中文乱码的问题,Navicat
    问题的发生昨天我帮我同学做了一个前端加后端的项目,使用的是mysql+jdbc+Servlet+jsp技术。但是通过junit测试向数据库插入数据时,插入中文,在Navicat中是以问号显示的。献上......
  • dremio jdbc 客户端简单说明
    dremiojdbc客户端实际上包含了基本上两大类,一个是传统jdbc的,一个是基于apachearrowflightsqljdbc的当前主要说明传统jdbc客户端的,内部上dremio基于了calcite......
  • jdbc简单封装
    构成:1、资源文件db.properties,中存放了驱动类地址、数据库url、用户名、密码。2、jdbc工具类JdbcUtils.java。jdbc工具类中实现了:1、获取数据库连接。......