JDBC的学习(第九节:JDBC的事务处理事务 )

本文深入探讨了JDBC事务处理的原理与应用,包括事务的四大特性:原子性、一致性、隔离性和持久性。通过具体实例,如银行转账场景,演示了如何在Java中使用JDBC进行事务控制,涉及SQL语句的执行、事务的开始、提交和回滚,以及保存点的设置和回滚。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第一节:JDBC的概述

第二节:JDBC连接数据库

第三节:使用Statement接口实现增、删、改操作

第四节:使用PreparedStatement接口实现增、删、改的操作

第五节:Resultset结果集

第六节:处理大数据对象

第七节:使用CallableStatement接口调用存储过程

第八节:使用元数据分析数据库

第九节:JDBC的事务处理事务

下面是第九个部分,其他部分可以通过上面的链接访问

8.JDBC的事务处理事务

主要是从四个方面来学习

  1. 事务的概念

事务处理在数据库开发中有着非常重要的作用,所谓事务就是所有的操作要么一起成功,要么一起失败,事务
本身具有原子性(Atomicity)、一致性(Consistency)、隔离性或独立性(Isolation)
、持久性(Durability)4 个特 性,这 4 个特性也被称为 ACID 特征。
原子性:原子性是事务最小的单元,是不可再分隔的单元,相当于一个个小的数据库操作,这些操作必须同时
成功,如果一个失败了,则一切的操作将全部失败。
一致性:指的是在数据库操作的前后是完全一致的,保证数据的有效性,如果事务正常操作则系统会维持有效
性,如果事务出现了错误,则回到最原始状态,也要维持其有效性,这样保证事务开始时和结束时系统处于一 致状态。
隔离性:多个事务可以同时进行且彼此之间无法访问,只有当事务完成最终操作时,才可以看到结果;
持久性:事务完成之后,它对于系统的影响是永久性的。该修改即使出现致命的系统故障也将一直保持。

2 . MySQL 对事务的支持

序号命令描述
1SETAUTOCOMMIT=0取消自动提交处理,开启事务处理
2SETAUTOCOMMIT=1打开自动提交处理,关闭事务处理
3STARTTRANSACTION启动事务
4BEGIN启动事务,相当于执行 STARTTRANSACTION
5COMMIT提交事务
6ROLLBACK回滚全部事务
7SAVEPOINT事务保存点名称设置事务保存点
8ROLLBACK TO SAVEPOINT保存点名称回滚操作到保存点
  1. JDBC 事务处理
  1. 事务保存点

准备工作,创建一个表,来模拟事务的相关操作
在这里插入图片描述编号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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值