事务的概念
事务是应用程序中一个完整的业务逻辑,一个事务中的一系列的操作要么全部成功,要不就全部失败。
事务的特性(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;
}
}
效果图: