使用了持久化框架几乎没有使用过原生的jdbc API ,发现原来使用jdbc API来实现事务也是很简单的。

数据库的链接connection具有一个属性autocommit,这个属性默认是true,作用是控制是否把执行的命令提交给数据库。一旦命令被提交就无法回滚数据库。

而我们实现事务的方式也是很简单,就是手动设置属性autocommit的值为false,等执行完全部命令之后再手动提交所有命令就可以了。

try (Connection connection = DriverManager.getConnection(url, username, password)) {
System.out.println("数据库链接成功!"); try (Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY)) {
String command = "insert into a_dept(name) values('1'),('2')";
int count = statement.executeUpdate(command);
System.out.println("受影响行数:" + count); String selectSql = "select * from a_dept";
String updateSql = "update a_dept set name=? where id=?";
String insertSql = "insert into a_dept(name) values(?)";
try (ResultSet resultSet = statement.executeQuery(selectSql)) {
while (resultSet.next()) {
System.out.print("修改前id " + resultSet.getInt("id") + "的值是: ");
System.out.println(resultSet.getString("name"));
}
resultSet.beforeFirst();
connection.setAutoCommit(false);
while (resultSet.next()) {
PreparedStatement updateState = connection.prepareStatement(updateSql);
updateState.setString(1, "I am new" + resultSet.getInt("id"));
updateState.setInt(2, resultSet.getInt("id"));
updateState.executeUpdate();
} // Savepoint savepoint = connection.setSavepoint();
PreparedStatement updateState = connection.prepareStatement(insertSql);
updateState.setString(1, "我是插入的");
updateState.executeUpdate();
try {
PreparedStatement updateStateFail = connection.prepareStatement(insertSql);
updateStateFail.setString(1, "我是插入的,但是我太长了,所以我是插不进去的,会报错!");
updateStateFail.executeUpdate(); } catch (Exception e) {
connection.rollback();
System.err.println(e.getMessage());
}
connection.commit();
Statement newStatement = connection.createStatement();
ResultSet newSet = newStatement.executeQuery(selectSql);
System.out.println("打印出所有的值:");
while (newSet.next()) {
System.out.print(newSet.getInt("id") + ": ");
System.out.println(newSet.getString("name"));
}
}
}
}

  贴运行结果:

红色字体就是报错的信息。我们可以发现,在这个结果集当中没有进行修改,也没有进行插入,所有的修改和插入命令因为插入操作的错误都被回滚了。

但是我们发现我们的修改操作和插入操作都被回滚了,这在一些情况下我们不希望所有的操作都被回滚,那么我们可以设置回滚的节点,设置回滚的节点也很简单,在想要的地方添加如下代码,

Savepoint savepoint = connection.setSavepoint();

那么就会在该地生成一个节点,回滚把这个节点作为参数传递给回滚的方法 rollback() ,那么回滚的时候会放过该节点之前的操作,需要注意的是节点使用完之后必须释放它。

结果如下(不要在意Id亲,我清了数据库了):
Connected to the target VM, address: '127.0.0.1:17576', transport: 'socket'
数据库链接成功!
受影响行数:2
修改前id 479的值是: 1
修改前id 480的值是: 2
Data truncation: Data too long for column 'name' at row 1
打印出所有的值:
479: I am new479
480: I am new480
Disconnected from the target VM, address: '127.0.0.1:17576', transport: 'socket'

简单吧:

最后附上使用节点回滚的全部代码,可以不看~:

        try (Connection connection = DriverManager.getConnection(url, username, password)) {
System.out.println("数据库链接成功!"); try (Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY)) {
String command = "insert into a_dept(name) values('1'),('2')";
int count = statement.executeUpdate(command);
System.out.println("受影响行数:" + count); String selectSql = "select * from a_dept";
String updateSql = "update a_dept set name=? where id=?";
String insertSql = "insert into a_dept(name) values(?)";
try (ResultSet resultSet = statement.executeQuery(selectSql)) {
while (resultSet.next()) {
System.out.print("修改前id " + resultSet.getInt("id") + "的值是: ");
System.out.println(resultSet.getString("name"));
}
resultSet.beforeFirst();
connection.setAutoCommit(false);
while (resultSet.next()) {
PreparedStatement updateState = connection.prepareStatement(updateSql);
updateState.setString(1, "I am new" + resultSet.getInt("id"));
updateState.setInt(2, resultSet.getInt("id"));
updateState.executeUpdate();
} Savepoint savepoint = connection.setSavepoint();
PreparedStatement updateState = connection.prepareStatement(insertSql);
updateState.setString(1, "我是插入的");
updateState.executeUpdate();
try {
PreparedStatement updateStateFail = connection.prepareStatement(insertSql);
updateStateFail.setString(1, "我是插入的,但是我太长了,所以我是插不进去的,会报错!");
updateStateFail.executeUpdate(); } catch (Exception e) {
connection.rollback(savepoint);
               connection.releaseSavepoint(savepoint);
System.err.println(e.getMessage());
}
connection.commit();
Statement newStatement = connection.createStatement();
ResultSet newSet = newStatement.executeQuery(selectSql);
System.out.println("打印出所有的值:");
while (newSet.next()) {
System.out.print(newSet.getInt("id") + ": ");
System.out.println(newSet.getString("name"));
}
}
}
}

  

