使用JDBC进行数据库的事务操作(2)
本篇将讲诉如何使用JDBC进行数据库有关事务的操作。在上一篇博客中已经介绍了事务的概念,和在MySQL命令行窗口进行开启事务,提交事务以及回滚事务的操作。
似乎事务和批处理都可以一次同时执行多条SQL命令,但是事务是如果某一条SQL出错,则前面已经执行过的SQL全部都将回滚;而批处理中某一条SQL出错,那么这条出错的SQL要么会抛出个异常,要么以一个代表出错的值返回,已经执行过的SQL不受影响,至于后面的SQL是否还会执行则看数据库,不同数据库有不同的处理。
在前一篇我们说过,数据库对于事务是默认自动提交的,也就是发一条SQL命令则数据库就执行一条。而对于JDBC而言,当向数据库获取一个链接Connection对象,在默认情况下通过Connection对象发送的SQL命令也是默认自动提交事务的。
操作:
① 如果我们想使用JDBC对多条SQL进行整体执行,需要先提交事务命令,这一步是通过Connection对象先将自动提交关闭,调用Connection对象的setAutoCommit(false)方法即可。这个方法相当于在MySQL命令行窗口中输入”start transaction”命令。
② 如果我们在JDBC已经将自动提交关闭的情况下需要提交事务,则调用Connection对象的commit()方法即可。
③ 如果我们在JDBC已经将自动提交关闭的情况下需要回滚事务,则调用Connection对象的rollback(…)方法即可。rollback方法如果是无参,则回滚前面所有已执行的SQL命令;如果是有参,则可以指定回滚点,保留前面部分指定的已执行的SQL命令。
下面以几个案例来像上一篇博客一样分别介绍几种事务的相关操作。
例1:正确提交事务的小案例
在这个简单的案例中,通过用户A向用户B转账100元来快速了解如何使用JDBC操作事务。
创建数据库和表,另外再添加两条数据:
create database jdbcdemo;
use jdbcdemo;
create table account(
id int primary key auto_increment,
name varchar(40),
money double
);
insert into account(name,money) values('a',1000);
insert into account(name,money) values('b',1000);
先看看准备的数据:

创建工程,在工程中导入数据库连接驱动的jar包。在【src】目录下新建一个database.properties文件,内容如下:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcdemo
username=root
password=root
构建JDBC的工具类,包括注册驱动,获取连接,释放资源和连接等,这部分同《JDBC操作数据库的学习(2)》中相同,此处略。
使用JDBC完成事务操作的demo代码如下:
public void transaction() throws SQLException {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try{
conn = JdbcUtils.getConnection();
conn.setAutoCommit(false); //开启事务,相当于start transaction命令
String sql1 = "update account set money=money-100 where name='a'";
st = conn.prepareStatement(sql1);
st.executeUpdate(); //执行SQL语句
String sql2 = "update account set money=money+100 where name='b'";
st = conn.prepareStatement(sql2);
st.executeUpdate(); //执行SQL语句
conn.commit(); //提交事务
}finally{
JdbcUtils.release(conn, st, rs);
}
}
查看事务执行情况:

通过例1中简单的代码就完成了事务的一系列操作。可以看到用户A向用户B确实转账了100元。
例2:事务执行过程出错回滚的小案例
通过前一篇博客,我们知道如果在事务执行过程中发生了错误,则数据库将会使该事务中所有的操作都回滚,那么我们在使用JDBC的情况下也来重新模拟一次,依然还是用户A向用户B转账100元。
将例1中的account表所有用户的金额重新制定为1000元的SQL命令:
update account set money=1000;

创建工程,在工程中导入数据库连接驱动的jar包。在【src】目录下新建一个database.properties文件,内容如下:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcdemo
username=root
password=root
构建JDBC的工具类,包括注册驱动,获取连接,释放资源和连接等,这部分同《JDBC操作数据库的学习(2)》中相同,此处略。
在使用JDBC进行事务处理中,我们添加一个显而易见的错误:int x = 1/0 ,如下代码:
public void transaction() throws SQLException {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try{
conn = JdbcUtils.getConnection();
conn.setAutoCommit(false); //开启事务,相当于start transaction命令
String sql1 = "update account set money=money-100 where name='a'";
st = conn.prepareStatement(sql1);
st.executeUpdate();
int x = 1/0; //在此处模拟事务处理过程中出错
String sql2 = "update account set money=money+100 where name='b'";
st = conn.prepareStatement(sql2);
st.executeUpdate();
conn.commit(); //提交事务
}finally{
JdbcUtils.release(conn, st, rs);
}
}
当我们执行这个Java方法时,由于设置了int x = 1/0这个逻辑错误,程序会抛出异常,但是因为抛出异常后,后面的代码不再执行,也就是说程序无法执行到提交事务conn.commit()方法处,因此数据库将会回滚该事务所有的操作,因此A与B的金额还是原来那样:

