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作为参数,取出数据。
具体代码,稍后奉上,如果喜欢的,请点赞留言好发。