使用JDBC的DAO模式完成图书管理

本文介绍了DAO模式在J2EE应用中的实现,包括Book实体类、DAO接口及其实现、数据源配置和工具类。通过DAO模式,将数据访问逻辑与业务逻辑分离,提高代码可读性和维护性。然而,代码中存在大量重复操作,后续章节将探讨如何利用模板方法和策略模式进一步优化DAO,减少重复代码并增强SQL安全性。
摘要由CSDN通过智能技术生成

      在核心J2EE模式中是这样介绍DAO模式的:为了建立一个健壮的J2EE应用,应该将所有对数据源的访问操作抽象封装在一个公共API中。用程序设计的语言来说,就是建立一个接口,接口中定义了此应用程序中将会用到的所有事务方法。在这个应用程序中,当需要和数据源进行交互的时候则使用这个接口,并且编写一个单独的类来实现这个接口在逻辑上对应这个特定的数据存储。

      DAO模式是标准的J2EE设计模式之一.开发人员使用这个模式把底层的数据访问操作和上层的商务逻辑分开。一个典型的DAO实现有下列几个组件:

  1. 一个DAO工厂类;
  2. 一个DAO接口;
  3. 一个实现DAO接口的具体类;
  4. 数据传递对象(有些时候叫做值对象).

第一步,建立数据传递对象(pojo)Book实体类

package com.wise.tiger.pojo;  
//********** import *************//  
/** 
 * 图书实体类(在Dao模式中用于各层消息--数据传递) 
 */  
public class Book{  
    /** 
     * id 
     */  
    private Integer id;  
    /** 
     * 图书名称 
     */  
    private String title;  
    /** 
     * 图书作者 
     */  
    private String author;  
    /** 
     * 图书价格 
     */  
    private float price;  
    /** 
     * 出版社信息 
     */  
    private String publisher;  
    /** 
     * 图书简介 
     */  
    private String intro;  
    /** 
     * 出版日期 
     */  
    private LocalDate publishDate = LocalDate.now();  
//********************* setter and getter *******************//  
}  

sql脚本

drop database if exists db_book;  
  
create database db_book;  
use db_book;  
  
create table tb_book(  
 id int primary key auto_increment,  
 title varchar(20) not null,  
 author varchar(20),  
 price decimal(10,2),  
 publisher varchar(30),  
 intro text,  
 publish_date date  
)  

 一个DAO接口

package com.wise.tiger.dao;  
//***************** import ******************//  
/** 
 * 图书dao接口 
 * @Author: <a href="mailto:1020zhaodan@163.com">Adan</a> 
 * @Date: 2019/4/15 0015 10:59 
 * @version: 1.0-SNAPSHOT 
 */  
public interface BookDao {  
    /** 
     * 保存一本图书 
     * @param book 图书信息 
     */  
    void persistent(Book book);  
  
    /** 
     * 根据id删除图书信息 
     * @param id id 
     */  
    void delete(Integer id);  
  
    /** 
     * 修改图书信息 
     * @param book 修改后的图书信息 
     */  
    void update(Book book);  
  
    /** 
     * 根据id获取图书信息 
     * @param id id 
     * @return 图书信息 
     */  
    Book search(Integer id);  
  
    /** 
     * 加载全部图书信息,未分页 
     * @return 全部图书信息 
     */  
    List<Book> search();  
  
    /** 
     * 获取图书总记录数 
     * @return 总记录数 
     */  
    long getCount();  
}  

 Dao接口具体实现类

package com.wise.tiger.dao.impl;  
//***************** import ******************//  
public class BookDaoImpl implements BookDao {  
    @Override  
    public void persistent(Book book) {  
        var sql = "INSERT INTO tb_book(title,author,price,publisher,intro,publish_date) VALUES (?,?,?,?,?,?)";  
        //采用try-with-resource语法确保相关资源的释放  
        try(var conn = DBHelper.getConnection();//1.通过工具类获取连接  
            var ptst = conn.prepareStatement(sql)){//2.预编译语句对象  
            //对预编译语句?占位符进行设置参数  
            ptst.setString(1,book.getTitle());  
            ptst.setString(2,book.getAuthor());  
            ptst.setFloat(3,book.getPrice());  
            ptst.setString(4,book.getPublisher());  
            ptst.setString(5,book.getIntro());  
            ptst.setString(6,book.getPublishDate());  
            //执行dml语句  
            ptst.executeUpdate();  
        }catch (SQLException e){  
            e.printStackTrace();  
        }          
    }  
  
