JDBC事务的理解及用法实例

事务的概念

事务是应用程序中一个完整的业务逻辑,一个事务中的一系列的操作要么全部成功,要不就全部失败。

事务的特性(ACID)

特性 概念
原子性(Atomicity) 事务包含的所有操作要么成功,要么全部失败。
一致性(Consistency) 事务必须使数据库从一个一致性状态转换到另一个一致性状态。
隔离性(Isolation) 多个并发事务之间互不影响
持久性(Durability) 事务产生的影响是不能撤销的

事务的语句

语句 说明
setAutoComit(false/true) 开始事务,false为手动提交,true为自动提交
commit 提交事务
rollback 回滚事务

代码

环境

在java项目导入JDBC的包,见此文章:JAVA中利用JDBC实现连接Mysql的操作;
我用的是JDBC8版本的驱动,编译软件为Eclipse,数据库为Mysql;

应用

#创建库
CREATE DATABASE student;

#创建表
CREATE TABLE account(
id INT UNIQUE NOT NULL, --账号
username VARCHAR(30) NOT NULL,--用户名(账号名)
money DOUBLE UNSIGNED --账户金额
);

#录入数据
INSERT INTO account(id,username,money) values(1,"张飞",1000),(2,"关羽",2000);

应用1:转帐

package com.bingjiu.affair;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Scanner;

public class JDBC事务 {
	//
	public static void main(String[] args) throws SQLException {
		int id1;//发款人账号id
		int id2;//收款人账号id
		double money;//转账金额
		//连接数据库,jdbk8版本
		Connection con = conMysql();
		
		//录入数据
		Scanner sc=new Scanner(System.in);
		System.out.println("");
		System.out.print("请输入你的账号:");
		id1=sc.nextInt();
		System.out.print("收款人账号:");
		id2=sc.nextInt();
		System.out.print("转账金额:");
		money=sc.nextDouble();
		 
		//true:sql命令的提交(commit)由驱动程序负责
		//false:sql命令的提交由应用程序负责,程序必须调用commit或者rollback方法
		//开启事务,设置为手动提交
		con.setAutoCommit(false);
		
		//转账操作
		changeMoney(id1, (-money), con);
		changeMoney(id2, money, con);
		
		
		/*异常捕获
		 * 如果一切正确执行try,然后执行finally
		 * 如果出现错误执行catch里语句,然后执行finally里语句
		 * finally都会执行
		*/
		try {
			//提交事务
			con.commit();
			System.out.println("转账成功!");
		} catch (SQLException e) {
			//回滚事务
			con.rollback();
			System.out.println("转账失败!");
			
			e.printStackTrace();
		}finally {
			//断开数据库
			con.close();
		}
		
		
	}
	//转账方法
	public static void changeMoney(int id,double money,Connection con) throws SQLException {
		//sql语句
		String sql="UPDATE account SET money=money+? where id=?";
		//创建sql语句执行器
		PreparedStatement ps = con.prepareStatement(sql);
		//传入数据
		ps.setDouble(1, money);//传入sql中第一个‘?’的值,金额
		ps.setInt(2, id);//传入sql中第2个‘?’的值,账号
		//执行sql语句
		int n = ps.executeUpdate();
		
	}
	
	
	//连接数据库
	public static Connection conMysql() throws SQLException {
		Connection con=DriverManager.getConnection("jdbc:mysql:///student?serverTimezone=UTC","root","root");
		//验证连接情况
		if(con!=null) {
			System.out.println("数据库连接成功!");
		}else {
			System.out.println("数据库连接失败!");
		}
		return con;
	}
}

应用2:银行转账存取的实现

功能:转账(用到事务),查询余额,取钱,存钱
代码中自己定义方法的说明:

自定义方法 说明
changeMoney(int id, double money, Connection con) 修改账户金额的方法,用于转账,存钱,取钱。无返回值类型
getname(int id, Connection con) 根据id查询用户姓名的方法,返回类型为String,返回值为此id的账号名,不过我好像没用这个方法。
getId(int id, Connection con) 判断用户名是否在数据库中存在,返回类型为boolean,返回值为:数据库中有该id返回true,否之返回false
getIdMoney(int id, Connection con) 查询用户金额,返回值类型为double,返回值是该id的余额
conMysql() 连接数据库,返回类型为Connection,返回值为连上或者者没连接上的Connection
package com.bingjiu.affair;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Scanner;

