第二章不使用框架完成了自己的Web应用。

重点:

服务层的完善优化过程,思路

在看这一段的时候引起了无数次的共鸣。相信大家在开始接触Java Web的时候,都做过类似的封装和优化。

第一版

在Service的静态代码块中获取config.properties配置文件中与JDBC相关的配置项。在service的业务方法中获取数据库的连接,并进行数据库的操作,finally中关闭数据库。

/**
* 提供客户数据服务
*/
public class CustomerServiceVersion { private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseHelper.class); private static final String DRIVER;
private static final String URL;
private static final String USERNAME;
private static final String PASSWORD;
private static final String URL; static {
Properties conf = PropsUtil.loadProps("config.properties");
DRIVER = conf.getProperty("jdbc.driver");
URL = conf.getProperty("jdbc.url");
USERNAME = conf.getProperty("jdbc.username");
PASSWORD = conf.getProperty("jdbc.password"); try {
Class.forName(DRIVER);
}catch(ClassNotFoundException e){
LOGGER.error("can not load jdbc driver",e);
}
} /**
* 获取客户列表
* @return
*/
public List<Customer> getCustomerList(){
Connection conn = null;
try {
List<Customer> customerList = new ArrayList<Customer>();
String sql = "select * from customer";
conn = DriverManager.getConnection(URL,USERNAME,PASSWORD);
PreparedStatement stmt = conn.prepareStatement(sql);
ResultSet rs = stmt.executeQuery();
while (rs.next()){
Customer customer = new Customer();
customer.setId(rs.getLong("id"));
customer.setName(rs.getString("name"));
customer.setContact(rs.getString("contact"));
customer.setTelephone(rs.getString("telephone"));
customer.setEmail(rs.getString("email"));
customer.setRemark(rs.getString("remark"));
customerList.add(customer);
}
return customerList;
}catch (SQLException e){
LOGGER.error("excute sql failure",e);
}finally {
if(conn != null){
try{
conn.close();
}catch (SQLException e){
LOGGER.error("close connection failure",e);
}
}
}
}
}

存在的问题

1.在service中读取config.properties文件,不合理,其他service使用的时候反复进行io。

2.执行一条SQL语句需要编写一大堆代码,并且使用try...catch...finally结构,开发效率不高)

第二版

开发DatabaseHelper来读取配置文件,获取数据库连接,关闭数据库连接。(解决了第一个问题)

使用Apache Common项目中的DbUtils类库,在DatabaseHelper中写SQL公共类,通过传参的形式,利用反射,执行对应的SQL。(解决了第二个问题)

/**
* 数据库助手类
*/
public final class DatabaseHelper1 { private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseHelperV.class); private static final QueryRunner QUERY_RUNNER = new QueryRunner(); private static final String DRIVER;
private static final String URL;
private static final String USERNAME;
private static final String PASSWORD;
private static final String URL; static {
Properties conf = PropsUtil.loadProps("config.properties");
DRIVER = conf.getProperty("jdbc.driver");
URL = conf.getProperty("jdbc.url");
USERNAME = conf.getProperty("jdbc.username");
PASSWORD = conf.getProperty("jdbc.password"); try {
Class.forName(DRIVER);
}catch(ClassNotFoundException e){
LOGGER.error("can not load jdbc driver",e);
}
} /**
* 获取数据库连接
*/
public static Connection getConnection() {
Connection conn = null;
try {
conn = DriverManager.getConnection(URl,USERNAME,PASSWORD);
} catch (SQLException e) {
LOGGER.error("get connection failure", e);
}
return conn;
} /**
* 关闭数据库连接
*/
public static void closeConnection(Connection conn){
if(conn != null){
try{
conn.close();
}catch (SQLException e){
LOGGER.error("close connection failure",e);
}
}
} /**
* 查询实体列表
*/
public static <T> List<T> queryEntityList(Class<T> entityClass, String sql, Object... params) {
List<T> entityList;
try {
Connection conn = getConnection();
entityList = QUERY_RUNNER.query(conn, sql, new BeanListHandler<T>(entityClass), params);
} catch (SQLException e) {
LOGGER.error("query entity list failure", e);
throw new RuntimeException(e);
}
return entityList;
}
}

存在的问题

1.由于Connection是static变量,(静态对象可以节省频繁访问引起的频繁分配内存、释放内存、占用内存的性能开销)但是这样是线程不安全的。

第三版

使用ThreadLocal来存放本地线程变量。在每次获取Connection的时候,在ThreadLocal中查找,不存在,则新创建一个连接。

