MySQL数据库入门学习(五)——使用工具类封装JDBC实现MySQL的查询操作
1.前言
我们知道,事实上,MySQL的 “增删查改”其实就是分为两类,一类是更新操作:int executeUpdate(String sql)包括了插入(insert),更新(update),删除(delete);另外一类是查询操作(select),由ResultSet executeQuery(String sql) 或者 ResultSet executeQuery() 实现。在上篇文章:MySQL数据库入门学习(四)——使用工具类封装JDBC实现MySQL的更新操作中已经实现了自定义封装的MySQL的更新操作。现在我们开始对查询操作进行封装.
2.查询操作的步骤
2.1首先观察一个查询方法
/**
* 通过ID查询book
* @param id 要查询的book的ID
* @return 返回ID对应的book
*/
public Book findBookById(int id) {
//需要执行的查找的sql语句
String sql = "select * from book where id = ?";
//结果集
ResultSet resultSet = null;
Book book = null;
try {
//获取创建连接
Connection connection = JDBCUtil.getConnection();
//创建预处理对象
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//设置id占位符对应的值
preparedStatement.setInt(1, id);
//开始执行查询语句,并返回查询的结果集
resultSet = preparedStatement.executeQuery();
//如果查询到结果不为空而是有记录
if(resultSet.next()) {
//获取book的name
String name = resultSet.getString("name");
//获取book的status
byte status = resultSet.getByte("status");
//获取book的price
double price = resultSet.getDouble("price");
//获取book的discount
float discount = resultSet.getFloat("discount");
//获取book的isBorrowed
boolean isBorrowed = resultSet.getBoolean("isBorrowed");
//获取book的createTime
Date date = resultSet.getDate("createTime");
book = new Book();
book.setBorrowed(isBorrowed);
book.setDiscount(discount);
book.setId(id);
book.setPrice(price);
book.setName(name);
book.setStatus(status);
book.setCreateTime(date);
}
//释放资源,先开启的后释放
JDBCUtil.close(connection, preparedStatement, resultSet);
} catch (SQLException e) {
e.printStackTrace();
book = null;
}
return book;
}
我们发现,查询(query)操作有这几个步骤:
①获取连接对象Connection 。
②根据sql语句创建预处理对象PreparedStatement
③使用实际参数替换PreparedStatement 中的占位符“?”。
④执行查询操作:preparedStatement.executeQuery(),得到结果集ResultSet。
⑤封装结果集ResultSet到实体对象book中。
⑥关闭资源
⑦返回结果对象book。
这个是对于方法 public Book findBookById(int id);来说,它的参数只有一个,但是在有些查询情况中,查询的条件肯定不止一个,因此来说,我们可以将这个查询条件用一个可变的Object数组params来表示。然后preparedStatement.setXXX(int parameterIndex, XXX x);中XXX也就是填充的实际参数类型是不确定的。这时候我们可以使用preparedStatement.setObject(int parameterIndex, Object x)来进行设置参数。因为Object是所有类的公共父类,所以使用这个参数可以达到代码通用性来设置占位符“?"。
2.2抽取通用的查询方法
作为一个通用的查询方法,查询不同的对象时候返回的结果对象不同,比如说查询学生Student那么返回的是student对象,查询book,那么返回的是book对象等。因此这个通用的查询方法返回的是一个泛型对象,交给查询者指定:
public static <T> T query(String sql,Object... params)
但是我们知道,这样子通过preparedStatement.setObject(i+1,params[i]);后执行 ResultSet result =preparedStatement.executeQuery();得到的是一个结果集ResultSet ,这是时候我们需要对这个结果集封装成对应的实体对象。由此我们需要指定一个处理器ResultSetHandler专门处理这个结果集。这里定义一个接口:
/**
* @author 陌意随影
TODO :结果集处理器。
*2021年2月18日 下午12:44:11
*/
public interface ResultSetHandler<T> {
/**
* @param resultSet 查询的结果集
* @return 返回一个实体对象
*/
T handleResutl(ResultSet resultSet);
}
这样,我们定义的这个查询方法抽取为:
public static <T> T query(String sql, ResultSetHandler<T> resultSetHandler,Object... params);
这个ResultSetHandler接口我们可以由查询者自定义实现这个接口,然后在这个T handleResutl(ResultSet resultSet);方法中将ResultSet封装成一个实体对象T并返回即可。
2.3完整的查询方法代码
/**
* 执行sql的查询语句。
* @param sql 需要执行的sql语句
* @param params 预处理占位符中的实际参数数组
* @resultSetHandler 结果集处理器,负责将结果集ResultSet封装成对象。
* @return 返回查询的对象。
*/
public static <T> T query(String sql, ResultSetHandler<T> resultSetHandler,Object... params){
if (params==null) return null;
//获取连接对象
Connection connection=JDBCUtil.getConnection();
PreparedStatement preparedStatement=null;
ResultSet resultSet = null;
try {
//创建预处理对象
preparedStatement= connection.prepareStatement(sql);
//使用实际参数替换占位符
for (int i= 0;i < params.length;i++){
//parameterIndex从1开始
preparedStatement.setObject(i+1,params[i]);
}
//执行sql查询语句
resultSet = preparedStatement.executeQuery();
} catch (SQLException e) {
e.printStackTrace();
}
//关闭资源
JDBCUtil.close(connection,preparedStatement,null);
//通过处理器处理这个结果集,封装成一个实体对象
T t = resultSetHandler.resultSetHandler(resultSet);
return t;
}
3.实现查询book的方法
3.1首先自定义实现一个book的结果集处理器,对结果集进行封装成一个对象
/**
* @author 陌意随影
TODO :book的结果集处理实现类
*2021年2月18日 下午1:26:07
*/
public class BookResultSetHandlerImpl implements ResultSetHandler<List<Book>>{
@Override
public List<Book> resultSetHandler(ResultSet resultSet) {
List<Book> bookList = new ArrayList<>();
try {
//如果查询到结果不为空而是有记录
while(resultSet.next()) {
//获取book的ID
int id = resultSet.getInt("id");
//获取book的name
String name = resultSet.getString("name");
//获取book的status
byte status = resultSet.getByte("status");
//获取book的price
double price = resultSet.getDouble("price");
//获取book的discount
float discount = resultSet.getFloat("discount");
//获取book的isBorrowed
boolean isBorrowed = resultSet.getBoolean("isBorrowed");
//获取book的createTime
Date date = resultSet.getDate("createTime");
Book book = new Book();
book.setBorrowed(isBorrowed);
book.setDiscount(discount);
book.setId(id);
book.setPrice(price);
book.setName(name);
book.setStatus(status);
book.setCreateTime(date);
bookList.add(book);
}
} catch (Exception e) {
e.printStackTrace();
}
return bookList;
}
3.2查询所有book
/**
* 查询所有图书
* @return 返回List<book>
*/
public List<Book> findAllBook() {
//拼接需要执行的查找的sql语句
String sql = "select * from book ";
//结果集
List<Book> bookList = JDBCUtil.query(sql, new BookResultSetHandlerImpl());
return bookList;
}
3.3通过ID查询book
/**
* 通过ID查询book
* @param id 要查询的book的ID
* @return 返回ID对应的book
*/
public Book findBookById(int id) {
//需要执行的查找的sql语句
String sql = "select * from book where id = ?";
//结果集
List<Book> bookList = JDBCUtil.query(sql, new BookResultSetHandlerImpl(),id);
if (bookList == null || bookList.size() == 0 ) {
return null;
}
//根据ID查询只有一个对象
Book book = bookList.get(0);
return book;
}
4.测试