public class JDBC事务 {
	//
	public static void main(String[] args) throws SQLException {
		int num=0;// 操作号
		int id1=0;// 发款人账号id
		int id2=0;// 收款人账号id
		double money=0;// 金额
		// 连接数据库,jdbk8版本
		Connection con = conMysql();

		// 录入数据
		Scanner sc = new Scanner(System.in);
		System.out.println("");
		System.out.print("请输入你的账号:");
		id1 = sc.nextInt();
		if (getId(id1, con)) {
		  while(true) {
			System.out.println("1、查询余额");
			System.out.println("2、存钱");
			System.out.println("3、取钱");
			System.out.println("4、转账");
			System.out.println("其他退出");
			System.out.print("请输入你要操作事务的编号:");
			num = sc.nextInt();

			switch (num) {
			//余额
			case 1:
				double residueMoney =getIdMoney(id1, con);
				System.out.println("账户余额:"+residueMoney);
				break;
			//存钱
			case 2:
				System.out.println("快给我钱:");
				money=sc.nextDouble();
				changeMoney(id1, money, con);
				System.out.println("老板大气!已存入。现有余额:"+getIdMoney(id1, con));
				break;
			case 3:
				System.out.println("说吧,要取多少钱:");
				money=sc.nextDouble();
				if(getIdMoney(id1, con)>=money) {
					changeMoney(id1, -money, con);
					System.out.println("取款成功,你还有资产"+getIdMoney(id1, con));
				}else {
					System.out.println("你做梦呢?你有这么多钱吗,赶紧取挣钱");
				}
				break;
			case 4:
				System.out.print("收款人账号:");
				id2 = sc.nextInt();
				System.out.print("转账金额:");
				money = sc.nextDouble();

				// true:sql命令的提交(commit)由驱动程序负责
				// false:sql命令的提交由应用程序负责,程序必须调用commit或者rollback方法
				// 开启事务,设置为手动提交
				con.setAutoCommit(false);

				// 转账操作
				changeMoney(id1, (-money), con);
				changeMoney(id2, money, con);
				/*
				 * 异常捕获 如果一切正确执行try,然后执行finally 如果出现错误执行catch里语句,然后执行finally里语句 finally都会执行
				 */
				try {
					// 提交事务
					con.commit();
					System.out.println("转账成功!");
				} catch (SQLException e) {
					// 回滚事务
					con.rollback();
					System.out.println("转账失败!");

					e.printStackTrace();
				}
				break;

			default:
				System.out.println("输的什么玩意!886");
				//结束程序运行
				System.exit(0);
				break;
			}
			System.out.println("按回车键继续操作!");
			sc.nextLine();
			sc.nextLine();
		  }
		} else {
			System.out.println("SB,账号都输错!");
		}
		
		// 关闭数据库
		con.close();

	}

	// 转账,存钱,取钱方法
	public static void changeMoney(int id, double money, Connection con) throws SQLException {
		// sql语句
		String sql = "UPDATE account SET money=money+? where id=?";
		// 创建sql语句执行器
		PreparedStatement ps = con.prepareStatement(sql);
		// 传入数据
		ps.setDouble(1, money);// 传入sql中第一个‘?’的值,金额
		ps.setInt(2, id);// 传入sql中第2个‘?’的值,账号
		// 执行sql语句
		int n = ps.executeUpdate();

	}
	
	// 查询用户名字
	public static String getname(int id, Connection con) throws SQLException {
		// sql语句
		String sql = "SELECT * FROM account where id=?";
		// 创建sql语句执行器
		PreparedStatement ps = con.prepareStatement(sql);
		// 录进数据,传sql语句中第一个'?'值
		ps.setInt(1, id);
		// 执行sql语句,接受返回数据,进行查询
		ResultSet rs = ps.executeQuery();
		// 获取用户姓名
		String name = rs.getString("username");
		// 返回姓名
		return name;
		}

	// 查询id账号是否存在
	public static boolean getId(int id, Connection con) throws SQLException {
		// sql语句
		String sql = "SELECT * FROM account where id=?";
		// 创建sql语句执行器
		PreparedStatement ps = con.prepareStatement(sql);
		// 录进数据,传sql语句中第一个'?'值
		ps.setInt(1, id);
		// 执行sql语句,并接受返回数据,进行查询
		ResultSet rs = ps.executeQuery();
		// 如果返回的数据中为空,说明不存在该用户返回false,否之返回true
		if (rs.next()) {
			return true;
		} else {
			return false;
		}

	}

	// 查询用户金额
	public static double getIdMoney(int id, Connection con) throws SQLException {
		// sql语句
		String sql = "SELECT * FROM account where id=?";
		// 创建sql语句执行器
		PreparedStatement ps = con.prepareStatement(sql);
		// 录进数据,传sql语句中第一个'?'值
		ps.setInt(1, id);
		// 执行sql语句,接受返回数据
		ResultSet rs = ps.executeQuery();
		// 获取改用户的余额
		double money=0;
		while(rs.next()) {
			money=rs.getDouble("money");
		}
		// 返回余额
		return money;
	}

	// 连接数据库
	public static Connection conMysql() throws SQLException {
		Connection con = DriverManager.getConnection("jdbc:mysql:///student?serverTimezone=UTC", "root", "root");
		// 验证连接情况
		if (con != null) {
			System.out.println("数据库连接成功!");
		} else {
			System.out.println("数据库连接失败!");
		}
		return con;
	}
}

效果图:
JDBC事务的理解及用法实例

上一篇:NGUI实现ScrollView功能


下一篇:JDK中Concurrent包介绍及使用(包含atomic包/lock包/并发容器/执行器)