笔者之前写过一篇通过JDBC操作MySQL数据库,文章内容对使用 JDBC 操作数据库过程的各个步骤进行了说明,并在最后给出了一个小的样例。
此次,将尝试使用一种新的方式进行公共操作的封装。在样例程序中也将使用数据访问层和业务层的模式进行模块划分。
连接到数据库并在使用完成之后释放资源的方法封装。
public class BaseDao {
/*
* 不同的数据库甚至同一数据库的不同版本,在不同的驱动包下配置信息都有所不同
*/
private static final String CLASS_NAME = "com.mysql.cj.jdbc.Driver";
private static final String URL = "jdbc:mysql://127.0.0.1:3306/databasename?useSSL=FALSE&serverTimezone=UTC&characterEncoding=utf8";
private static final String USER_NAME = "username";
private static final String PASSWORD = "password";
public Connection getConnection() {
Connection connection = null;
try {
// 加载驱动
Class.forName(CLASS_NAME);
// 获取数据库连接对象
connection = DriverManager.getConnection(URL, USER_NAME, PASSWORD);
} catch (Exception e) {
e.printStackTrace();
}
return connection;
}
public void closeAll(Connection connection, PreparedStatement statement, ResultSet resultSet) {
/*
* 当且仅当资源对象不为 null 的时候进行资源的关闭与释放
* 释放资源的时候, 先释放结果集, 再释放操作对象, 最后释放连接对象
*/
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
} // end if
} // end method
}
增删改查 实际上是增删改和查操作。即更新和查询两种分类。
如果是更新操作,返回的是数据库中受影响的行数,使用 int 接收即可;如果是查询操作,返回的是结果集ResultSet,一般情况下,还要继续对结果集中的信息进行读取并封装成想要的数据格式。
以图书查询为例,创建一个属性较为简单的实体类 Book。
public class Book {
private Long bookId;
private String bookName;
private double price;
// constructor
// getters and setters
// toString
}
如果按照面向接口编程,应该首先使用接口定义方法,然后在实现类中实现这些方法。
public interface BookDao {
// 添加书籍到数据库
int insertBook(Book book);
// 根据编号删除图书
int deleteBookById(Long bookId);
// 修改图书信息
int updateBook(Book book);
// 查询所有图书
List selectAllBooks();
// 根据书名进行模糊查询
List selectBooksByName(String bookName);
// 根据编号查询具体的一本书
Book selectBookById(Long bookId);
// 其他查询, 根据要求进行补充
}
在 DAO 的具体实现类中,实现 BookDao 接口,对其中的方法进行实现。可以通过继承 BaseDao 然后调用其中方法,也可以将 BaseDao 作为成员变量然后创建实例对象调用方法。本例使用继承实现重用。
public class BookDaoImpl extends BaseDao implements BookDao {
// 添加书籍到数据库
public int insertBook(Book book) {
// 记录数据库受影响行数
int count = 0;
// 数据库连接对象
Connection connection = null;
// 数据库操作对象
PreparedStatement statement = null;
// 添加图书的 SQL 语句, id 自增, 不需要设置
String sqlString = "insert into t_book(bname,bprice) values(?,?)";
try {
// 获取数据库连接对象
connection = this.getConnection();
// 使用数据库连接对象和 SQl 语句创建预编译的数据库操作对象
statement = connection.prepareStatement(sqlString);
// 给占位符赋值
statement.setString(1, book.getBookName());
statement.setDouble(2, book.getPrice());
// 执行添加图书的操作, 更新操作统一使用 executeUpdate()
count = statement.executeUpdate();
} catch(Exception e) {
e.printStackTrace();
return 0;
} finally {
// 因为更新操作没有结果集对象, 所有传入 null
this.closeAll(connection, statement, null);
}
return count;
}
// 根据编号删除图书
public int deleteBookById(Long bookId) {
// 记录数据库受影响行数
int count = 0;
// 数据库连接对象
Connection connection = null;
// 数据库操作对象
PreparedStatement statement = null;
// 删除图书的 SQL 语句
String sqlString = "delete from t_book where bid = ?";
try {
// 获取数据库连接对象
connection = this.getConnection();
// 使用数据库连接对象和 SQl 语句创建预编译的数据库操作对象
statement = connection.prepareStatement(sqlString);
// 给占位符赋值
statement.setLong(1, bookId);
// 执行删除图书的操作
count = statement.executeUpdate();
} catch(Exception e) {
e.printStackTrace();
return 0;
} finally {
this.closeAll(connection, statement, null);
}
return count;
}
// 修改图书信息
public int updateBook(Book book) {
// 记录数据库受影响行数
int count = 0;
// 数据库连接对象
Connection connection = null;
// 数据库操作对象
PreparedStatement statement = null;
// 更新图书的 SQL 语句
String sqlString = "update t_book set bname = ?, bprice = ? where bid = ?";
try {
// 获取数据库连接对象
connection = this.getConnection();
// 使用数据库连接对象和 SQl 语句创建预编译的数据库操作对象
statement = connection.prepareStatement(sqlString);
// 给占位符赋值
statement.setString(1, book.getBookName());
statement.setDouble(2, book.getPrice());
statement.setLong(3, book.getBookId());
// 执行更新图书的操作
count = statement.executeUpdate();
} catch(Exception e) {
e.printStackTrace();
return 0;
} finally {
this.closeAll(connection, statement, null);
}
return count;
}
// 查询所有图书
public List selectAllBooks() {
// 用于封装查询结果的 List
List booksList = new ArrayList<>();
// 数据库连接对象
Connection connection = null;
// 数据库操作对象
PreparedStatement statement = null;
// 接收查询的结果集
ResultSet resultSet = null;
// 查询语句
String sqlString = "select bid,bname,bprice from t_book";
try {
// 获取数据库连接
connection = this.getConnection();
// 构造数据库操作对象
statement = connection.prepareStatement(sqlString);
// 执行查询操作, executeQuerty()
resultSet = statement.executeQuery();
// 将结果集中的查询结果封装到 List
while (resultSet.next()) {
Book book = new Book();
book.setBookId(resultSet.getLong("bid"));
book.setBookName(resultSet.getString("bname"));
book.setPrice(resultSet.getDouble("bprice"));
booksList.add(book);
}
} catch(Exception e) {
e.printStackTrace();
return null;
} finally {
this.closeAll(connection, statement, resultSet);
}
return booksList;
}
// 根据书名进行模糊查询, 与上面的方法仅仅时 SQL 语句的区别(注意为占位符赋值)
public List selectBooksByName(String bookName) {
// 用于封装查询结果的 List
List booksList = new ArrayList<>();
// 数据库连接对象
Connection connection = null;
// 数据库操作对象
PreparedStatement statement = null;
// 接收查询的结果集
ResultSet resultSet = null;
// 查询语句
String sqlString = "select bid,bname,bprice from t_book where bname like ?";
try {
// 获取数据库连接
connection = this.getConnection();
// 构造数据库操作对象
statement = connection.prepareStatement(sqlString);
// 为占位符赋值, 模糊查询的通配符在这里设置
statement.setString(1, "%" + bookName + "%");
// 执行查询操作, executeQuerty()
resultSet = statement.executeQuery();
// 将结果集中的查询结果封装到 List
while (resultSet.next()) {
Book book = new Book();
book.setBookId(resultSet.getLong("bid"));
book.setBookName(resultSet.getString("bname"));
book.setPrice(resultSet.getDouble("bprice"));
booksList.add(book);
}
} catch(Exception e) {
e.printStackTrace();
return null;
} finally {
this.closeAll(connection, statement, resultSet);
}
return booksList;
}
// 根据编号查询具体的一本书
public Book selectBookById(Long bookId) {
// 用于封装查询结果的 Book 对象, 设置为 null 而不是直接创建对象, 当查询出错时返回 null 有助于业务层的判断
Book book = null;
// 数据库连接对象
Connection connection = null;
// 数据库操作对象
PreparedStatement statement = null;
// 接收查询的结果集
ResultSet resultSet = null;
// 查询语句
String sqlString = "select bid,bname,bprice from t_book where bid = ?";
try {
// 获取数据库连接
connection = this.getConnection();
// 构造数据库操作对象
statement = connection.prepareStatement(sqlString);
// 为占位符赋值, 模糊查询的通配符在这里设置
statement.setLong(1, bookId);
// 执行查询操作, executeQuerty()
resultSet = statement.executeQuery();
// 将结果集中的查询结果封装到 List
while (resultSet.next()) {
book = new Book();
book.setBookId(resultSet.getLong("bid"));
book.setBookName(resultSet.getString("bname"));
book.setPrice(resultSet.getDouble("bprice"));
}
} catch(Exception e) {
e.printStackTrace();
return null;
} finally {
this.closeAll(connection, statement, resultSet);
}
return book;
}
}
实际上,在 DAO 层就已经完成了所有的数据库操作。但是这仍然给出业务层的实现并通过业务层进行单元测试。
// 略过接口
public class BookServiceImpl {
private BookDao bookDao = null;
public BookServiceImpl() {
// 创建对象的时候给 bookDao 赋值
bookDao = new BookDaoImpl();
}
// 添加书籍到数据库
public Boolean addBook(Book book) {
int count = bookDao.insertBook(book);
if (count == 1) {
return true;
} else {
return false;
}
}
// 根据编号删除图书
public Boolean removeBookById(Long bookId) {
int count = bookDao.deleteBookById(bookId);
if (count > 0) {
return true;
} else {
return false;
}
}
// 修改图书信息
public Boolean updateBook(Book book) {
int count = bookDao.updateBook(book);
if (count > 0) {
return true;
} else {
return false;
}
}
// 查询所有图书
public List getAllBooks() {
return bookDao.selectAllBooks();
}
// 根据书名进行模糊查询
public List getBooksByName(String bookName) {
return bookDao.selectBooksByName(bookName);
}
// 根据编号查询具体的一本书
public Book getBookById(Long bookId) {
return bookDao.selectBookById(bookId);
}
}
public class BookServiceImplTest {
@Test
public void testAddBook() throws Exception {
Book book = new Book("三国演义", 89);
BookServiceImpl service = new BookServiceImpl();
if (service.addBook(book)) {
System.out.println("添加成功");
} else {
System.out.println("添加失败");
}
}
@Test
public void testRemoveBookById() throws Exception {
BookServiceImpl service = new BookServiceImpl();
if (service.removeBookById(1L)) {
System.out.println("删除成功");
} else {
System.out.println("删除失败");
}
}
@Test
public void testUpdateBook() throws Exception {
Book book = new Book(1L, "三国演义", 89.92);
BookServiceImpl service = new BookServiceImpl();
if (service.updateBook(book)) {
System.out.println("更新成功");
} else {
System.out.println("更新失败");
}
}
@Test
public void testGetAllBooks() throws Exception {
BookServiceImpl service = new BookServiceImpl();
List list = service.getAllBooks();
for (Book book : list) {
System.out.println(book);
}
}
@Test
public void testGetBooksByName() throws Exception {
BookServiceImpl service = new BookServiceImpl();
List list = service.getBooksByName("演义");
for (Book book : list) {
System.out.println(book);
}
}
@Test
public void testGetBookById() throws Exception {
BookServiceImpl service = new BookServiceImpl();
Book book = service.getBookById(1L);
System.out.println(book);
}
}
本篇博客所有代码均使用记事本书写,没有借助工具检测,可能存在拼写错误,欢迎读者朋友们指正。