四.转账案例:
描述:一个人的账户减少,另一个人的账户增加相同金额.
步骤:
1.Eclipse创建工程transfer,并添加jar包:mysql-connector;c3p0(c3p0-config.xml放在src文件夹下);commens-dbutils;
2.创建5个包:web/service/DAO/Account类/utils
3.创建数据库bank,添加数据表account(id,name,money);(用于与Account类相关联)
4.web层是供客户使用的,只用于输入信息,及展示运行结果(转账成功或失败)
5.serive层用于转账操作,并返回给web层转账成功或失败的信息;
6.DAO层用于操作数据库,即查询是否有客户输入的相关信息,并将查询结果封装成类(javabean),返回给service层;
代码演示:
web层:
1 package huguangqin.cnblogs.web; 2 import huguangqin.cnblogs.service.Service; 3 import java.util.Scanner; 4 //该层展示给客户,用于收集信息,展示数据及结果 5 public class MyAPP { 6 public static void main(String[] args) { 7 // 提示用户输入 8 Scanner sc = new Scanner(System.in); 9 System.out.print("请输入付款人姓名:"); 10 String payName = sc.next(); 11 System.out.print("请输入收款人姓名:"); 12 String receiptName = sc.next(); 13 System.out.print("请输入金额:"); 14 double money = sc.nextDouble(); 15 16 // 面向service层,返回转账结果 17 Service ser = new Service(); 18 String message = ser.transfer(payName, receiptName, money); 19 System.out.println(message); 20 } 21 22 }
service层:
1 package huguangqin.cnblogs.service; 2 import huguangqin.cnblogs.DAO.DAO; 3 import huguangqin.cnblogs.domain.Account; 4 import huguangqin.cnblogs.utils.ConnectionManager; 5 public class Service { 6 public String transfer(String payName, String receiptName, double money) { 7 // 开启事务 8 ConnectionManager.startTransaction(); 9 10 // 根据传入的收/付款人姓名在数据库中查找是否存在--以后所有的步骤都是面向Account操作 11 DAO d = new DAO(); 12 Account payAccount = d.queryAccount(payName); 13 if (payAccount == null) { 14 ConnectionManager.rollback(); 15 return "付款账户不存在"; 16 } 17 18 Account receiptAccount = d.queryAccount(receiptName); 19 if (receiptAccount == null) { 20 ConnectionManager.rollback(); 21 return "收款账户不存在"; 22 } 23 24 // 根据传入的金额,查询余额是否足够 25 if (payAccount.getMoney() >= money) { 26 payAccount.setMoney(payAccount.getMoney() - money); 27 } else { 28 ConnectionManager.rollback(); 29 return "余额不足"; 30 } 31 receiptAccount.setMoney(receiptAccount.getMoney() + money); 32 33 int i = d.update(payAccount); 34 int j = d.update(receiptAccount); 35 36 // 根据操作的结果,返回操作是否成功 37 if (i == 1 && j == 1) { 38 ConnectionManager.commit(); 39 return "转账成功,金额:" + money + "元"; 40 } else { 41 ConnectionManager.rollback(); 42 return "服务器升级...,转账失败"; 43 } 44 } 45 }
DAO(Data Access Object)层:
1 package huguangqin.cnblogs.DAO; 2 import huguangqin.cnblogs.domain.Account; 3 import huguangqin.cnblogs.utils.ConnectionManager; 4 import java.sql.Connection; 5 import java.sql.SQLException; 6 import org.apache.commons.dbutils.QueryRunner; 7 import org.apache.commons.dbutils.handlers.BeanHandler; 8 //该层用于操作数据库-创建-查询-更新 9 public class DAO { 10 // 能否将QueryRunner/Connection作为成员变量? 11 private static QueryRunner qr = new QueryRunner(); 12 private static Connection conn = ConnectionManager.getConnectionThreadLocal(); 13 14 /* 15 * 查询数据库 返回值:Account 参数:String name 方法名:queryAccount 16 */ 17 public Account queryAccount(String name) { 18 // 获取本地线程连接对象 19 String querySql = "SELECT * FROM account WHERE name = ?"; 20 BeanHandler<Account> bh = new BeanHandler<>(Account.class); 21 Account queryAccount = null; 22 try { 23 queryAccount = qr.query(conn, querySql, bh, name); 24 } catch (SQLException e) { 25 e.printStackTrace(); 26 } 27 return queryAccount; 28 } 29 30 /* 31 * 更新数据库 方法名:update 返回值:int 参数:money-转账金额 32 */ 33 34 public int update(Account a) { 35 String updateSql = "UPDATE account SET money = ? WHERE id = ?"; 36 int i = 0; 37 try { 38 i = qr.update(conn, updateSql, a.getMoney(), a.getId()); 39 } catch (SQLException e) { 40 e.printStackTrace(); 41 } 42 return i; 43 } 44 }
domain层:
1 package huguangqin.cnblogs.domain; 2 //javabean 3 public class Account { 4 private int id;// 账户ID 5 private String name;// 账户名 6 private double money;// 余额 7 8 public Account() { 9 super(); 10 } 11 12 public Account(int id, String name, double money) { 13 super(); 14 this.id = id; 15 this.name = name; 16 this.money = money; 17 } 18 19 public int getId() { 20 return id; 21 } 22 23 public void setId(int id) { 24 this.id = id; 25 } 26 27 public String getName() { 28 return name; 29 } 30 31 public void setName(String name) { 32 this.name = name; 33 } 34 35 public double getMoney() { 36 return money; 37 } 38 39 public void setMoney(double money) { 40 this.money = money; 41 } 42 43 @Override 44 public String toString() { 45 return "Account [id=" + id + ", name=" + name + ", money=" + money 46 + "]"; 47 } 48 49 }
utils包://ConnectionManager工具
1 package huguangqin.cnblogs.utils; 2 import java.sql.Connection; 3 import java.sql.SQLException; 4 //该工具用于事务管理 5 public class ConnectionManager { 6 // 面向Connection进行事务管理,因此首先获取Connection,并存放于ThreadLocal,规避线程安全问题 7 private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>(); 8 9 // 获取本线程的Connection连接,因为后面的事务管理全部是面向Connection对象的 10 public static Connection getConnectionThreadLocal() { 11 Connection conn = threadLocal.get();// 注意要从当前线程获取,不要利用MyC3P0创建!!! 12 if (conn == null) { 13 // 如果连接为空,则通过MyC3P0工具获取并存放线程一个连接 14 conn = MyC3P0.getConnection(); 15 threadLocal.set(conn); 16 } 17 return conn; 18 } 19 20 // 面向获取到的本地线程的连接对象,开启事务 21 public static void startTransaction() { 22 try { 23 getConnectionThreadLocal().setAutoCommit(false); 24 } catch (SQLException e) { 25 e.printStackTrace(); 26 throw new RuntimeException("事务开启失败"); 27 } 28 } 29 30 // 面向本地线程的连接对象,提交事务 31 public static void commit() { 32 try { 33 getConnectionThreadLocal().commit(); 34 } catch (SQLException e) { 35 e.printStackTrace(); 36 throw new RuntimeException("提交失败!"); 37 } 38 } 39 40 // 面向本地线程的连接对象,回滚事务 41 public static void rollback() { 42 try { 43 getConnectionThreadLocal().rollback(); 44 } catch (SQLException e) { 45 e.printStackTrace(); 46 throw new RuntimeException("回滚失败!"); 47 } 48 } 49 }
//MyC3P0工具类
1 package huguangqin.cnblogs.utils; 2 import java.sql.Connection; 3 import java.sql.SQLException; 4 import javax.sql.DataSource; 5 import com.mchange.v2.c3p0.ComboPooledDataSource; 6 7 //MyC3P0工具用于建立资源池,并从池中获取Connection 8 public class MyC3P0 { 9 // 创建连接池 10 private static DataSource ds = new ComboPooledDataSource(); 11 12 // 创建方法获取资源池中Connection对象 13 public static Connection getConnection() { 14 Connection conn = null; 15 try { 16 conn = ds.getConnection(); 17 } catch (SQLException e) { 18 e.printStackTrace(); 19 } 20 return conn; 21 } 22 23 // 返回连接池 24 public static DataSource getDataSource() { 25 return ds; 26 } 27 28 }