outline
对JDBC的CRUD操作的通用代码进行提取,封装为工具。
共4个源代码文件,其中1个为测试文件。
DBConfig.java
数据库配置接口
RowMapper.java
策略接口,读取数据时需要将ResultSet
数据映射为Java Object
对象。
DBUtil.java
对外提供两个工具方法:read
(select)和write
(insert, delete, update)。
TestDBUtil.java
测试CRUD。
keys
- 开闭原则(Open Close Principle)
- 单一职责原则(Single Responsibility Principle)
- 策略模式(Strategy Pattern)
- 泛型方法(Generic Method)
数据库配置 DBConfig.java
- 变化的量不应该写死在工具类中,否则以后改配置还需要修改源代码。
- 常规操作应该是写在配置文件中,用程序读取解析。
- 此处不引入配置文件,直接将配置参数作为接口中的公有常量。
package cn.jt.util.db;
public interface DBConfig {
String className = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/vms";
String user = "root";
String password = "root";
}
策略接口 RowMapper.java
package cn.jt.util.db;
import java.sql.ResultSet;
/**
* 策略接口
* @author wyj
*
* @param <T> 每行记录最终封装好的类型。
*/
public interface RowMapper<T> {
/**
* 将一行记录封装,返回对应的一个对象。
* @param rs 换行后的结果集对象
* @return
*/
T mapRow(ResultSet rs);
}
数据库读写工具 DBUtil
- 数据库的四种操作CRUD(Create, Retrieve, Update, Delete),就是两种基本操作:读写。
- 抽取公有操作,封装起来,变化的部分由参数入口传入。
- write(sql, params),写操作,setObject()帮了大忙。
- read(rm, sql, params),为了抽取所有读操作的共性,引入一个策略接口(strategy pattern)。
- 策略接口帮助我们写更少的代码。动态地完成不同的需求。
package cn.jt.util.db;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* 数据库操作工具,只对外显示读写通用操作。
* @author wyj
*/
public class DBUtil implements DBConfig {
/**
* 通用查询方法,需要传入一个实现了策略接口的匿名类的实例对象。
* @param rm
* @param sql
* @param params
* @return
*/
public static <T> List<T> read(RowMapper<T> rm, String sql, Object...params) {
List<T> list = new ArrayList<T>();
Connection con = DBUtil.getCon();
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
pstmt = con.prepareStatement(sql);
if (params != null) {
for (int i = 0; i < params.length; i++) {
pstmt.setObject(i + 1, params[i]);
}
}
// System.out.println("读SQL:" + pstmt);
rs = pstmt.executeQuery();
while (rs.next()) {
T t = rm.mapRow(rs);
list.add(t);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtil.closeSrc(pstmt, rs, con);
}
return list;
}
/**
* 通用更新。利用setObject(xxx)方法的通用性。
* @param sql
* @param params
* @return
*/
public static int write(String sql, Object...params) {
int rowAffect = 0;
Connection con = DBUtil.getCon();
PreparedStatement pstmt = null;
try {
con.setAutoCommit(false); // 不自动提交。
pstmt = con.prepareStatement(sql);
// 客户端可能在params的位置传入null。
if (params != null) {
// 若params.length == 0,则不会进入此分支。
for (int i = 0; i < params.length; i++) {
pstmt.setObject(i + 1, params[i]);
}
}
// System.out.println("写SQL:" + pstmt);
rowAffect = pstmt.executeUpdate(); // 执行更新
con.commit(); // 执行提交
} catch (SQLException e) {
e.printStackTrace();
try {
con.rollback(); // 出错则回滚。
} catch (SQLException e1) {
e1.printStackTrace();
}
} finally {
DBUtil.closeSrc(pstmt, null, con);
}
return rowAffect;
}
/**
* 获取连接
* @return
*/
private static Connection getCon() {
Connection con = null;
try {
Class.forName(className);
con = DriverManager.getConnection(url, user, password);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return con;
}
/**
* 释放三种资源
* @param pstmt
* @param rs
* @param con
*/
private static void closeSrc(PreparedStatement pstmt, ResultSet rs, Connection con) {
close(pstmt);
close(rs);
close(con);
}
/**
* 关闭单份资源
* @param cse
*/
private static void close(AutoCloseable cse) {
if (cse != null) {
try {
cse.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
测试CRUD TestDBUtil.java
用户自己新建数据库表users
,自建JavaBean类User
。后测试:
package cn.jt.test;
import cn.jt.pojo.User;
import cn.jt.util.db.DBUtil;
import cn.jt.util.db.RowMapper;
import org.junit.Test;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
/**
* 测试DBUtil
*
* @author wyj
* @create 2019-04-22 18:31
*/
public class TestDBUtil {
@Test
public void testRead() {
// 从数据库读回的数据需要用一个策略接口下的实例。
RowMapper<User> mapper = new RowMapper<User>() {
@Override
public User mapRow(ResultSet rs) throws SQLException {
User user = new User();
user.setId(rs.getInt("id"));
user.setPhone(rs.getString("phone"));
user.setEmail(rs.getString("email"));
return user;
}
};
// 无参数查询
// String sql = "select id, phone, email from users";
// Object[] params = {};
// 带参数的查询
String sql = "select id, phone, email from users where id = ?";
Object[] params = {new Integer(3)};
List<User> userList = DBUtil.read(mapper, sql, params);
for (User user : userList) {
System.out.println(user);
}
}
@Test
public void testInsert() {
String sql = "insert into users (phone, email) values (?, ?)";
Object[] params = {"123-456", "123@qq.com"};
int rowAffect = DBUtil.write(sql, params);
System.out.println(rowAffect);
}
@Test
public void testUpdate() {
String sql = "update users set email = ? where email = ?";
Object[] params = {"666666@qq.com", "123@qq.com"};
int rowAffect = DBUtil.write(sql, params);
System.out.println(rowAffect);
}
@Test
public void testDelete() {
String sql = "delete from users where email = ?";
Object[] params = {"666666@qq.com"};
int rowAffect = DBUtil.write(sql, params);
System.out.println(rowAffect);
}
}