例3:事务执行过程出错由开发者手动回滚的小案例
在例2中当事务执行过程中出错时,会由数据库自动回滚所有的操作,而在JDBC中,我们也可以调用链接Connection对象的rollback()方法回滚所有的操作,在下面的案例中,我们将在捕获异常的代码块中手动回滚所有的操作。
所有表、表中数据、配置文件和JDBC工具类都同例2相同。
将例2中的代码修改为如下:
public void transaction() throws SQLException {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try{
conn = JdbcUtils.getConnection();
conn.setAutoCommit(false); //开启事务,相当于start transaction命令
String sql1 = "update account set money=money-100 where name='a'";
st = conn.prepareStatement(sql1);
st.executeUpdate();
int x = 1/0; //在此处模拟事务处理过程中出错
String sql2 = "update account set money=money+100 where name='b'";
st = conn.prepareStatement(sql2);
st.executeUpdate();
conn.commit(); //提交事务
}catch (Exception e) {
e.printStackTrace();
conn.rollback(); //手动回滚该事务中所有的操作
}finally{
JdbcUtils.release(conn, st, rs);
}
}
效果和例2也是一样的,事务出错则回滚所有的操作。
例4:指定事务回滚点的案例
例3的手动回滚其实有些鸡肋,与其说是手动回滚,其实即使没有调用rollback该事务就不会执行成功,而rollback方法更高级的功能在于能回滚到指定的地方。
通过链接Connection对象的setSavepoint()方法即可在该方法所在的位置设置回滚点对象,当调用rollback(回滚点对象)方法即可将事务回滚到这个位置。这样在执行回滚之后,再次调用提交事务(Commit),则回滚点之前的SQL还是执行的。
以例2为前提,我们在会发生异常地方的前面设置回滚点,而使第一条SQL语句能被执行,即用户A的操作能执行(减少100),用户B的操作不能执行(金额不变)。
所有表、表中数据、配置文件和JDBC工具类都同例2相同。
将例2中的代码修改为如下:
public void transaction() throws SQLException {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
Savepoint sp = null; //代表回滚点对象
try{
conn = JdbcUtils.getConnection();
conn.setAutoCommit(false); //开启事务,相当于start transaction命令
String sql1 = "update account set money=money-100 where name='a'";
st = conn.prepareStatement(sql1);
st.executeUpdate();
sp = conn.setSavepoint(); //在此处设置回滚点
int x = 1/0; //在此处模拟事务处理过程中出错
String sql2 = "update account set money=money+100 where name='b'";
st = conn.prepareStatement(sql2);
st.executeUpdate();
conn.commit(); //提交事务
}catch (Exception e) {
conn.rollback(sp); //回滚到指定的回滚点处
conn.commit(); //回滚之后再次提交事务保证回滚点之前的SQL能被执行
}finally{
JdbcUtils.release(conn, st, rs);
}
}
查看事务执行情况:

可以看到结果正如我们希望的那样,由于用户A的操作在回滚点之前,又因为执行回滚之后还执行了提交事务,因此回滚点之前的SQL命令还是可以被执行成功的。因此切记,要想使用回滚点,一定要在回滚之后再次提交事务,否则设置回滚点是没有意义的。
下图是一张上面例子的执行流程:

