使用JDBC连接和操作数据库

写在前面

笔者之前写过一篇通过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
}

在 DAO 层进行增删改查操作

增删改查 实际上是增删改和查操作。即更新和查询两种分类。
如果是更新操作,返回的是数据库中受影响的行数,使用 int 接收即可;如果是查询操作,返回的是结果集ResultSet,一般情况下,还要继续对结果集中的信息进行读取并封装成想要的数据格式。 

在数据操作之前,先封装一个实体类

以图书查询为例,创建一个属性较为简单的实体类 Book。

public class Book {
    
    private Long bookId;
    private String bookName;
    private double price;
    
    // constructor
    // getters and setters
    // toString
}

BookDao

如果按照面向接口编程,应该首先使用接口定义方法,然后在实现类中实现这些方法。

public interface BookDao {
    // 添加书籍到数据库
    int insertBook(Book book);
    // 根据编号删除图书
    int deleteBookById(Long bookId);
    // 修改图书信息
    int updateBook(Book book);
    // 查询所有图书
    List<Book> selectAllBooks();
    // 根据书名进行模糊查询
    List<Book> 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<Book> selectAllBooks() {
        // 用于封装查询结果的 List
        List<Book> 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<Book> selectBooksByName(String bookName) {
        // 用于封装查询结果的 List
        List<Book> 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<Book> getAllBooks() {
        return bookDao.selectAllBooks();
    }
    // 根据书名进行模糊查询
    public List<Book> 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<Book> list = service.getAllBooks();
        for (Book book : list) {
            System.out.println(book);
        }
    }
    @Test
    public void testGetBooksByName() throws Exception {
        BookServiceImpl service = new BookServiceImpl();
        List<Book> 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);
    }
}

 说明:

本篇博客所有代码均使用记事本书写,没有借助工具检测,可能存在拼写错误,欢迎读者朋友们指正。

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值