    @Override  
    public void delete(Integer id) {  
       var sql = "DELETE FROM tb_book WHERE id = ?";  
       //采用try-with-resource语法确保相关资源的释放  
       try(var conn = DBHelper.getConnection();//1.通过工具类获取连接  
            var ptst = conn.prepareStatement(sql)){//2.预编译语句对象  
            //对预编译语句?占位符进行设置参数  
            ptst.setInt(1,id);  
            //执行dml语句  
            ptst.executeUpdate();  
        }catch (SQLException e){  
            e.printStackTrace();  
        }          
    }  
  
    @Override  
    public void update(Book book) {  
        var sql = "UPDATE tb_book SET title = ?,author=?,price=?,publisher=?,intro=?,publish_date=? WHERE id = ?";  
        //采用try-with-resource语法确保相关资源的释放  
        try(var conn = DBHelper.getConnection();//1.通过工具类获取连接  
            var ptst = conn.prepareStatement(sql)){//2.预编译语句对象  
            //对预编译语句?占位符进行设置参数  
            ptst.setString(1,book.getTitle());  
            ptst.setString(2,book.getAuthor());  
            ptst.setFloat(3,book.getPrice());  
            ptst.setString(4,book.getPublisher());  
            ptst.setString(5,book.getIntro());  
            ptst.setString(6,book.getPublishDate());  
            ptst.setInt(7,book.getId());  
            //执行dml语句  
            ptst.executeUpdate();  
        }catch (SQLException e){  
            e.printStackTrace();  
        }          
    }  
  
    @Override  
    public Book search(Integer id) {  
        Book book = null;  
        var sql = "SELECT id,title,author,price,publisher,intro,publish_date FROM tb_book WHERE id = ?";  
        //采用try-with-resource语法确保相关资源的释放  
        try(var conn = DBHelper.getConnection();//1.通过工具类获取连接  
            var ptst = conn.prepareStatement(sql)){//2.预编译语句对象  
            //对预编译语句?占位符进行设置参数  
            ptst.setInt(1,id);  
            //执行dql语句,返回结果集  
            var rs = ptst.executeQuery();  
            //处理结果集,结果集中列对应的值设置为book实体对应的属性值  
            if(rs.next()){  
                book = new Book();  
                book.setId(rs.getInt("id"));  
                book.setTitle(rs.getString("title"));  
                book.setAuthor(rs.getString("author"));  
                book.setPrice(rs.getFloat("price"));  
                book.setPublisher(rs.getString("publisher"));  
                book.setIntro(rs.getString("intro"));  
                book.setPublishDate(LocalDate.ofInstant(new Date(rs.getDate("publish_date").getTime()).toInstant(),ZoneId.systemDefault()));//java.sql.Date转LocalDate  
            }  
        }catch (SQLException e){  
            e.printStackTrace();  
        }  
        return book;          
    }  
  
    @Override  
    public List<Book> search() {  
        List<Book> books = new ArrayList<>();  
        var sql = "SELECT id,title,author,price,publisher,intro,publish_date FROM tb_book";  
         //采用try-with-resource语法确保相关资源的释放  
        try(var conn = DBHelper.getConnection();//1.通过工具类获取连接  
            var ptst = conn.prepareStatement(sql)){//2.预编译语句对象  
            //执行dql语句,返回结果集  
            var rs = ptst.executeQuery();  
            //处理结果集,结果集中列对应的值设置为book实体对应的属性值  
            while(rs.next()){  
                var book = new Book();  
                book.setId(rs.getInt("id"));  
                book.setTitle(rs.getString("title"));  
                book.setAuthor(rs.getString("author"));  
                book.setPrice(rs.getFloat("price"));  
                book.setPublisher(rs.getString("publisher"));  
                book.setIntro(rs.getString("intro"));  
                book.setPublishDate(LocalDate.ofInstant(new Date(rs.getDate("publish_date").getTime()).toInstant(),ZoneId.systemDefault()));//java.sql.Date转LocalDate  
                books.add(book);  
            }  
        }catch (SQLException e){  
            e.printStackTrace();  
        }  
        return books;  
    }  
  
    @Override  
    public long getCount() {  
        var count = 0;  
        var sql = "SELECT COUNT(1) FROM tb_book";  
        try(var conn = DBHelper.getConnection();//1.通过工具类获取连接  
            var ptst = conn.prepareStatement(sql)){//2.预编译语句对象  
            //执行dql语句,返回结果集  
            var rs = ptst.executeQuery();  
            //处理结果集,结果集中列对应的值设置为book实体对应的属性值  
            if(rs.next()){  
               count = rs.getLong(1);  
            }  
        }catch (SQLException e){  
            e.printStackTrace();  
        }  
        return count;  
    }  
}  

     Dao工厂类(非必须):针对这个Dao可能有多个实现,我们需要根据其外部配置动态获取dao的实例,该工厂专门用于创建Dao实例

