架构探险——第二章(为web应用添加业务功能)
2015-09-08 16:33
465 查看
第二章不使用框架完成了自己的Web应用。
第一版
在Service的静态代码块中获取config.properties配置文件中与JDBC相关的配置项。在service的业务方法中获取数据库的连接,并进行数据库的操作,finally中关闭数据库。
存在的问题:
1.在service中读取config.properties文件,不合理,其他service使用的时候反复进行io。
2.执行一条SQL语句需要编写一大堆代码,并且使用try...catch...finally结构,开发效率不高)
第二版
开发DatabaseHelper来读取配置文件,获取数据库连接,关闭数据库连接。(解决了第一个问题)
使用Apache Common项目中的DbUtils类库,在DatabaseHelper中写SQL公共类,通过传参的形式,利用反射,执行对应的SQL。(解决了第二个问题)
存在的问题:
1.由于Connection是static变量,(静态对象可以节省频繁访问引起的频繁分配内存、释放内存、占用内存的性能开销)但是这样是线程不安全的。
第三版
使用ThreadLocal来存放本地线程变量。在每次获取Connection的时候,在ThreadLocal中查找,不存在,则新创建一个连接。
存在的问题:每次都需要创建一个Connection,然后进行数据库操作,然后关闭。
第四版
引入了DBCP数据库连接池
在这个过程中,黄老师已经教我们开发了一个轻量级的JDBC框架。
最终代码
ThreadLocal的用法——传送门-ThreadLocal那点事儿
重点:
服务层的完善优化过程,思路
在看这一段的时候引起了无数次的共鸣。相信大家在开始接触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那点事儿
相关文章推荐
- 奥普思凯---这是一个神奇的网站
- Activity(一):MVC模式架构篇
- [PHP自动化-进阶]002.CURL模拟登录带有验证码的网站
- 网站分析(Google Analytics)学习资料
- 网站用户体验,你要如何提升?
- armv7架构下lubuntu系统apt-get安装ffmpeg方法
- 游戏服务器架构设计(2)
- 游戏服务器架构设计(一)
- 网站502自动重启服务
- ios 提升的网站 -- 精髓
- 一些简单的学习网站
- WEB服务架构
- 网站禾 只 分之我见
- wpa_supplicant软件架构分析
- 架构设计:负载均衡层设计方案(5)——LVS单节点安装
- 【分享】分享一个值得前端开发收藏的网站
- lvs+keepalived+mha高可用环境搭建过程中遇到的问题
- VIEWGOOD(远古)政府网站视频互动服务系统解决方案
- PV、UV、IP分别是什么意思?
- MIT评选出的全球最聪明的50个公司-完整名单(附带往年名单)!