create table BANKACCOUNT
(
id VARCHAR2(255) not null,
name VARCHAR2(255) not null,
balance NUMBER(10)
)
tablespace TS_USER
pctfree 10
initrans 1
maxtrans 255
storage
(
initial 64K
next 1M
minextents 1
maxextents unlimited
);
alter table BANKACCOUNT
add primary key (ID)
using index
tablespace TS_USER
pctfree 10
initrans 2
maxtrans 255
storage
(
initial 64K
next 1M
minextents 1
maxextents unlimited
);
2. 初始数据
![](http://static.oschina.net/uploads/space/2015/1208/150232_TvUJ_1989867.png)
3. Test2.java------------------利用事务模拟简单的"转账"情景
package com.lxh.transaction2;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.swing.JOptionPane;
import com.util.ConnectToDB;
public class Test3 {
public Connection conn = null;
public Statement stat = null;
public ResultSet rs = null;
public static void main(String[] args) {
JOptionPane.showMessageDialog(null, "转账开始:请输入对方账号名和转账金额");
String name = JOptionPane.showInputDialog("请输入对方账户名:");
String money = JOptionPane.showInputDialog("请输入转账金额:");
if (null == name || "".equals(name) || null == money
|| "".equals(money)) {
JOptionPane.showMessageDialog(null, "账号和转账金额不能为空");
} else {
// 判断转账金额是否为数字
char m[] = money.toCharArray();
boolean flag = true;
for (char c : m) {
if (!(Character.isDigit(c))) {
flag = false;
break;
}
}
if (flag) {
int tradeMoney = Integer.parseInt(money);
/**
* 校验账户名和转账金额
*/
Test3 t = new Test3();
try {
/**
* 数据库链接操作
*/
Class.forName("oracle.jdbc.driver.OracleDriver");
t.conn = DriverManager.getConnection(
"jdbc:oracle:thin:@127.0.0.1:1521:tran",
"test", "123");
t.stat = t.conn.createStatement();
/********************** 转账前置处理 **********************/
boolean userExist = Test3.checkAccount(t.stat, name);
// 用户存在
if (userExist) {
// 转账账户正常
boolean tradeMoneyIsAvail = Test3.checkTradeMoney(
t.stat, "lxh", tradeMoney);// 模拟lxh为转出账户
if (tradeMoneyIsAvail) {
// 转账金额正常
/********************** 转账开始 ***************************/
String sql1 = "update bankAccount set balance=balance-"
+ tradeMoney + " where name='lxh'";
String sql2 = "update bankAccount set balance=balance+"
+ tradeMoney + " where name='" + name + "'";
/**
* 设置非自动提交-------非常重要
*/
t.conn.setAutoCommit(false);
// 批处理
t.stat.addBatch(sql1);
t.stat.addBatch(sql2);
/**
* 处理执行SQL的结果
*/
int res[] = t.stat.executeBatch();
int result = 1;// 正常执行,返回结果为1
for (int i : res) {
result = i;
}
if (1 == result) {
JOptionPane.showMessageDialog(
null,
"转账成功,您的当前账户余额为("
+ Test3.getBalance(t.stat,
"lxh") + ")");
// 执行结果全部为1的时候执行正确,允许提交
t.conn.commit();
t.conn.setAutoCommit(true);
} else {
// 不符合逻辑(SQL执行出错),回滚事务
JOptionPane.showMessageDialog(null,
"转账失败。。。请核查输入参数");
t.conn.rollback();
}
/********************** 转账结束 ***************************/
} else {
JOptionPane.showMessageDialog(
null,
"尊敬的lxh用户,您的账户余额为("
+ Test3.getBalance(t.stat, "lxh")
+ ")小于转账金额" + tradeMoney
+ ",不能转账。");
}
} else {
JOptionPane.showMessageDialog(null, "账户: " + name
+ " 不存在,请输入正确的账户名.");
}
/********************** 转账前置处理 **********************/
} catch (SQLException e) {
System.out.println("转账失败:\t" + e.getMessage());
try {
// 出现异常回滚(比如数据表名称/字段名称有误,参数有误)
t.conn.rollback();
t.conn.setAutoCommit(true);
} catch (SQLException e1) {
e1.printStackTrace();
}
} catch (ClassNotFoundException e) {
System.out.println(e.getMessage());
} finally {
// 关闭资源
ConnectToDB.closeResultSet(t.rs);
ConnectToDB.closeStatemet(t.stat);
ConnectToDB.closeConnection(t.conn);
}
} else {
// 非数字直接结束
JOptionPane.showMessageDialog(null, "转账金额应该为数字.");
}
}
}
/***************************** 工具方法 *******************************/
// 校验账户名
public static boolean checkAccount(Statement stat, String userName) {
//
boolean flag = true;
//
int result = 0;
//
try {
ResultSet rs = stat
.executeQuery("select count(1) res from bankAccount where name='"
+ userName + "'");
while (rs.next()) {
result = rs.getInt("res");
}
// 帐户名不存在
if (result != 1) {
flag = false;
}
} catch (SQLException e) {
System.out.println("" + e.getMessage());
}
//
return flag;
}
// 校验转账金额
public static boolean checkTradeMoney(Statement stat, String userName,
int tradeMoneyValue) {
// flag
boolean flag = false;
//
int balance = 0;
// 获取账户金额并判断转账金额是否可以转账
balance = getBalance(stat, userName);
if (tradeMoneyValue <= balance) {
flag = true;
}
//
return flag;
}
// 查询余额
public static int getBalance(Statement stat, String userName) {
//
int result = 0;
//
try {
//
ResultSet rs = stat
.executeQuery("select balance from bankAccount where name='"
+ userName + "'");
while (rs.next()) {
result = rs.getInt("balance");
}
} catch (SQLException e) {
System.out.println("获取账户余额失败:\t" + e.getMessage());
}
//
return result;
}
}
4. 运行结果
<1> 账户名不存在
![](http://static.oschina.net/uploads/space/2015/1208/150835_Db2I_1989867.png)
<2> 金额错误
![](http://static.oschina.net/uploads/space/2015/1208/151058_ULTF_1989867.png)
![](http://static.oschina.net/uploads/space/2015/1208/151545_GcKW_1989867.png)
<4> 转账信息(账户:xiaowu 金额:500)正确
![](http://static.oschina.net/uploads/space/2015/1208/151256_VBdT_1989867.png)
5. 结果分析
其实跟"事务的应用demo1-------采用JDBC硬编码方式实现银行转账."没有本质区别,只是多了与用户交互的操作,以及相关数据的验证和相关信息的显示。
6. 不足之处:转账方是固定的。
当然这只是为了说明事务的作用做的simple demo,离真正的银行转账逻辑以及实现还有很大差别。
7. 补充:
实际开发中,可能会使用spring来进行事务管理。