public class DaoFactory {  
    private static BookDao bookDao = null;  
    private static DaoFactory instance = new DaoFactory();  
  
    private DaoFactory() {  
        try {  
            Properties prop = new Properties();  
            InputStream inStream = DaoFactory.class.getClassLoader()  
                    .getResourceAsStream("daoconfig.properties");  
            prop.load(inStream);  
            var bookDaoClass = prop.getProperty("bookDaoClass");  
            Class clazz = Class.forName(bookDaoClass);  
            bookDao = (BookDao) clazz.getDeclaredConstructor().newInstance();  
        } catch (Throwable e) {  
            throw new ExceptionInInitializerError(e);  
        }  
    }  
  
    public static DaoFactory getInstance() {  
        return instance;  
    }  
  
    public BookDao getBookDao() {  
        return bookDao;  
    }  
}  

相关配置文件

Java代码 

bookDaoClass=com.wise.tiger.dao.impl.BookDaoImpl  

 数据源配置文件

driverClassName = com.mysql.cj.jdbc.Driver  
url = jdbc:mysql:///db_book  
username = root  
password =  
  
########## 连接池配置 #############  
initialSize = 5  
maxTotal = 20  
maxIdle = 10  
minIdle = 3  
maxWaitMillis = 1000  
  
connectionProperties = serverTimezone=UTC;useSSL=false;useUnicode=true;characterEncoding=utf-8  
  
# 配置事务是否自动提交  
# defaultAutoCommit = false  
  
# 配置事务的格力级别 (READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ、SERIALIZABLE)  
# defaultTransactionIsolation = REPEATABLE_READ  

短字符指令集(枚举)

package com.wise.tiger.commons;  
  
import java.util.HashMap;  
import java.util.Map;  
  
public enum CommandLineInput {  
    FIND_ALL('a'), FIND_BY_ID('f'), INSERT('i'), UPDATE('u'), DELETE('d'), EXIT('e');  
  
    private final static Map<Character, CommandLineInput> INPUTS;  
  
    static {  
        INPUTS = new HashMap<>();  
        for (CommandLineInput input : values()) {  
            INPUTS.put(input.getShortCmd(), input);  
        }  
    }  
  
    private final char shortCmd;  
  
    CommandLineInput(char shortCmd) {  
        this.shortCmd = shortCmd;  
    }  
  
    public char getShortCmd() {  
        return shortCmd;  
    }  
  
    public static CommandLineInput getCommandLineInputForInput(char input) {  
        return INPUTS.get(input);  
    }  
}  

 工具类

package com.wise.tiger.commons;  
// ****************** import ******************//  
public class CommandLineInputHandler {  
    private BookService service = new BookServiceImplInDB();  
  
    public void printOptions() {  
        System.out.println("\n--- Book Application ---");  
        System.out.println("Please make a choice:");  
        System.out.println("(a)ll items");  
        System.out.println("(f)ind a specific item");  
        System.out.println("(i)nsert a new item");  
        System.out.println("(u)pdate an existing item");  
        System.out.println("(d)elete an existing item");  
        System.out.println("(e)xit");  
    }  
  
    public String readInput() {  
        Scanner scanner = new Scanner(System.in);  
        return scanner.nextLine();  
    }  
  
    public void processInput(CommandLineInput input) {  
        if (input == null) {  
            handleUnknownInput();  
        } else {  
            switch (input) {  
                case FIND_ALL:  
                    printAllBookItems();  
                    break;  
                case FIND_BY_ID:  
                    printBookItem();  
                    break;  
                case INSERT:  
                    insertToDoItem();  
                    break;  
                case UPDATE:  
                    updateToDoItem();  
                    break;  
                case DELETE:  
                    deleteToDoItem();  
                    break;  
                case EXIT:  
                    break;  
                default:  
                    handleUnknownInput();  
            }  
        }  
    }  
  
    private Integer askForItemId() {  
        System.out.println("Please enter the book ID:");  
        String input = readInput();  
        return Integer.parseInt(input);  
    }  
  