/**
* 数据库助手类
*/
public final class DatabaseHelper2 { private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseHelperV.class); private static final ThreadLocal<Connection> CONNECTION_HOLDER; private static final QueryRunner QUERY_RUNNER = new QueryRunner(); private static final String DRIVER;
private static final String URL;
private static final String USERNAME;
private static final String PASSWORD;
private static final String URL; static {
CONNECTION_HOLDER = new ThreadLocal<Connection>(); Properties conf = PropsUtil.loadProps("config.properties");
DRIVER = conf.getProperty("jdbc.driver");
URL = conf.getProperty("jdbc.url");
USERNAME = conf.getProperty("jdbc.username");
PASSWORD = conf.getProperty("jdbc.password"); try {
Class.forName(DRIVER);
}catch(ClassNotFoundException e){
LOGGER.error("can not load jdbc driver",e);
}
} /**
* 获取数据库连接
*/
public static Connection getConnection() {
Connection conn = CONNECTION_HOLDER.get();
if (conn == null) {
try {
conn = DATA_SOURCE.getConnection();
} catch (SQLException e) {
LOGGER.error("get connection failure", e);
throw new RuntimeException(e);
} finally {
CONNECTION_HOLDER.set(conn);
}
}
return conn;
} /**
* 关闭数据库连接
*/
public static void closeConnection(){
Connection conn = CONNECTION_HOLDER.get();
if(conn != null){
try {
conn.close();
}catch (SQLException e){
LOGGER.error("cose connection failure",e);
throw new RuntimeException(e);
}finally {
CONNECTION_HOLDER.remove();
}
}
} /**
* 查询实体列表
*/
public static <T> List<T> queryEntityList(Class<T> entityClass, String sql, Object... params) {
List<T> entityList;
try {
Connection conn = getConnection();
entityList = QUERY_RUNNER.query(conn, sql, new BeanListHandler<T>(entityClass), params);
} catch (SQLException e) {
LOGGER.error("query entity list failure", e);
throw new RuntimeException(e);
}
return entityList;
}
}

存在的问题:每次都需要创建一个Connection,然后进行数据库操作,然后关闭。

第四版

引入了DBCP数据库连接池

/**
* 数据库助手类
*/
public final class DatabaseHelper { private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseHelper.class); private static final ThreadLocal<Connection> CONNECTION_HOLDER; private static final QueryRunner QUERY_RUNNER; private static final BasicDataSource DATA_SOURCE; static {
CONNECTION_HOLDER = new ThreadLocal<Connection>(); QUERY_RUNNER = new QueryRunner(); Properties conf = PropsUtil.loadProps("config.properties");
String driver = conf.getProperty("jdbc.driver");
String url = conf.getProperty("jdbc.url");
String username = conf.getProperty("jdbc.username");
String password = conf.getProperty("jdbc.password"); DATA_SOURCE = new BasicDataSource();
DATA_SOURCE.setDriverClassName(driver);
DATA_SOURCE.setUrl(url);
DATA_SOURCE.setUsername(username);
DATA_SOURCE.setPassword(password);
} /**
* 获取数据库连接
*/
public static Connection getConnection() {
Connection conn = CONNECTION_HOLDER.get();
if (conn == null) {
try {
conn = DATA_SOURCE.getConnection();
} catch (SQLException e) {
LOGGER.error("get connection failure", e);
throw new RuntimeException(e);
} finally {
CONNECTION_HOLDER.set(conn);
}
}
return conn;
} /**
* 执行查询语句
*/
public List<Map<String, Object>> executeQuery(String sql, Object... params) {
List<Map<String, Object>> result;
try {
Connection conn = getConnection();
result = QUERY_RUNNER.query(conn, sql, new MapListHandler(), params);
} catch (Exception e) {
LOGGER.error("execute query failure", e);
throw new RuntimeException(e);
}
return result;
}
}

在这个过程中,黄老师已经教我们开发了一个轻量级的JDBC框架。

最终代码

干货分享:

读取配置文件——Java读取Properties配置文件

ThreadLocal的用法——传送门-ThreadLocal那点事儿

