第一节:JDBC的概述
第二节:JDBC连接数据库
第四节:使用PreparedStatement接口实现增、删、改的操作
第五节:Resultset结果集
第六节:处理大数据对象
第七节:使用CallableStatement接口调用存储过程
第八节:使用元数据分析数据库
第九节:JDBC的事务处理事务
下面是第九个部分,其他部分可以通过上面的链接访问
8.JDBC的事务处理事务
主要是从四个方面来学习
- 事务的概念
事务处理在数据库开发中有着非常重要的作用,所谓事务就是所有的操作要么一起成功,要么一起失败,事务
本身具有原子性(Atomicity)、一致性(Consistency)、隔离性或独立性(Isolation)
、持久性(Durability)4 个特 性,这 4 个特性也被称为 ACID 特征。
原子性:原子性是事务最小的单元,是不可再分隔的单元,相当于一个个小的数据库操作,这些操作必须同时
成功,如果一个失败了,则一切的操作将全部失败。
一致性:指的是在数据库操作的前后是完全一致的,保证数据的有效性,如果事务正常操作则系统会维持有效
性,如果事务出现了错误,则回到最原始状态,也要维持其有效性,这样保证事务开始时和结束时系统处于一 致状态。
隔离性:多个事务可以同时进行且彼此之间无法访问,只有当事务完成最终操作时,才可以看到结果;
持久性:事务完成之后,它对于系统的影响是永久性的。该修改即使出现致命的系统故障也将一直保持。
2 . MySQL 对事务的支持
序号 | 命令 | 描述 |
---|---|---|
1 | SETAUTOCOMMIT=0 | 取消自动提交处理,开启事务处理 |
2 | SETAUTOCOMMIT=1 | 打开自动提交处理,关闭事务处理 |
3 | STARTTRANSACTION | 启动事务 |
4 | BEGIN | 启动事务,相当于执行 STARTTRANSACTION |
5 | COMMIT | 提交事务 |
6 | ROLLBACK | 回滚全部事务 |
7 | SAVEPOINT事务保存点名称 | 设置事务保存点 |
8 | ROLLBACK TO SAVEPOINT保存点名称 | 回滚操作到保存点 |
- JDBC 事务处理
- 事务保存点
准备工作,创建一个表,来模拟事务的相关操作
编号id,还有账户人的姓名,此人的账户余额,我们模拟的是一个银行转账的操作
设计两个用户,给虚拟的余额
开始写代码的部分
package chap9_sec03;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import util.DbUtil;
public class Demo1 {
private static DbUtil dbUtil= new DbUtil();
/**
* 转出
* @param con
* @param accountName
* @param account
* @throws SQLException
*/
private static void outCount(Connection con,String accountName,int account) throws SQLException{
String sql="update t_bank set accountBalance=accountBalance-? where accountName=?";
PreparedStatement pstmt=con.prepareStatement(sql);
pstmt.setInt(1, account);
pstmt.setString(2, accountName);
pstmt.executeUpdate();
}
/**
* 转入
* @param con
* @param accountName
* @param account
* @throws SQLException
*/
private static void inCount(Connection con,String accountName,int account) throws SQLException{
String sql="update t_bank set accountBalance=accountBalance+? where accountName=?";
PreparedStatement pstmt=con.prepareStatement(sql);
pstmt.setInt(1, account);
pstmt.setString(2, accountName);
pstmt.executeUpdate();
}
public static void main(String[] args) {
Connection con=null;
try {
con=dbUtil.getCon();
System.out.println("张三开始向李四转账!");
int account=500;
outCount(con, "张三", account);
inCount(con, "李四", account);
System.out.println("转账成功");
} catch (Exception e) {
e.printStackTrace();
System.out.println("转账失败");
}finally {
try {
con.close();//关闭数据库
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
写了两个函数,核心是sql语句,用到的还是前面的PrepareStatement,两个函数的区别在于函数名的不同和sql语句中的加减法的差异。
刷新一下数据库,可以看到转账是成功的
如果在转账的过程中出现事故,现在模拟一下事故的产生
改一下inCount中的sql语句,使执行的时候出问题,但是这的outcount函数是没有问题的,因此,第一个转账的函数会执行成功,张三的钱会减少,但是李四没有收到钱。
执行一下
可以看到李四确实没收到钱,张三的钱却少了。
现在把错的sql语句部分依然留着,开始真正的引入事务的概念,主要的变动在main函数中
package chap9_sec03;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import util.DbUtil;
public class Demo1 {
private static DbUtil dbUtil= new DbUtil();
/**
* 转出
* @param con
* @param accountName
* @param account
* @throws SQLException
*/
private static void outCount(Connection con,String accountName,int account) throws SQLException{
String sql="update t_bank set accountBalance=accountBalance-? where accountName=?";
PreparedStatement pstmt=con.prepareStatement(sql);
pstmt.setInt(1, account);
pstmt.setString(2, accountName);
pstmt.executeUpdate();
}
/**
* 转入
* @param con
* @param accountName
* @param account
* @throws SQLException
*/
private static void inCount(Connection con,String accountName,int account) throws SQLException{
String sql="update t_bank set account=accountBalance+? where accountName=?";
PreparedStatement pstmt=con.prepareStatement(sql);
pstmt.setInt(1, account);
pstmt.setString(2, accountName);
pstmt.executeUpdate();
}
public static void main(String[] args) {
Connection con=null;
try {
con=dbUtil.getCon();
con.setAutoCommit(false);//取消自动提交
System.out.println("张三开始向李四转账!");
int account=500;
outCount(con, "张三", account);
inCount(con, "李四", account);
System.out.println("转账成功");
} catch (Exception e) {
try {
con.rollback();//遇到异常就回滚
} catch (SQLException e1) {
e1.printStackTrace();
System.out.println("转账失败");
}
}finally {
try {
con.commit();//最终要提交事务
con.close();//关闭数据库
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
现在执行的效果是这样的
刷新了数据库之后也没有金额的变化
下面设计一个回滚的保存点,这样做的意义是,执行的时候,张三的钱转出去了,而李四收钱的部分出问题了,但是有回滚保存点的出现,这不会产生报错。
package chap9_sec04;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Savepoint;
import util.DbUtil;
public class Demo1 {
private static DbUtil dbUtil= new DbUtil();
/**
* 转出
* @param con
* @param accountName
* @param account
* @throws SQLException
*/
private static void outCount(Connection con,String accountName,int account) throws SQLException{
String sql="update t_bank set accountBalance=accountBalance-? where accountName=?";
PreparedStatement pstmt=con.prepareStatement(sql);
pstmt.setInt(1, account);
pstmt.setString(2, accountName);
pstmt.executeUpdate();
}
/**
* 转入
* @param con
* @param accountName
* @param account
* @throws SQLException
*/
private static void inCount(Connection con,String accountName,int account) throws SQLException{
String sql="update t_bank set accountBalance=accountBalance+? where accountName=?";
PreparedStatement pstmt=con.prepareStatement(sql);
pstmt.setInt(1, account);
pstmt.setString(2, accountName);
pstmt.executeUpdate();
}
public static void main(String[] args) {
Connection con=null;
Savepoint sp=null;
try {
con=dbUtil.getCon();
con.setAutoCommit(false);//取消自动提交
System.out.println("张三开始向李四转账!");
int account=500;
outCount(con, "张三", account);
sp=con.setSavepoint();//设置一个保存点
inCount(con, "李四", account);
System.out.println("转账成功");
} catch (Exception e) {
try {
con.rollback(sp);//遇到异常就回滚,回滚到sp这个保存点
} catch (SQLException e1) {
e1.printStackTrace();
System.out.println("转账失败");
}
}finally {
try {
con.commit();//最终要提交事务
con.close();//关闭数据库
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
最后的执行效果是无报错,数据库中张三少了500,李四的钱没变。
这次的学习差不多到这就结束了,总的来说比以前的数据库的应用更灵活了,喜欢看jdk文档,在学这个的通过又把J2SE系统性的学了一遍,最近满疲惫,所以最后一个写的很慢,本身自己在事务的这方面就有些不太会,学习不能一下子太狠,那样真的很累,组要时间调整,最近搞的有点狠,希望写一个大的类型的知识的学习中,我能更好的安排好自己的时间,也希望自己写的博客,对我那几个小学弟有帮助,对想学这方面的知识的人有帮助,本次的学习结束了,下一篇是关于JSP的系统性学习和同步做我最后的那个中型的项目,博客会继续更新,望支持,谢谢!
需要学习的时候用到的数据库和所有的源代码,请去百度网盘提取
链接:https://pan.baidu.com/s/1wDL_aFCPQ9WAZ_vSy6UVdg
提取码:hime