    private Book askForNewToDoAction() {  
        var book = new Book();  
        System.out.println("Please enter the title of the book:");  
        book.setTitle(readInput());  
        System.out.println("Please enter the author of the book:");  
        book.setAuthor(readInput());  
        System.out.println("Please enter the price of the book:");  
        book.setPrice(Float.parseFloat(readInput()));  
        System.out.println("Please enter the publisher of the book:");  
        book.setPublisher(readInput());  
        System.out.println("Please enter the intro of the book:");  
        book.setIntro(readInput());  
        return book;  
    }  
  
    private void printAllBookItems() {  
        var books = service.search();  
  
        if (books.isEmpty()) {  
            System.out.println("没有图书,赶快去添加一本吧!");  
        } else {  
            for (var book : books)  
                System.out.println(book);  
        }  
    }  
  
    private void printBookItem() {  
        var book = findBookItem();  
  
        if (book != null) {  
            System.out.println(book);  
        }  
    }  
  
    private Book findBookItem() {  
        Integer id = askForItemId();  
        var book = service.search(id);  
  
        if (book == null)  
            System.err.println("book item with ID " + id + " could not be found.");  
        return book;  
    }  
  
    private void insertToDoItem() {  
        var book = askForNewToDoAction();  
        service.save(book);  
        System.out.println("Successfully inserted book item .");  
    }  
  
    private void updateToDoItem() {  
        var book = findBookItem();  
  
        if (book != null) {  
            System.out.println(book);  
            System.out.println("Please enter the title of the book:");  
            book.setTitle(readInput());  
            System.out.println("Please enter the author of the book:");  
            book.setAuthor(readInput());  
            System.out.println("Please enter the price of the book:");  
            book.setPrice(Float.parseFloat(readInput()));  
            System.out.println("Please enter the publisher of the book:");  
            book.setPublisher(readInput());  
            System.out.println("Please enter the intro of the book:");  
            book.setIntro(readInput());  
            service.merge(book);  
            System.out.println("Successfully updated book item with ID " + book.getId() + ".");  
        }  
    }  
  
    private void deleteToDoItem() {  
        var book = findBookItem();  
        if (book != null) {  
            service.remove(book.getId());  
            System.out.println("Successfully deleted book item with ID " + book.getId() + ".");  
        }  
    }  
  
    private void handleUnknownInput() {  
        System.out.println("Please select a valid option!");  
    }  
}  

 DBHelper工具类,用于获取连接等(后续添加事务控制)

package com.wise.tiger.commons;  
// ****************** import ******************//  
public class DBHelper {  
    private static DataSource dataSource;  
    private DBHelper(){  
  
    }  
    static {  
        try {  
            var prop = new Properties();  
            prop.load(DBHelper.class.getClassLoader().getResourceAsStream("dbcp-config.properties"));  
            dataSource = BasicDataSourceFactory.createDataSource(prop);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
  
    /** 
     * 获取数据库连接对象 
     * @return Connection 
     * @throws SQLException 获取连接失败异常 
     */  
    public static Connection getConnection() throws SQLException{  
        try {  
            return dataSource.getConnection();  
        } catch (SQLException e) {  
            throw e;  
        }  
    }  
  
    /** 
     * 返回数据源DataSource 
     * @return DataSource 
     */  
    public static DataSource getDataSource() {  
        return dataSource;  
    }  
}  

程序入口

package com.wise.tiger.client;  
//************ import ********************/  
/** 
 * 程序入口 
 */  
public class BookApp {  
    public static final char DEFAULT_INPUT = '\u0000';  
  
    public static void main(String args[]) {  
        CommandLineInputHandler commandLineInputHandler = new CommandLineInputHandler();  
        char command = DEFAULT_INPUT;  
        while (CommandLineInput.EXIT.getShortCmd() != command) {  
            commandLineInputHandler.printOptions();  
            String input = commandLineInputHandler.readInput();  
            char[] inputChars = input.length() == 1 ? input.toCharArray() : new char[]{DEFAULT_INPUT};  
            command = inputChars[0];  
            CommandLineInput commandLineInput = CommandLineInput.getCommandLineInputForInput(command);  
            commandLineInputHandler.processInput(commandLineInput);  
        }  
    }  
}  

      在该应用中省略了service层,后续事务控制中再进行添加。

      至此,一个DAO设计模式就基本完成,但是这里面存在一个问题,就是大量的重复操作以及重复代码,这样的代码不便于我们阅读以及维护,或者由于开发者本身的疏忽而造成sql代码失控,如何解决这一问题呢?在下一节中我们采用模板方法模式以及策略模式对dao加以完善

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值