架构探险-第二章:为Web应用添加业务功能(4)-优化服务层-提取DatabaseHelper和使用DbUtils

一,前言

通过上一节对服务层的优化:
    提取数据库配置信息到外部properties配置文件
    在Service中通过读取外部properties配置文件获取连接信息
目前Service层还存在一些问题:
    1)在CustomerService类中读取config.properties文件,是不合理的
    开发中会存在多个Service,所以要将这些公共代码提取重来以便于复用
    2)执行一条Sql语句需要写一大堆代码,还有try...catch...finally结构,开发效率不高
这篇就针对这两个问题进行优化和处理

二,优化服务层-提取DatabaeHelper

创建org.smart4j.chapter2.helper包
在该包下创建DatabaeHelper类-数据库操作助手类

DatabaeHelper中包含一些静态方法,封装了数据库相关操作
目前提供"获取数据库连接"和"关闭数据库连接"两个助手方法

DatabaeHelper.java:


/**
 * 数据库助手类
 */
public final class DatabaseHelper {

    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;

    /**
     * 静态初始化
     *      读取数据库配置文件
     */
    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) {
            e.printStackTrace();
        }
    }

    /**
     * 获取数据库连接
     */
    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);
            }
        }
    }
}

有了DatabaeHelper助手类,就可以对CustomerService做一下简化:
CustomerService.java:

public class CustomerService {

    private static final Logger LOGGER = LoggerFactory.getLogger(CustomerService.class);

    /**
     * 获取客户列表
     */
    public List<Customer> getCustomerList() {
        Connection conn = null;
        try{
            List<Customer> customerList = new ArrayList<Customer>();
            String sql = "select * from customer";
            // 使用DatabaseHelper封装的方法,获取数据库连接
            conn = DatabaseHelper.getConnection();
            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("execute sql failure", e);
        }finally {
            // 使用DatabaseHelper封装的方法,获取数据库连接
            DatabaseHelper.closeConnection(conn);
        }
        return null;
    }
}
通过DatabaseHelper对以上两处("获取数据库连接"和"关闭数据库连接")进行了简化
目前多个Service类可以重用这些代码,而不必在每个Service类中重复写静态变量与代码块了

三,优化服务层-使用DbUtils

目前执行一条Sql语句需要写一大堆代码,还有try...catch...finally结构,开发效率不高
这里使用Apache Common项目的DbUtils类库
DbUtils为我们提供了一个JDBC的封装

1,在pom.xml中添加DbUtils依赖:

<!-- Apache Commons DbUtils -->
<dependency>
    <groupId>commons-dbutils</groupId>
    <artifactId>commons-dbutils</artifactId>
    <version>1.6</version>
</dependency>

2,在DatabaseHelper中使用DbUtils

// DbUtils类库提供的QueryRunner对象可以面向实体(Entity)进行查询
private static final QueryRunner QUERY_RUNNER = new QueryRunner();

/**
 * 查询实体列表
 */
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;
}

3,CustomerService使用DatabaseHelper提供的获取实体列表方法
简化后的获取客户列表方法:

/**
 * 获取客户列表
 */
public List<Customer> getCustomerList() {
    Connection conn = DatabaseHelper.getConnection();
    try{
        String sql = "select * from customer";
        return DatabaseHelper.queryEntityList(Customer.class, sql);
    }finally {
        // 使用DatabaseHelper封装的方法,获取数据库连接
        DatabaseHelper.closeConnection(conn);
    }
}

运行测试:

这里写图片描述

通过使用DbUtils提供的QueryRunner对象
不再面对 PreparedStatement 与 ResultSet 对象了

我们对获取实体对象列表方法做了进一步封装
将queryEntityList方法封装到DatabaseHelper类中,便于Service复用

四,结尾

本节针对之前服务层存在的两个问题,对服务层进行了优化
    1,提取DatabaeHelper类,便于多Service复用数据库相关操作的方法
    2,使用DbUtils解决数据库查询时大量重复代码问题
目前仍存在需优化的问题:
    每次执行数据库操作时,都需要新创建一个Connection对象,操作完成后关闭
    如何能将这部分操作从Service中移除,是Connection对于开发者完全透明
下一节将对此部分进行优化

猜你喜欢

转载自blog.csdn.net/abap_brave/article/details/80436409
今日推荐