JDBC API 事务的实践的更多相关文章

  1. JDBC、事务和连接池

    一:JDBC 1.什么是JDBC JDBC(Java Data Base Connectivity)SUN公司提供的一套操作数据库的标准规范.具体来讲是一种用于执行SQL语句的Java API,为多种 ...

  2. [疯狂Java]JDBC:事务管理、中间点、批量更新

    1. 数据库事务的概念:     1) 事务的目的就是为了保证数据库中数据的完整性.     2) 设想一个银行转账的过程,假设分两步,第一步是A的账户-1000,第二步是B的账户+1000.这两个动 ...

  3. 二十 Spring的事务管理及其API&事务的传播行为,编程式&声明式(xml式&注解式,底层AOP),转账案例

    Spring提供两种事务方式:编程式和声明式(重点) 前者需要手写代码,后者通过配置实现. 事务的回顾: 事务:逻辑上的一组操作,组成这组事务的各个单元,要么全部成功,要么全部失败 事务的特性:ACI ...

  4. Spring中的JDBC API

    1 JdbcTemplate的诞生 JDBC作为Java平台访问关系数据库的标准API,其成功是有目共睹的.为了避免在JDBC API在使用中的种种尴尬局面(几乎程式一样的代码,繁琐的异常处理),Sp ...

  5. JDBC基础:JDBC快速入门,JDBC工具类,SQL注入攻击,JDBC管理事务

    JDBC基础 重难点梳理 一.JDBC快速入门 1.jdbc的概念 JDBC(Java DataBase Connectivity:java数据库连接)是一种用于执行SQL语句的Java API,可以 ...

  6. Spring框架——JDBC与事务管理

    JDBC JDBCTemplate简介 XML配置JDBCTemplate 简化JDBC模板查询 事务管理 事务简介 Spring中的事务管理器 Spring中的事务管理器的不同实现 用事务通知声明式 ...

  7. RESTful API 设计最佳实践

    背景 目前互联网上充斥着大量的关于RESTful API(为了方便,以后API和RESTful API 一个意思)如何设计的文章,然而却没有一个"万能"的设计标准:如何鉴权?API ...

  8. JDBC API Description

    package java.sql description What the JDBCTM 4.2 API Includes Versions What the java.sql Package Con ...

  9. Spring总结——AOP、JDBC和事务的总结

    1.上一次总结了 Spring 的核心三大组件(Core,Beans,Context),今天总结的 AOP.JDBC和事务都可以看成是核心三大组件的应用. 其中 Spring 的事务管理又以 AOP ...

随机推荐

  1. CMDB服务器管理系统【s5day90】:创建资产更新服务器硬盘信息

    1.创建硬件资产信息 import json from django.shortcuts import render,HttpResponse from django.views.decorators ...

  2. MongoDB3.6 一键化自动部署方案

    1.系统基础配置 下面的命令默认都使用root用户进行操作,操作系统为Centos7,mongodb3.6.x以上版本 1.1 修改系统配置文件/etc/security/limits.conf和/e ...

  3. 程序通过ReportViewer对象来调用reporting services并导出pdf文件

    ReportViewer tempReportViewer = new ReportViewer(); tempReportViewer.ProcessingMode = ProcessingMode ...

  4. 激活函数——sigmoid函数(理解)

    0 - 定义 $Sigmoid$函数是一个在生物学中常见的S型函数,也称为$S$型生长曲线.在信息科学中,由于其单增以及反函数单增等性质,$Sigmoid$函数常被用作神经网络的阈值函数,将变量映射到 ...

  5. 关于模拟I2C的一些问题???

    1.在调试BH1750时发现stm32f103rb单片机用模拟I2C通讯时引脚使用开漏模式能正常读出来数据,使用推挽模式则完全无法通讯,发送地址后从机没有应答? https://blog.csdn.n ...

  6. (转)Java代码书写规范

    0. 安装阿里代码规范的eclipse插件 https://www.cnblogs.com/caer/p/7753522.html 1.基本原则 强制性原则:     1.字符串的拼加操作,必须使用S ...

  7. PGCD2 - Primes in GCD Table (Hard)

    这题肝了三四天,其他啥也没做... 传送门 然后...双倍经验 简单版 不知道为什么会脑抽去帮 LZ_101 大佬验题... 题目和被 A 穿的 PGCD 一样,数据范围变成大概 2e11 ... 于 ...

  8. 【easy】112.path sum 113.-----------------

    求是否有从根到叶的路径,节点和等于某个值. /** * Definition for a binary tree node. * struct TreeNode { * int val; * Tree ...

  9. RTF文件格式

    文档地址 首先给出一个生成最简单的RTF文件的脚本 f=open('hello_world.rtf','w') padding='{\\rtf1\\ansi' padding+=' Hello Wor ...

  10. C# ClickOnce部署WinForm程序

    之前做过ClickOnce部署应用程序的项目,今天做一次全面的总结.那么这些都是微软提供方便分布式部署的相关解决方法,这种方法既有弊端,也有优点. 最大的缺点: 远程部署,不能更换安装目录:并且每次安 ...