文档章节

事务的应用demo2-------采用可交互的JDBC硬编码方式模拟"银行转账"

绿林小子
 绿林小子
发布于 2015/12/08 15:16
字数 1023
阅读 51
收藏 0
    1. 数据表-----BANKACCOUNT
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. 初始数据

    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> 账户名不存在

       <2> 金额错误

       <3> 余额不足
       
       <4> 转账信息(账户:xiaowu 金额:500)正确

    5. 结果分析
       其实跟"事务的应用demo1-------采用JDBC硬编码方式实现银行转账."没有本质区别,只是多了与用户交互的操作,以及相关数据的验证和相关信息的显示。
    6. 不足之处:转账方是固定的。
       当然这只是为了说明事务的作用做的simple demo,离真正的银行转账逻辑以及实现还有很大差别。
    7. 补充:
       实际开发中,可能会使用spring来进行事务管理。

© 著作权归作者所有

绿林小子
粉丝 5
博文 131
码字总数 45566
作品 0
福州
私信 提问
事务的应用demo1-------采用JDBC硬编码方式模拟"银行转账"。

数据表-----BANKACCOUNT create table BANKACCOUNT(id VARCHAR2(255) not null,name VARCHAR2(255) not null,balance NUMBER(10))tablespace TS_USERpctfree 10initrans 1maxtrans 255storag......

绿林小子
2015/12/08
65
0
Java程序员从笨鸟到菜鸟之(六十五)细谈Hibernate(十六)数据库事务与隔离级别

数据库事务:事务是指一组相互依赖的操作行为,如银行交易、股票交易或网上购物。事务的成功取决于这些相互依赖的操作行为是否都能执行成功,只要有一个操作行为失败,就意味着整个事务失败。...

长平狐
2012/11/12
69
0
Spring事务管理的四种方式(以银行转账为例)

本文配套示例代码下载地址(完整可运行,含sql文件,下载后请修改数据库配置):http://download.csdn.net/detail/daijin888888/9567096 一、事务的作用 将若干的数据库操作作为一个整体控制...

梁金晶
2017/10/31
0
0
Java原理 事务的ACID是指什么?

Java原理 事务的ACID是指什么?一、什么是Java事务通常的观念认为,事务仅与数据库相关。事务必须服从ISO/IEC所制定的ACID原则。ACID是原子性(atomicity)、一致性(consistency)、隔离性 ...

勇往直前的麻雀
2017/10/20
0
0
Spring编程式和声明式事务实例讲解

Java面试通关手册(Java学习指南):https://github.com/Snailclimb/JavaGuide 历史回顾: 可能是最漂亮的Spring事务管理详解 Spring事务管理 Spring支持两种方式的事务管理: 编程式事务管理...

snailclimb
2018/05/23
0
0

没有更多内容

加载失败,请刷新页面

加载更多

状态模式

//相当把一个State对象存到Context对象中,然后通过Context实例化对象调用保存的state对象去调用state的相应的方法 https://blog.csdn.net/syc434432458/article/details/51210361...

南桥北木
17分钟前
0
0
基于 Jenkins + JaCoCo 实现功能测试代码覆盖率统计

本文首发于:Jenkins 中文社区 使用 JaCoCo 统计功能测试代码覆盖率? 对于 JaCoCo,有所了解但又不是很熟悉。 "有所了解"指的是在 CI 实践中已经使用 JaCoCo 对单元测试代码覆盖率统计: 当...

Jenkins中文社区
24分钟前
3
0
聊聊Elasticsearch的OsProbe

序 本文主要研究一下Elasticsearch的OsProbe OsProbe elasticsearch-7.0.1/server/src/main/java/org/elasticsearch/monitor/os/OsProbe.java public class OsProbe { private static f......

go4it
25分钟前
0
0
谈谈lucene的DocValues特性之NumericDocValuesField

在默认实现的DocValuesCosumer中,数值有可能分块存储也有可能放在一个数据块中存储。 分块的大小默认是16384,并且通过预先计算如果按一个块存储最大值与最小值的差所占用的比特数和分块存储...

FAT_mt
43分钟前
0
0
【BATJ】面试必问MySQL索引实现原理

BATJ面试题剖析 1、为什么需要使用索引? 2、数据结构Hash、平衡二叉树、B树、B+树区别? 3、机械硬盘、固态硬盘区别? 4、Myisam与Innodb B+树的区别? 5、MySQL中的索引什么数据结构? 6、...

须臾之余
今天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部