使用JDBC进行数据库的事务操作(2)的更多相关文章
- 使用JDBC进行数据库的事务操作(1)
本篇讲述数据库中非常重要的事务概念和如何使用MySQL命令行窗口来进行数据库的事务操作.下一篇会讲述如何使用JDBC进行数据库的事务操作. 事务是指数据库中的一组逻辑操作,这个操作的特点就是在该组逻辑 ...
- 使用JDBC对数据库实现批处理操作
本篇讲述如何使用JDBC对数据库实现批处理操作.很多时候单条SQL命令不能满足我们的需求,我们需要对数据库一次实现很多操作,需要发送一批SQL命令给数据库执行. 而JDBC也提供了相应的方法给我们实现 ...
- 第二百八十六节,MySQL数据库-MySQL事务操作(回滚)
MySQL数据库-MySQL事务操作(回滚) 事务用于将某些操作的多个SQL作为原子性操作,一旦有某一个出现错误,即可回滚到原来的状态,从而保证数据库数据完整性. 举例:有这样一张表 从表里可以看出张 ...
- JDBC对数据库的简单操作
/** * 获取数据库连接 */ public Connection GetConnection(){ Connection connection=null; try { Class.forName( ...
- day18-事务与连接池 3.jdbc中事务操作介绍
那么我们都是通过程序操作数据库.所以要了解jdbc下怎样对事务操作.jdbc如何操作事务? 自动事务false那就不开了呗相当于开启事务. package cn.itcast.transaction; ...
- Django的ORM实现数据库事务操作
在Django中实现数据库的事务操作 在学习MySQL数据库时,MySQL数据库是支持原子操作的. 什么是数据库的原子操作呢??打个比方,一个消费者在一个商户里刷信用卡消费. 交易正常时,银行在消费者 ...
- 遇过的坑(2)—MyISAM表类型不支持事务操作
最近需要通过JDBC对数据库做事务型操作,实践时发现,并没有达到想要的效果,表现在:1.每次执行executeUpdate()后,数据就马上能在DB中查到.但按理来说,我还没执行commit(),DB ...
- 数据库中事务的四大特性(ACID)
本篇讲诉数据库中事务的四大特性(ACID),并且将会详细地说明事务的隔离级别. 如果一个数据库声称支持事务的操作,那么该数据库必须要具备以下四个特性: ⑴ 原子性(Atomicity) 原子性是指事务 ...
- Spring中的事务操作
事务的特性 原子性:强调事务的不可分割. 一致性:事务的执行的前后数据的完整性保持一致. 隔离性:一个事务执行的过程中,不应该受到其他事务的干扰. 持久性:事务一旦结束,数据就持久化到数据库. 如果不 ...
随机推荐
- BZOJ 3544: [ONTAK2010]Creative Accounting( BST )
题意 : 一段序列 , 求一段子序列和取余 M 的最大值 其实是一道水题... 前缀和 , 然后就是找 ( sum( r ) - sum( l ) ) % M 的最大值 . 考虑一个 sum( r ) ...
- Group DataList
一,效果图. 二,源代码. <!DOCTYPE html><html><head> <meta charset="UTF-8"> & ...
- String类的一些方法
String 类有以下方法: startsWith(String prefix) boolean java.lang.String.startsWith(String prefix) Tests if ...
- JAVA的一些小笔记
构造块优先于构造方法执行,而且每当有一个新的实例化对象产生时,就会重复执行构造块的程序. 静态块优先于构造块执行,而且不管有多少个实例化对象产生,静态块只会执行一次,它的主要作用是为类中的static ...
- BAAS
http://blogs.embarcadero.com/sarinadupont/category/baas-tutorials/?cid=701G0000000vH0A&elq=51f98 ...
- 为什么要用BASE64
BASE64和其他相似的编码算法通常用于转换二进制数据为文本数据,其目的是为了简化存储或传输.更具体地说,BASE64算法主要用于转换二进 制数据为ASCII字符串格式.Java语言提供了一个非常好的 ...
- matlab绘图方法汇总
Matlab画图 强大的画图功能是Matlab的特点之中的一个,Matlab提供了一系列的画图函数,用户不须要过多的考虑画图的细节,仅仅须要给出一些基本參数就能得到所需图形,这类函数称为高层画图函数. ...
- POJ2485——Highways
Description The island nation of Flatopia is perfectly flat. Unfortunately, Flatopia has no public h ...
- SystemTap----将SystemTap脚本编译成内核模块
当运行SystemTap脚本时,会根据脚本生成一个内核模块,然后插入到系统中执行后退出.这个过程总共分为5个阶段:parse, elaborate, translate, compile, run ...
- Java中的异常详解
一.异常定义 阻止当前方法或作用域继续执行的问题,称为异常 二.异常分析 所有不正常类都继承Throwable类,这个类主要有两个子类Error类和Exception类.Error指系统错误 ...