Java設計的銀行取款系統-Mysql資料庫(改進篇)2017/7/16
前言
這是前一篇http://blog.csdn.net/u011958281/article/details/73499642博文,沒有想到會有那麼多讀者,初次編寫,為了實現功能,犧牲了很多,最近經過一輪學習,有了一點新的想法,結合學習,特此分享ATM加強版,改進篇主要是加強效能安全,針對程式碼的優化,程式碼解耦度更好,更具可讀性,功能化分的更好。
程式碼的清晰度更好,直觀性更強,這裡可以看一下我的這片博文,JavaWEB分層設計思想模式http://blog.csdn.net/u011958281/article/details/74156940
作者也是通過學習,不斷的規範自己的程式碼分類,可能寫起來多了工作,多了劃分,但是整體可讀性更強,後期程式碼的複用率也是對於整體很看重的。
1. 程式碼解析與分析改進
- DAO介面
package com.shao.DAO;
import java.sql.SQLException;
import com.shao.model.user;
public interface accountDAO {
/**
* 登入檢驗
* @param name
* @param password
* @return
* @throws SQLException
*/
public user query(String name,String password) throws SQLException;
/**
* 新增賬戶
* @throws SQLException
*/
public void addUser(String name,String password) throws SQLException;
/**
* 更新使用者賬戶資訊
* @throws SQLException
*/
public void updateAccount(String FromName,String ToName,double balance) throws SQLException;
/**
* 查詢賬戶
* @param name
* @return
* @throws SQLException
*/
public user findUserByName(String name) throws SQLException;
}
- DAO介面實現層
package com.shao.DAO.impl;
import java.sql.SQLException;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import com.shao.DAO.accountDAO;
import com.shao.model.user;
import com.shao.util.C3P0Util;
import com.shao.util.ManagerThreadLocal;
public class accountDAO_impl implements accountDAO{
@Override
public user query(String name, String password) throws SQLException {
// TODO Auto-generated method stub
QueryRunner qr = new QueryRunner();
return qr.query(ManagerThreadLocal.getConnection(), "select * from bank where name = ? and password = ?",new BeanHandler<user>(user.class), name,password);
}
@Override
public void addUser(String name, String password) throws SQLException {
QueryRunner qr = new QueryRunner(C3P0Util.getDataSource());
qr.update("insert into bank(name,password,balance) values (?,?,?)",name,password,0);
}
@Override
public void updateAccount(String FromName, String ToName, double balance) throws SQLException {
QueryRunner qr = new QueryRunner();
qr.update(ManagerThreadLocal.getConnection(),"update bank set balance =balance - ? where name = ?",balance,FromName);
qr.update(ManagerThreadLocal.getConnection(),"update bank set balance =balance + ? where name = ?",balance,ToName);
}
public void updateAccount(String name,double balance) throws SQLException {
QueryRunner qr = new QueryRunner();
qr.update(ManagerThreadLocal.getConnection(),"update bank set balance = ? where name = ? ",balance,name);
}
@Override
public user findUserByName(String name) throws SQLException {
// TODO Auto-generated method stub
QueryRunner qr = new QueryRunner();
return qr.query(ManagerThreadLocal.getConnection(), "select * from bank where name = ?",new BeanHandler<user>(user.class), name);
}
}
在這段程式碼中,大家仔細看有沒有發現什麼,是不是感覺資料處理起來跟我之前的完全不一樣,程式碼更少,寫起來更簡單,更直觀,效果更好。後面我會把我用到的學習資料一起備份上去,供大家一起學習,在這裡我引入了資料庫工具類DBUtils.
DBUtils是java程式設計中的資料庫操作實用工具,小巧簡單實用。
DBUtils封裝了對JDBC的操作,簡化了JDBC操作。可以少寫程式碼。
- 1.對於資料表的讀操作,他可以把結果轉換成List,Array,Set等java集合,便於程式設計師操作;
- 2.對於資料表的寫操作,也變得很簡單(只需寫sql語句)
- 3.可以使用資料來源,使用JNDI,資料庫連線池等技術來優化效能–重用已經構建好的資料庫連線物件
在這裡我就不多說了,引進這個工具類,可以少些好多程式碼,其實內部實現你看它的功能,也基本能夠猜到,只是把我們常用的一些包裝起來,程式設計師不就是喜歡程式碼的複用嗎。
- Service介面層:
package com.shao.Service;
import com.shao.model.user;
public interface AccountService {
/**
* 註冊使用者
*/
public void addUser(String name,String passsword);
/**
* 登入驗證,查詢
*/
public user check(String name,String password) ;
/**
* 轉賬
*/
public void transfer(String FromName,String ToName,double balance);
/**
* 存款
*/
public void update(String name,double balance);
/**
* 查詢使用者
*/
public user query(String name) ;
}
從這裡我們可以吧需要的功能全部設計成介面,方便子類的實現,將DAO層設計與Service功能設計完全的區分開來,更具可讀性。
- Service介面實現
package com.shao.Service.impl;
import java.sql.SQLException;
import com.shao.DAO.impl.accountDAO_impl;
import com.shao.Service.AccountService;
import com.shao.model.user;
import com.shao.util.ManagerThreadLocal;
public class AccountServiceImpl implements AccountService{
accountDAO_impl account = new accountDAO_impl();
@Override
public void addUser(String name,String password) {
// TODO Auto-generated method stub
try {
ManagerThreadLocal.startTransaction();
account.addUser(name,password);
ManagerThreadLocal.commit();
} catch (SQLException e) {
// TODO Auto-generated catch block
ManagerThreadLocal.rollback();
} finally{
ManagerThreadLocal.close();
}
}
@Override
public user query(String name) {
// TODO Auto-generated method stub
user u = new user();
try {
ManagerThreadLocal.startTransaction();
u = account.findUserByName(name);
ManagerThreadLocal.commit();
} catch (SQLException e) {
// TODO Auto-generated catch block
ManagerThreadLocal.rollback();
}finally{
ManagerThreadLocal.close();
}
return u;
}
@Override
public void update(String name, double balance) {
// TODO Auto-generated method stub
user u = new user();
try {
ManagerThreadLocal.startTransaction();
account.updateAccount(name,balance);
ManagerThreadLocal.commit();
} catch (SQLException e) {
// TODO Auto-generated catch block
ManagerThreadLocal.rollback();
}finally{
ManagerThreadLocal.close();
}
}
@Override
public void transfer(String FromName, String ToName, double balance) {
// TODO Auto-generated method stub
try {
ManagerThreadLocal.startTransaction();
user u_from = account.findUserByName(FromName);
user u_to = account.findUserByName(ToName);
u_from.setbalance(u_from.getbalance()-balance);
u_to.setbalance(u_to.getbalance()+balance);
account.updateAccount(FromName,u_from.getbalance());
account.updateAccount(ToName,u_to.getbalance());
ManagerThreadLocal.commit();
} catch (SQLException e) {
// TODO Auto-generated catch block
ManagerThreadLocal.rollback();
}finally{
ManagerThreadLocal.close();
}
}
@Override
public user check(String name, String password) {
// TODO Auto-generated method stub
user u = new user();
try {
ManagerThreadLocal.startTransaction();
u = account.query(name,password);
ManagerThreadLocal.commit();
} catch (SQLException e) {
// TODO Auto-generated catch block
ManagerThreadLocal.rollback();
}finally{
ManagerThreadLocal.close();
}
return u;
}
}
View層設計我就不對說了,類似上一篇博文,在這裡我沒有對頁面進行過多的處理,主要是在邏輯上下了功夫。
效能與安全
前一篇博文,針對資料處理,我主要是利用JDBC跟SQL語句進行了底層DAO的實現,針對高併發情況沒有過多的涉及,其實C3P0大家應該不陌生,資料池的引入,可以很好的解決效能這方面,每次呼叫資料語言,並不需要頻繁的請求跟關閉,浪費資源。
資料庫連線池負責分配、管理和釋放資料庫連線,它允許應用程式重複使用一個現有的資料庫連線,而不是再重新建立一個;釋放空閒時間超過最大空閒時間的資料庫連線來避免因為沒有釋放資料庫連線而引起的資料庫連線遺漏。這項技術能明顯提高對資料庫操作的效能。
C3P0資料池的設計
package com.shao.util;
import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class C3P0Util {
//得到一個數據源
private static ComboPooledDataSource dataSource;
public static void initParam() throws PropertyVetoException{
dataSource=new ComboPooledDataSource();
/*
* 設定資料來源的各項屬性值
*/
//資料使用者名稱
dataSource.setUser("root");
//資料庫密碼
dataSource.setPassword("root");
//資料庫連線URL
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/atm");
//資料庫連線驅動,注意:必須在專案中匯入對應資料庫的驅動jar包
dataSource.setDriverClass("com.mysql.jdbc.Driver");
//初始化大小
dataSource.setInitialPoolSize(5);
//最小池大小
dataSource.setMinPoolSize(1);
//最大池大小
dataSource.setMaxPoolSize(10);
dataSource.setMaxStatements(50);
dataSource.setMaxIdleTime(60);
}
public static DataSource getDataSource() {
try {
initParam();
} catch (PropertyVetoException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return dataSource;
}
//從資料來源中得到一個連線物件
public static Connection getConnection() {
try {
return getDataSource().getConnection();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
C3P0資料池的管理
package com.shao.util;
import java.sql.Connection;
import java.sql.SQLException;
public class ManagerThreadLocal {
private static ThreadLocal<Connection> tl = new ThreadLocal<>();
public static Connection getConnection(){
Connection conn = tl.get();
if(conn==null){
conn = C3P0Util.getConnection();
tl.set(conn);
}
return conn;
}
/**
* 開啟事務
*/
public static void startTransaction(){
try {
getConnection().setAutoCommit(false);//設定開啟事務
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 事務回滾
*/
public static void rollback(){
try {
getConnection().rollback();//回滾事務
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 提交事務
*/
public static void commit(){
try {
getConnection().commit();//回滾事務
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void close(){
try {
getConnection().close();//把連線放入池裡
tl.remove();//釋放當前執行緒
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
在這裡,我將事務自動提交功能關閉,每次程式碼的操作,若果未能提交成功,回滾事務,防止對資料庫的誤操作,引入ThreadLocal,ThreadLocal是怎麼實現了多個執行緒之間每個執行緒一個變數副本的?它是如何實現共享變數的。
ThreadLocal提供了set和get訪問器用來訪問與當前執行緒相關聯的執行緒區域性變數。
get函式就是從當前執行緒的threadlocalmap中取出當前執行緒對應的變數的副本【注意,變數是儲存線上程中的,而不是儲存在ThreadLocal變數中】。當前執行緒中,有一個變數引用名字是threadLocals,這個引用是在ThreadLocal類中createmap函式內初始化的。每個執行緒都有一個這樣的threadLocals引用的ThreadLocalMap,以ThreadLocal和ThreadLocal物件宣告的變數型別作為引數。這樣,我們所使用的ThreadLocal變數的實際資料,通過get函式取值的時候,就是通過取出Thread中threadLocals引用的map,然後從這個map中根據當前threadLocal作為引數,取出資料。
具體程式碼,稍後奉上,如果喜歡的,請點贊留言好發。