一,前言
通过上一节对服务层的优化:
提取数据库配置信息到外部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对于开发者完全透明
下一节将对此部分进行优化