目录

  1 Connection中的重用方法

  2 JDBC事务管理经典案例

1 Connection类中常用的方法回顾

  1.1 Statement createStatement() throws SQLException;

    创建一个Statement实例(即:创建一个SQL执行对象)

  1.2 PreparedStatement prepareStatement(String sql) throws SQLException;

    创建一个PreparedStatement对象(即:创建一个预编译SQL执行对象)

  1.3 void setAutoCommit(boolean autoCommit) throws SQLException;

    设置事务的自动提交(false为关闭自动提交,true为启动自动提交)

  1.4 void commit() throws SQLException;

    手动提交事务

  1.5 void rollback() throws SQLException;

    手动回滚事务

2 需要用到事务回滚的经典案例:银行转账案例

  转出和转入是一个事务,如果转出成功但是转入失败的会就需要进行事务回滚,否则就出出现转出者余额减少但是转入者余额没有增加

  注意:事务的提交与回滚是通过Connection提供的方法来调用的;本质上事务还是依赖数据库的实现;Connection的方法实质上也是调用了数据库事务机制.

  2.1 不使用事务控制的转账业务

    缺点:如果转入成功,但是转入失败的话,会造成转出者余额减少,但是转入者余额不变

    项目结构图

      

 package cn.xiangxu.entity;

 import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.Scanner; import cn.xiangxu.tools.DBUtil; public class Test {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入转出用户名:");
String outName = scanner.nextLine();
System.out.println("请输入需要转出的资金额度:");
Double money = Double.parseDouble(scanner.nextLine());
System.out.println("请输入转入用户名:");
String inName = scanner.nextLine();
System.out.println("转出账户为:" + outName + "转出金额为:" + money + "转入账户为:" + inName); Connection conn = null;
try {
conn = DBUtil.getConnection(); // 实例化连接对象 // conn.setAutoCommit(false); // 关闭自动提交事务功能 String sql = "UPDATE client "
+ "SET account = account - ? "
+ "WHERE name = ? ";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setDouble(1, money);
ps.setString(2, outName);
Integer rs = ps.executeUpdate();
if(rs > 0) {
System.out.println("转出成功");
} else {
System.out.println("转出失败");
return; // 转出失败跳出函数,不再执行下面的语句;但是finally中的语句还是会执行的,因为就算天塌下来finally中的语句都会执行
} System.out.println("======分割线======="); String sql_in = "UPDATE client "
+ "SET account = account + ? "
+ "WHERE name = ? ";
PreparedStatement ps_in = conn.prepareStatement(sql_in);
ps_in.setDouble(1, money);
ps_in.setString(2, inName);
Integer judge_in = ps_in.executeUpdate();
if(judge_in > 0) {
System.out.println("转入成功");
// conn.commit(); // 转出、转入都成功就提交事务
} else {
System.out.println("转入失败");
// conn.rollback(); // 转出成功、转入失败就回滚事务
} // conn.setAutoCommit(true); // 打开自动提交事务 } catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
System.out.println("我是finally中的语句哟");
try {
DBUtil.closeConnection();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

转账业务java源代码

 CREATE TABLE client  (
id INT (10) PRIMARY KEY,
name VARCHAR (10),
pwd VARCHAR (10),
account INT (20)
);

SQL语句

 package cn.xiangxu.tools;

 import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties; import org.apache.commons.dbcp.BasicDataSource; public class DBUtil {
/*
* ThreadLocal用于线程跨方法共享数据使用
* ThreadLocal内部有一个Map, key为需要共享数据的线程本身,value就是其需要共享的数据
*/
private static ThreadLocal<Connection> tl; // 声明一个类似于仓库的东西
private static BasicDataSource dataSource; // 声明一个数据库连接池对象 // 静态代码块,在类加载的时候执行,而且只执行一次
static {
tl = new ThreadLocal<Connection>(); // 实例化仓库对象
dataSource = new BasicDataSource(); // 实例数据库连接池对象 Properties prop = new Properties(); // 创建一个Properties对象用(该对象可以用来加载配置文件中的属性列表)
InputStream is = DBUtil.class.getClassLoader().getResourceAsStream("config/mysql.properties"); // 读取配置文件信息
try {
prop.load(is); // 加载配置文件中的属性列表 String driverClassName = prop.getProperty("driverClassName"); // 获取属性信息
String url = prop.getProperty("url");
String username = prop.getProperty("username");
String password = prop.getProperty("password");
Integer maxActive = Integer.parseInt(prop.getProperty("maxActive"));
Integer maxWait = Integer.parseInt(prop.getProperty("maxWait")); dataSource.setDriverClassName(driverClassName); // 初始化数据库连接池(即:配置数据库连接池的先关参数)
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setMaxActive(maxActive);
dataSource.setMaxWait(maxWait); is.close(); // 关闭输入流,释放资源
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} } /**
* 创建连接对象(注意:静态方法可以直接通过类名来调用)
* @return 连接对象
* @throws Exception
*/
public static Connection getConnection() throws Exception {
try {
Connection conn = dataSource.getConnection(); // 创建连接对象(利用数据库连接池进行创建)
tl.set(conn); // 将连接对象放到仓库中
return conn;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw e;
}
} /**
* 关闭连接对象(注意:静态方法可以通过类名直接调用)
* @throws Exception
*/
public static void closeConnection() throws Exception {
Connection conn = tl.get(); // 从仓库中取出连接对象
tl.remove(); // 清空仓库
if(conn != null) { // 判断连接对象是否释放资源
try {
conn.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw e;
}
}
} }

数据库连接池的java源代码

 # zhe shi zhu shi , yi ban bu yong zhong wen
# deng hao liang bian mei you kong ge, mo wei mei you fen hao
# hou mian bu neng you kong ge
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test
username=root
password=182838
maxActive=100
maxWait=3000

数据库信息文件

 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.xiangxu</groupId>
<artifactId>testJDBC</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.37</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
</project>

maven依赖文件

  2.2 利用事务控制的转账业务

 package cn.xiangxu.entity;

 import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Scanner; import cn.xiangxu.tools.DBUtil; public class Test {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入转出用户名:");
String outName = scanner.nextLine();
System.out.println("请输入需要转出的资金额度:");
Double money = Double.parseDouble(scanner.nextLine());
System.out.println("请输入转入用户名:");
String inName = scanner.nextLine();
System.out.println("转出账户为:" + outName + "转出金额为:" + money + "转入账户为:" + inName); Connection conn = null;
try {
conn = DBUtil.getConnection(); // 实例化连接对象 conn.setAutoCommit(false); // 关闭自动提交事务功能 String sql = "UPDATE client "
+ "SET account = account - ? "
+ "WHERE name = ? ";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setDouble(1, money);
ps.setString(2, outName);
Integer rs = ps.executeUpdate();
if(rs > 0) {
System.out.println("转出成功");
} else {
System.out.println("转出失败");
return; // 转出失败跳出函数,不再执行下面的语句;但是finally中的语句还是会执行的,因为就算天塌下来finally中的语句都会执行
} System.out.println("======分割线======="); String sql_in = "UPDATE client "
+ "SET account = account + ? "
+ "WHERE name = ? ";
PreparedStatement ps_in = conn.prepareStatement(sql_in);
ps_in.setDouble(1, money);
ps_in.setString(2, inName);
Integer judge_in = ps_in.executeUpdate();
if(judge_in > 0) {
System.out.println("转入成功");
conn.commit(); // 转出、转入都成功就提交事务
} else {
System.out.println("转入失败");
conn.rollback(); // 转出成功、转入失败就回滚事务
} conn.setAutoCommit(true); // 打开自动提交事务 } catch (Exception e) {
// TODO Auto-generated catch block
try {
conn.rollback(); // 捕获到异常后也需要进行事务回滚
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
e.printStackTrace();
} finally {
System.out.println("我是finally中的语句哟");
try {
DBUtil.closeConnection();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

转账业务的java源代码

  2.3 将关闭自动提交功能、手动提交功能、手动回滚功能封装到一个类中

 package cn.xiangxu.tools;

 import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties; import org.apache.commons.dbcp.BasicDataSource; public class DBUtil {
/*
* ThreadLocal用于线程跨方法共享数据使用
* ThreadLocal内部有一个Map, key为需要共享数据的线程本身,value就是其需要共享的数据
*/
private static ThreadLocal<Connection> tl; // 声明一个类似于仓库的东西
private static BasicDataSource dataSource; // 声明一个数据库连接池对象 // 静态代码块,在类加载的时候执行,而且只执行一次
static {
tl = new ThreadLocal<Connection>(); // 实例化仓库对象
dataSource = new BasicDataSource(); // 实例数据库连接池对象 Properties prop = new Properties(); // 创建一个Properties对象用(该对象可以用来加载配置文件中的属性列表)
InputStream is = DBUtil.class.getClassLoader().getResourceAsStream("config/mysql.properties"); // 读取配置文件信息
try {
prop.load(is); // 加载配置文件中的属性列表 String driverClassName = prop.getProperty("driverClassName"); // 获取属性信息
String url = prop.getProperty("url");
String username = prop.getProperty("username");
String password = prop.getProperty("password");
Integer maxActive = Integer.parseInt(prop.getProperty("maxActive"));
Integer maxWait = Integer.parseInt(prop.getProperty("maxWait")); dataSource.setDriverClassName(driverClassName); // 初始化数据库连接池(即:配置数据库连接池的先关参数)
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setMaxActive(maxActive);
dataSource.setMaxWait(maxWait); is.close(); // 关闭输入流,释放资源
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} } /**
* 创建连接对象(注意:静态方法可以直接通过类名来调用)
* @return 连接对象
* @throws Exception
*/
public static Connection getConnection() throws Exception {
try {
Connection conn = dataSource.getConnection(); // 创建连接对象(利用数据库连接池进行创建)
tl.set(conn); // 将连接对象放到仓库中
return conn;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw e;
}
} /**
* 关闭连接对象(注意:静态方法可以通过类名直接调用)
* @throws Exception
*/
public static void closeConnection() throws Exception {
Connection conn = tl.get(); // 从仓库中取出连接对象
tl.remove(); // 清空仓库
if(conn != null) { // 判断连接对象是否释放资源
try {
conn.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw e;
}
}
} /**
* 在执行SQL语句前关闭JDBC的自动提交事务功能
* @throws SQLException
*/
public static void tansBegin() throws SQLException {
try {
tl.get().setAutoCommit(false); // 从仓库中获取连接对象并调用setAutoCommit来关闭自动提交事务功能
} catch(SQLException e) {
e.printStackTrace();
throw e;
}
} /**
* 手动回滚功能
* @throws SQLException
*/
public static void transBack() throws SQLException {
tl.get().rollback(); // 从仓库中获取连接对象并调用rollback来实现事务回滚操作
tl.get().setAutoCommit(true); // 回滚启动事务自动提交功能
} /**
* 手动提交功能
* @throws SQLException
*/
public static void transCommit() throws SQLException {
tl.get().commit(); // 从仓库中获取连接对象并调用commit来实现事务提交操作
tl.get().setAutoCommit(true); // 提交后启动事务自动提交功能
} }

DBUtil

 package cn.xiangxu.entity;

 import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Scanner; import cn.xiangxu.tools.DBUtil; public class Test {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入转出用户名:");
String outName = scanner.nextLine();
System.out.println("请输入需要转出的资金额度:");
Double money = Double.parseDouble(scanner.nextLine());
System.out.println("请输入转入用户名:");
String inName = scanner.nextLine();
System.out.println("转出账户为:" + outName + "转出金额为:" + money + "转入账户为:" + inName); Connection conn = null;
try {
conn = DBUtil.getConnection(); // 实例化连接对象 DBUtil.tansBegin(); // 关闭自动提交事务功能 String sql = "UPDATE client "
+ "SET account = account - ? "
+ "WHERE name = ? ";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setDouble(1, money);
ps.setString(2, outName);
Integer rs = ps.executeUpdate();
if(rs > 0) {
System.out.println("转出成功");
} else {
System.out.println("转出失败");
return; // 转出失败跳出函数,不再执行下面的语句;但是finally中的语句还是会执行的,因为就算天塌下来finally中的语句都会执行
} System.out.println("======分割线======="); String sql_in = "UPDATE client "
+ "SET account = account + ? "
+ "WHERE name = ? ";
PreparedStatement ps_in = conn.prepareStatement(sql_in);
ps_in.setDouble(1, money);
ps_in.setString(2, inName);
Integer judge_in = ps_in.executeUpdate();
if(judge_in > 0) {
System.out.println("转入成功");
DBUtil.transCommit(); // 转出、转入都成功就提交事务
} else {
System.out.println("转入失败");
DBUtil.transBack(); // 转出成功、转入失败就回滚事务
} } catch (Exception e) {
// TODO Auto-generated catch block
try {
DBUtil.transBack();// 捕获到异常后也需要进行事务回滚
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
e.printStackTrace();
} finally {
System.out.println("我是finally中的语句哟");
try {
DBUtil.closeConnection();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

转账业务java源代码

    

JDBC03 利用JDBC实现事务提交与回滚【调用Connection中的方法实现事务管理】的更多相关文章

  1. 【转】批量复制操作(SqlBulkCopy)的出错处理:事务提交、回滚

    原文地址:http://blog.csdn.net/westsource/article/details/6658109 默认情况下,批量复制操作作为独立的操作执行. 批量复制操作以非事务性方式发生, ...

  2. RocketMQ源码分析之RocketMQ事务消息实现原下篇(事务提交或回滚)

    摘要: 事务消息提交或回滚的实现原理就是根据commitlogOffset找到消息,如果是提交动作,就恢复原消息的主题与队列,再次存入commitlog文件进而转到消息消费队列,供消费者消费,然后将原 ...

  3. mysql事务提交和回滚机制

    应用场景:   银行取钱,从ATM机取钱,分为以下几个步骤       1 登陆ATM机,输入密码:    2 连接数据库,验证密码:    3 验证成功,获得用户信息,比如存款余额等:    4 用 ...

  4. 对mysql事务提交、回滚的错误理解

    一.起因 begin或者START TRANSACTION开始一个事务 rollback事务回滚 commit 事务确认 人们对事务的解释如下:事务由作为一个单独单元的一个或多个SQL语句组成,如果其 ...

  5. 关于SAP的事务提交和回滚(LUW)

    1 Sap的更新的类型 在sap中,可以使用CALL FUNCTION ... IN UPDATE TASK将多个数据更新绑定到一个database LUW中.程序使用COMMIT WORK提交修改请 ...

  6. 关于jave在oracle驱动下事务提交与回滚问题

    一直以来,都觉得Connection假设设置了setAutoCommit(false)后.启动手工事务提交.必须手工进行commit或者rollback才行.今天正好遇到一个问题.结果大跌眼镜. 于是 ...

  7. MySQL事务提交与回滚

    提交 为了演示效果,需要打开两个终端窗口,使用同一个数据库,操作同一张表 step1:连接 终端1:查询商品分类信息 select * from goods_cates; step2:增加数据 终端2 ...

  8. J2EE分布式事务中的提交、回滚方法调用异常。

    这个是昨天上班的时候,写一个后台程序的调试程序时碰到的问题,和项目经理纠结了一天,最后搞定了.于是今天上班正好闲着,花了几乎一天的时间去网上找各种相关的资料.目前了解的内容如此: 根据使用的weblo ...

  9. nestd事务如果报错了 则回滚到外部事物保存点 且外部事物如果没异常的话 会正常提交 nested事务并不会提交;如果外部事物报错了 内部事务会一同回滚

    nestd事务如果报错了 则回滚到外部事物保存点 且外部事物如果没异常的话 会正常提交 nested事务并不会提交:如果外部事物报错了 内部事务会一同回滚

随机推荐

  1. Django-form补充

    Django_form补充 问题1:  注册页面输入为空,报错:keyError:找不到password def clean(self): print("---",self.cle ...

  2. 17 python 内置函数

    内置函数:Python的内部自带的函数 作用域相关: 基于字典的形式获取局部变量和全局变量 globals()——获取全局变量的ha1 locals()——获取执行本方法所在命名空间内的局部变量的字典 ...

  3. windows下安装 redis并开机自启动

    1,redis官方下载地址:https://redis.io/download,redis 64位下载地址:https://github.com/ServiceStack/redis-windows, ...

  4. 6.MySQL优化---高级进阶之表的设计及优化

    转自互联网整理. 优化之路高级进阶——表的设计及优化 优化①:创建规范化表,消除数据冗余 数据库范式是确保数据库结构合理,满足各种查询需要.避免数据库操作异常的数据库设计方式.满足范式要求的表,称为规 ...

  5. [ZOJ2587]Unique Attack

    vjudge sol 最小割判定唯一性. 只要做完一个任意最小割后,判断一下是不是所有点都要么和\(S\)相连,要么和\(T\)相连. 只要两边各一次\(dfs\)就行了. code #include ...

  6. redis的no-appendfsync-on-rewrite参数

    redis提供了两种持久化机制,rdb和aof. 关于aof的原理,类似于预写日志,不再解释.其中几个选项如下: appendfsync always:总是写入aof文件,并完成磁盘同步appendf ...

  7. 前端跨域问题,以及ajax,jsonp,json的区别

    看了很多网上的资料,小七感觉都没有完全解决我的疑惑以及问题,所以特意拿出通俗易懂的话讲解跨域问题,以及ajax,jsonp,json的区别.首先先说跨域问题什么时候需要跨域?[1]域名不同(即网址不同 ...

  8. 洛谷 3803 【模板】多项式乘法(FFT)

    题目:https://www.luogu.org/problemnew/show/P3803 第一道FFT! https://www.cnblogs.com/zwfymqz/p/8244902.htm ...

  9. 5 Things You Should Know About the New Maxwell GPU Architecture

    The introduction this week of NVIDIA’s first-generation “Maxwell” GPUs is a very exciting moment for ...

  10. verilog学习五点经验分享

    1.规范很重要工作过的朋友肯定知道,公司里是很强调规范的,特别是对于大的设计(无论软件还是硬件),不按照规范走几乎是不可实现的.逻辑设计也是这样:如果不按规范做的话,过一个月后调试时发现有错,回头再看 ...