使用了持久化框架几乎没有使用过原生的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. RSA Encrypting/Decrypting、RSA+AES Encrypting/Decrypting

    catalogue . CryptoAPI介绍 . RSA Encrypting/Decrypting File 1. CryptoAPI介绍 0x1: Cryptography Service Pr ...

  2. idea设置JVM运行参数

    对JVM运行参数进行修改是JVM性能调优的重要手段,下面介绍在应用程序开发过程中JVM参数设置的几种方式. 方式一 java程序运行时指定 -Dproperty=value 该参数通常用于设置系统级全 ...

  3. django - 总结 - cnblog

    1.头像预览 -------方法1-------- 点击头像------>点击input img和input重合; img在label,input-->display:none $(&qu ...

  4. java(9)类和对象

    一.理解什么是类和对象 万事万物皆对象 1.1.属性——对象具有的特征(特点) 1.2.方法——对象可执行的操作(能干什么事) 1.3.对象的定义: 是一个客观存在的,看的见或摸得着的实体,由属性和方 ...

  5. day 17 - 1 递归函数

    递归函数 什么是递归 了解什么是递归 : 在函数中调用自身函数 最大递归深度默认是 997/998 —— 是 python 从内存角度出发做得限制 能看懂递归 能知道递归的应用场景 初识递归 —— 二 ...

  6. BootStrap分页教程

    https://www.cnblogs.com/laowangc/p/8875526.html https://www.cnblogs.com/yinglunstory/p/6092834.html ...

  7. linux服务器安装Mysql后,只能看到information_schema/test这两个库,无法修改密码

    参考链接:https://www.cnblogs.com/ThinkVenus/p/7670722.html 问题背景:登录mysql失败,密码错误,由此想到需要更改密码 然而,进入数据库后,只能看到 ...

  8. liunx系统下调整Swap分区大小

    作者:邓聪聪 添加swap交换空间的步骤如下:第一步:确保系统中有足够的空间来用做swap交换空间,准备在一个独立的文件系统中添加一个swap交换文件,在/tmp中添加1G的swap交换文件第二步:添 ...

  9. 题解-AtCoder Code-Festival2017 Final-J Tree MST

    Problem \(\mathrm{Code~Festival~2017~Final~J}\) 题意概要:一棵 \(n\) 个节点有点权边权的树.构建一张完全图,对于任意一对点 \((x,y)\),连 ...

  10. Lua中的函数

    [前言] Lua中的函数和C++中的函数的含义是一致的,Lua中的函数格式如下: function MyFunc(param) -- Do something end 在调用函数时,也需要将对应的参数 ...