架构探险——第二章(为web应用添加业务功能)的更多相关文章

  1. 读《架构探险——从零开始写Java Web框架》

    内容提要 <架构探险--从零开始写Java Web框架>首先从一个简单的 Web 应用开始,让读者学会如何使用 IDEA.Maven.Git 等开发工具搭建 Java Web 应用:接着通 ...

  2. 【EatBook】-NO.3.EatBook.3.JavaArchitecture.2.001-《架构探险:从零开始写Java Web框架》-

    1.0.0 Summary Tittle:[EatBook]-NO.3.EatBook.3.JavaArchitecture.2.001-<架构探险:从零开始写Java Web框架>- S ...

  3. 2017.12.12 架构探险-第一章-从一个简单的web应用开始

    参考来自:<架构探险>黄勇 著 1 使用IDEA搭建MAVEN项目 1.1 搭建java项目 (1)创建java项目 为了整个书籍的项目,我创建了一个工程,在这个工程里创建了每个章节的mo ...

  4. 架构探险——从零开始写Java Web框架》第二章照作

    沉下来慢慢看实现了. 越来越觉得可以和DJANGO作对比. package org.smart4j.chapter2.model; /** * Created by sahara on 2016/3/ ...

  5. 第二章、Web中使用shiro(实现登陆)

    虽然Apache Shiro的核心设计目标允许它用于保护任何基于JVM的应用程序(如命令行应用程序,服务器守护程序,Web应用程序等),但本指南将着重讨论最常见的用例:确保运行的Web应用程序一个Se ...

  6. 《架构探险——从零开始写Java Web框架》这书不错,能看懂的入门书

    这书适合我. 哈哈,结合 以前的知识点,勉强能看懂. 讲得细,还可以参照着弄出来. 希望能坚持 完成啦... 原来,JSTL就类似于DJANGO中的模板. 而servlet类中的res,req,玩了D ...

  7. 002-读书笔记-企业IT架构转型之道-阿里巴巴中台战略思想与架构实战-第二章 构建业务中台的基础-共享服务体系简介

    2.1.回归SOA的本质-服务重用 SOA理念的核心价值:松耦合的服务带来业务的复用,通过服务的编排助力业务的快速响应和创新. 现有模式多是烟囱式结合 ESB 企业总线打通不同系统间的交互. 2.2. ...

  8. 《深入理解linux内核架构》第二章 进程管理和调度

    2.1进程优先级 进程优先级 硬实时进程 软实时进程 抢占式多任务处理 2.2进程生命周期 用户太切换到核心态的办法 系统调用 中断 抢占调度模型优先级普通进程<系统调用<中断 普通进程可 ...

  9. 网络安全从入门到精通 (第二章-1) Web安全前端基础

    本文内容: 前端是什么? 前端代码 HTML CSS JS !!!醋成酒的小墨,促成就的小墨,小墨促成就,!!! 1,前端是什么? 网站一般用两部分组成,前端负责展示,后端负责处理请求. 2,前端代码 ...

随机推荐

  1. GIT 命令 操作 记录

    1.git pull时冲突的解决 1.git stash 2.git pull 3.git stash pop stash@{0} 4.修改冲突 5.git add . 6.git commit 7. ...

  2. 文件的压缩与解压XZip,XUnzip

    参考http://www.codeproject.com/KB/cpp/xzipunzip.aspx CreateZip() –创建一个空的 zip 文件 HZIP CreateZip(void *z ...

  3. ps做gif love教程(转)

    先看看效果吧: 这是在写部教程的时候,看到一个由方格组成的心.于是试着用PS做成了动画,然后加入了LOVE四个字母,看起来还可以.但是,有些复杂.复杂倒不是技术上的复杂,是做起来复杂. 来试试吧. 1 ...

  4. js运动 多物体运动含Json 但是里面数值不一样

    <!doctype html> <html> <head> <meta charset = "utf-8"> <title&g ...

  5. hdu4135-Co-prime & Codeforces 547C Mike and Foam (容斥原理)

    hdu4135 求[L,R]范围内与N互质的数的个数. 分别求[1,L]和[1,R]和n互质的个数,求差. 利用容斥原理求解. 二进制枚举每一种质数的组合,奇加偶减. #include <bit ...

  6. 第三百四十九、五十天 how can I 坚持

    昨天是忘写博客了,今天下班才突然意思到,搞框架搞了好晚.今天重新下了个好了. 昨天,把存储过程交给同事写了,啥都不会,又一堆问题,折腾了一天. 今天相对轻松些,不过事情还没完..明天又周五了. 还有昨 ...

  7. MYSQL数据库性能调优之二:定位慢查询

    windows下开启慢查询: 第一步:先查看版本 第二步查看查询日志和慢查询配置 第三步:配置开启慢查询 在my.ini配置文件的[mysqld]选项下增加: slow_query_log=TRUE ...

  8. Cisco asa 5510升级IOS和ASDM

    asa asa(config)# dir                                                                                 ...

  9. 关于设置MX记录

    简介:正确设置MX(Mail Exchanger)邮件交换记录是企业电子邮件服务稳定运行的基本条件,我们经常发现很多企业电子邮箱管理员因为设置了不符合规范的MX记录,导致重要的外部邮件退回或者丢失. ...

  10. 做 fzu oj 1106 题目学到的

    题目如下 这道题的意识就是给一个数问是否可以又阶乘之和构成,而难点主要是在于如果是7的话就是1!+3!,并不是单纯的从1的阶乘开始加,而是没顺序的,所以这题就得用到递归. (大概就是函数自己调用函数自 ...