一、事务

  事务是指作为一系列操作组成的一个整体,该整体只有两种状态,要么全部执行,要么全部不执行。

  当组成这个事务的所有语句都执行成功则该事务执行,只要有一条语句执行失败则该事务不执行。

  假设这里有一个insert语句和一个update语句属于一个事务,从宏观上来看,这个事务的状态只有执行或者不执行。

  从微观上看,这个事务是由这两条语句组成的, 每个语句必定有其个体的状态(成功或者不成功)。

  比如可能是insert成功,update失败。也可能是insert失败,update成功。

  当其中只要有一条语句失败,则发送回滚(回到该事务执行前的状态即所有事务都不执行,已成功执行的语句会作废)。

  该事务不执行。如果所有语句都成功,则该事务执行。

  那么事务是如何划分的呢,怎么样算事务的开始,怎么样又算事务的结束呢?

  2.1事务开始

    -连接到数据库上,并执行了一条DML语句(insert、update、delete)。

    -前一个事务结束后,新输入的DML语句。

  2.2事务结束

    -执行commit,或rollback语句。

    -执行一条DDL语句,如create table,这种情况下回自动执行commit语句。

    -执行一条DCL语句,如grant语句,在这种情况下回自动执行commit语句。

    -断开与数据库连接

    -执行一条DML语句出现错误时,在这种情况下为这个无效的语句执行rollback。

    DDL、DCL、DML可参阅:https://www.cnblogs.com/kawashibara/p/8961646.html

    假设这里有五条语句:

      -select

      -insert   ---事务开始---

      -updata

      -delete

      -insert    ---

      commit or DCL or DDL  ---

    结合上面分析,事务从insert开始,如果所有语句都能正常执行,

    那么事务从insert开始,到commit or DCL or DDL结束,这代表一个事务。

    假如其中只要有一条DML语句执行错误,比如第二个insert执行错误,

    那么事务从第一个insert开始,第二个到insert结束。这个事务呈现出一种不执行的状态。

    即insert updata delete insert都不执行,可以看做回到了第一个insert之前的状态(回滚rollback)。

    这里需要用到一个函数:

    void rollback();撤消当前事务中所做的所有更改,并释放此连接对象当前支持的任何数据库锁。

    仅当禁用自动提交模式时才应使用此方法。

    但DML语句出现异常时,我们需要调用此方法达到回滚(回到该事务执行前的状态,即该事务没有执行)。

    

    我们先来看这样一个例子:

    insert(正常执行) --> insert(正常执行) -->commit();

    事务从insert开始,到commit结束。这整个事务是执行的。(测试前最好把表清空下,避免插入重复的主键导致错误)

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement; public class TestJDBC{
public static void main(String[] args){
final String connectionUrl = "jdbc:mysql://localhost:3306/mybatis";
String userName = "root";
String passWord = "123456";
String insertT = "INSERT INTO `mybatis`.`tadd`" //正确的insert语句
+ "(`id`, `tname`, `tpwd`, `tstudentnum`) "
+ "VALUES (?, ?, ?, ?);";
String insertF = "INSERT INTO `mybatis`.`tadd`" //错误的insert语句
+ "(`id`, `tname`, `tpwd`, `tstudentnum`) "
+ "VALUES (?, ?, ?, ?, ?, ?);";
Connection conn = null;
PreparedStatement p1 = null;
PreparedStatement p2 = null; try {
//加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//建立连接
conn = DriverManager.getConnection(connectionUrl,userName,passWord);
conn.setAutoCommit(false);//将自动提交设为false,即不进行自动提交 p1 = conn.prepareStatement(insertT);//第一个insert语句,事务开始(正确的语句)
setParam(p1,"1","1","1","1");
p1.execute();
System.out.println("p1插入完成"); Thread.sleep(5000);//休眠5s p2 = conn.prepareStatement(insertT);//第二个insert语句 (正确的语句)
setParam(p2,"2","2","2","2");
p2.execute();
System.out.println("p2插入完成");
conn.commit();//手动提交 System.out.println("执行成功");
} catch (SQLException e) {
try {
conn.rollback();//事务回滚
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
//依次关闭连接
try{
p1.close();
}catch(Exception e){ }
try{
p2.close();
}catch(Exception e){ }
try{
conn.close();
}catch(Exception e){
}
}
}
public static void setParam(PreparedStatement p,Object... o){
int i = 1;
for(Object temp:o){
try {
p.setObject(i, temp);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
i++;
}
}
}
运行结果:
p1插入完成
p2插入完成
执行成功

p1插入成功后会等待5s,5s之后p2进行插入,到最后commit整个事务的状态是执行的。

我们可以看下数据库中的数据是插入成功的。

    接下来我们去看这样一个例子:

    insert(正常执行) --> insert(执行错误) -->commit();

    事务从insert开始,到错误的insert结束,整个事务是不执行的。

    即第一个insert不执行,第二个insert也不执行。

   (由于测试数据依然采用之前的数据,所以测试前需先将表清空)  

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement; public class TestJDBC{
public static void main(String[] args){
final String connectionUrl = "jdbc:mysql://localhost:3306/mybatis";
String userName = "root";
String passWord = "123456";
String insertT = "INSERT INTO `mybatis`.`tadd`"
+ "(`id`, `tname`, `tpwd`, `tstudentnum`) "
+ "VALUES (?, ?, ?, ?);";
String insertF = "INSERT INTO `mybatis`.`tadd`"
+ "(`id`, `tname`, `tpwd`, `tstudentnum`) "
+ "VALUES (?, ?, ?, ?, ?, ?);";
Connection conn = null;
PreparedStatement p1 = null;
PreparedStatement p2 = null; try {
//加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//建立连接
conn = DriverManager.getConnection(connectionUrl,userName,passWord);
conn.setAutoCommit(false);//将自动提交设为false,即不进行自动提交 p1 = conn.prepareStatement(insertT);//正确的insert语句
setParam(p1,"1","1","1","1");
p1.execute();
System.out.println("p1插入完成"); Thread.sleep(5000); p2 = conn.prepareStatement(insertF);//错误insert的语句
setParam(p2,"2","2","2","2");
p2.execute();
System.out.println("p2插入完成");
conn.commit();//手动提交 System.out.println("执行成功");
} catch (SQLException e) {
try {
conn.rollback();//事务回滚
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
//依次关闭连接
try{
p1.close();
}catch(Exception e){ }
try{
p2.close();
}catch(Exception e){ }
try{
conn.close();
}catch(Exception e){
}
}
}
public static void setParam(PreparedStatement p,Object... o){
int i = 1;
for(Object temp:o){
try {
p.setObject(i, temp);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
i++;
}
}
}
运行结果;
p1插入完成
java.sql.SQLException: No value specified for parameter 5
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:127)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:95)
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
at com.mysql.cj.jdbc.ClientPreparedStatement.execute(ClientPreparedStatement.java:414)
at com.test.jdbc.TestJDBC.main(TestJDBC.java:41)

我们看下数据库中的数据:

我们会发现,即使第一条插入语句执行了,但由于这个事务中第二条insert发生了错误,所以这个事务是不执行的。

10.2(java学习笔记)JDBC事务简述的更多相关文章

  1. Java学习笔记--JDBC数据库的使用

    参考  hu_shengyang的专栏 : http://blog.csdn.net/hu_shengyang/article/details/6290029 一. JDBC API中提供的常用数据库 ...

  2. Java学习笔记——JDBC读取properties属性文件

    Java 中的 properties 文件是一种配置文件,主要用于表达配置信息,文件类型为*.properties,格式为文本文件. 文件的内容是格式是"键=值"(key-valu ...

  3. Java学习笔记——JDBC之与数据库MySQL的连接以及增删改查等操作

    必须的准备工作 一.MySQL的安装.可以参考博文: http://blog.csdn.net/jueblog/article/details/9499245 二.下载 jdbc 驱动.可以从在官网上 ...

  4. JAVA学习笔记 -- JDBC及其应用

    一个.准备工作 1.开放SQL Server服务与支持TCP/IP  进一步确认TCPport watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMjk ...

  5. Java学习笔记——JDBC之PreparedStatement类中“预编译”的综合应用

    预编译 SQL 语句被预编译并存储在 PreparedStatement 对象中.然后可以使用此对象多次高效地执行该语句. 预编译的优点 1.PreparedStatement是预编译的,对于批量处理 ...

  6. 5.10(java学习笔记)容器的同步控制与只读设置

    1.容器的同步控制 像我们平常使用的容器有些是不同步的即线程不安全,例如HashMap等,在多线程时可能出现并发问题. 而有些容器又是同步的,例如Hashtable. 有些时候我们需要将这些不同步的容 ...

  7. 1.10(java学习笔记)super关键字

    supe主要是调用父类中被重写的方法及属性. 用下列代码那说明: package cn.hcf.TestSuper; public class TestSuper { public static vo ...

  8. Java学习之JDBC 2019/3/10

    Java学习之JDBC 大部分的程序都是用来通过处理数据来达到人们预期的效果,数据是粮食,没有数据操作的程序就像helloworld程序一样没有用处.因此数据库操作是重中之重,是程序发挥功能的基石,j ...

  9. Java学习笔记4

    Java学习笔记4 1. JDK.JRE和JVM分别是什么,区别是什么? 答: ①.JDK 是整个Java的核心,包括了Java运行环境.Java工具和Java基础类库. ②.JRE(Java Run ...

  10. 《Java学习笔记(第8版)》学习指导

    <Java学习笔记(第8版)>学习指导 目录 图书简况 学习指导 第一章 Java平台概论 第二章 从JDK到IDE 第三章 基础语法 第四章 认识对象 第五章 对象封装 第六章 继承与多 ...

随机推荐

  1. webstorm中把style的内容隐藏,如何把style的内容展开?

    我们经常看到在webstorm中style的内容以...表示如下图所示,只有把光标移到上面时才会看到内容: 如何把上述的style的内容展开呢? 请按一下步骤操作: 第一步:File------> ...

  2. AWS nat monitor and route switch script

    This script will monitor another NAT instance and take over its routes if communication with the oth ...

  3. 通过js修改微信内置浏览器title

    document.setTitle = function(t) { document.title = t; var i = document.createElement('iframe'); i.sr ...

  4. MyBatis对象关联关系----多对多的保存与查询

    模拟情景: 对象:学生,课程 关系:一个学生可选多个课程,一门课程可被多个学生选择 一.保存 1.创建数据库表,student,course,student_course,其中student_cour ...

  5. 【HDU5772】String Problem [网络流]

    String Problem Time Limit: 10 Sec  Memory Limit: 64 MB[Submit][Status][Discuss] Description Input Ou ...

  6. 【Foreign】异色弧 [树状数组]

    异色弧 Time Limit: 20 Sec  Memory Limit: 256 MB Description Input Output 仅一行一个整数表示答案. Sample Input 8 1 ...

  7. 服务器应用程序不可用,由于无法创建应用程序域,因此未能执行请求。错误: 0x80070002 系统找不到指定的文件。

    使用360更新网站补丁导致.net2.0环境报错问题现象:服务器应用程序不可用查看日志:出现由于无法创建应用程序域,因此未能执行请求.错误: 0x80070002 系统找不到指定的文件. 搜索定位:罪 ...

  8. Linux 的源码安装工具 CheckInstall

    Linux 的源码安装工具 CheckInstall Checkinstall 是一个能从 tar.gz 类的 https://www.ibm.com/developerworks/cn/linux/ ...

  9. javascript的有效校验

    //年月日期有效性检验 function yearAndMonthCheck() { var flag = true; var currentyear = new Date().getFullYear ...

  10. 手机端图片插件可缩放 旋转 全屏查看photoswipe

    官方介绍PhotoSwipe 是专为移动触摸设备设计的相册/画廊.兼容所有iPhone.iPad.黑莓6+,以及桌面浏览器.底层实现基于HTML/CSS/JavaScript,是一款免费开源的相册产品 ...