JDBC DAO及其实现类
发布日期:2021-05-07 08:57:30 浏览次数:20 分类:精选文章

本文共 13129 字,大约阅读时间需要 43 分钟。

Java数据库访问优化:基于DAO模式的泛型处理方案

DAO模式设计与实现

在数据库开发中,Data Access Object(DAO)模式通过将数据访问逻辑封装为独立的类,实现了对数据库操作的统一管理。以下是基于Java泛型的DAO实现方案:

1. 基础DAO类设计

package indi.zhihuali2.DAO;import indi.zhihuali.util.JDBCUtils;import java.lang.reflect.Field;import java.lang.reflect.ParameterizedType;import java.lang.reflect.Type;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.ArrayList;/** * @author zhihua.li * @date 2020/7/28 - 21:33 * DAO:Data Access Object访问数据信息的类和接口,包括了对数据的CRUD(Create、Retrieval、Update、Delete),而不包含任何业务相关的信息。 * 有时也称作:BaseDAO * 作用:为了实现功能的模块化,更有利于代码的维护和升级。 */public abstract class BaseDAO
{ private static final String TAG = "BaseDAO"; private Class
clazz; { // 获取当前BaseDAO的子类继承的父类中的泛型类型 // 这里的this子类在实例化对象时会先把父类对象实例化 // 因此在这里初始化父类泛型是非常合适的 Type genericSuperclass = this.getClass().getGenericSuperclass(); ParameterizedType pty = (ParameterizedType) genericSuperclass; // 获取父类的泛型参数(可能多个,但获取父类泛型类型就是第一个) Type[] actualTypeArguments = pty.getActualTypeArguments(); // 泽然型的第一个参数 clazz = (Class
) actualTypeArguments[0]; } // 增删改操作 public int update(Connection connection, String sql, Object... args) { try { if (connection == null) { throw new SQLException("数据库连接为空"); } if (sql == null) { throw new SQLException("查询SQL语句为空"); } if (args == null || args.length == 0) { throw new SQLException("参数为空"); } PreparedStatement preparedStatement = null; try { preparedStatement = connection.prepareStatement(sql); for (int i = 0; i < args.length; i++) { preparedStatement.setObject(i + 1, args[i]); } return preparedStatement.executeUpdate(); } catch (SQLException e) { throw new RuntimeException(e); } finally { try { connection.setAutoCommit(true); } catch (SQLException throwables) { throwables.printStackTrace(); } JDBCUtils.closeResource(connection, preparedStatement, null); } } catch (SQLException e) { e.printStackTrace(); } return 0; } // 查询返回集合的方法 public ArrayList
getList(Connection connection, String sql, Object... args) { try { if (connection == null) { throw new SQLException("数据库连接为空"); } if (sql == null) { throw new SQLException("查询SQL语句为空"); } if (args == null || args.length == 0) { throw new SQLException("参数为空"); } PreparedStatement preparedStatement = null; ResultSet resultSet = null; ArrayList
ts = new ArrayList<>(); try { preparedStatement = connection.prepareStatement(sql); for (int i = 0; i < args.length; i++) { preparedStatement.setObject(i + 1, args[i]); } resultSet = preparedStatement.executeQuery(); if (resultSet == null) { return ts; } ResultSetMetaData rsmd = resultSet.getMetaData(); int columnCount = rsmd.getColumnCount(); while (resultSet.next()) { T t = clazz.getDeclaredConstructor().newInstance(); for (int i = 0; i < columnCount; i++) { Object columnValue = resultSet.getObject(i + 1); String columnName = rsmd.getColumnLabel(i + 1); Field field = clazz.getDeclaredField(columnName); field.setAccessible(true); field.set(t, columnValue); } ts.add(t); } } catch (SQLException e) { throw new RuntimeException(e); } finally { JDBCUtils.closeResource(connection, preparedStatement, resultSet); } return ts; } catch (SQLException e) { e.printStackTrace(); } return null; } // 查询返回单个对象的方法 public T getInstance(Connection connection, String sql, Object... args) { try { if (connection == null) { throw new SQLException("数据库连接为空"); } if (sql == null) { throw new SQLException("查询SQL语句为空"); } if (args == null || args.length == 0) { throw new SQLException("参数为空"); } PreparedStatement preparedStatement = null; ResultSet resultSet = null; T t = null; try { preparedStatement = connection.prepareStatement(sql); for (int i = 0; i < args.length; i++) { preparedStatement.setObject(i + 1, args[i]); } resultSet = preparedStatement.executeQuery(); if (resultSet == null) { return null; } ResultSetMetaData metaData = resultSet.getMetaData(); int columnCount = metaData.getColumnCount(); if (resultSet.next()) { t = clazz.getDeclaredConstructor().newInstance(); for (int i = 0; i < columnCount; i++) { Object objectValue = resultSet.getObject(i + 1); String columnName = metaData.getColumnLabel(i + 1); Field declaredField = clazz.getDeclaredField(columnName); declaredField.setAccessible(true); declaredField.set(t, objectValue); } } } catch (SQLException e) { throw new RuntimeException(e); } finally { try { connection.setAutoCommit(true); } catch (SQLException throwables) { throwables.printStackTrace(); } JDBCUtils.closeResource(connection, preparedStatement, resultSet); } return t; } catch (SQLException e) { e.printStackTrace(); } return null; } // 用于查询特殊值的通用方法 public E getValue(Connection connection, String sql, Object... args) { try { if (connection == null) { throw new SQLException("数据库连接为空"); } if (sql == null) { throw new SQLException("查询SQL语句为空"); } if (args == null || args.length == 0) { throw new SQLException("参数为空"); } PreparedStatement preparedStatement = null; ResultSet resultSet = null; E e = null; try { preparedStatement = connection.prepareStatement(sql); for (int i = 0; i < args.length; i++) { preparedStatement.setObject(i + 1, args[i]); } resultSet = preparedStatement.executeQuery(); if (resultSet == null) { return null; } while (resultSet.next()) { e = (E) resultSet.getObject(1); } } catch (SQLException e) { throw new RuntimeException(e); } finally { try { connection.setAutoCommit(true); } catch (SQLException throwables) { throwables.printStackTrace(); } JDBCUtils.closeResource(connection, preparedStatement, resultSet); } return e; } catch (SQLException e) { e.printStackTrace(); } return null; }}

2. 接口设计

package indi.zhihuali2.DAO;import indi.zhihuali2.bean.Book;import java.sql.Connection;import java.sql.Date;import java.util.List;/** * @author zhihua.li * @date 2020/7/28 - 21:48 * DAO(Data Access Object)数据访问对象 * 用于规范对于book表的常用操作 */public interface BookDAO {    // 将book对象添加到数据库中    void insert(Connection connection, Book book);    // 根据指定id删除表中相应记录    void deleteById(Connection connection, int id);    // 根据内存中的book对象 修改数据表中指定记录    void updateById(Connection connection, Book book);    // 根据指定id查询得到对应的Book对象    Book getBookById(Connection connection, int id);    // 查询表中全部记录构成的Book对象集合    List
getAllBooksById(Connection connection); // 返回数据表中记录个数 Long getCount(Connection connection); // 返回数据表中出生日期最大的对象 Date getMaxBirth(Connection connection);}

3. 实现类设计

package indi.zhihuali2.DAO;import indi.zhihuali.util.JDBCUtils;import indi.zhihuali2.bean.Book;import org.junit.Test;import java.sql.Connection;import java.sql.Date;import java.util.List;import static org.junit.Assert.*;/** * @author zhihua.li * @date 2020/7/29 - 12:39 */public class BookDAOImplProTest {    private BookDAOImpl dao = new BookDAOImpl();    @Test    public void insert() {        Connection connection = null;        try {            connection = JDBCUtils.getConnection();            Book book = new Book(1, "刘能", "LiuNeng@qq.com", new Date(201034453231L));            dao.insert(connection, book);            System.out.println("插入成功");        } catch (Exception e) {            e.printStackTrace();        } finally {            JDBCUtils.closeResource(connection, null);        }    }    @Test    public void deleteById() {        Connection connection = null;        try {            connection = JDBCUtils.getConnection();            dao.deleteById(connection, 17);            System.out.println("删除成功");        } catch (Exception e) {            e.printStackTrace();        } finally {            JDBCUtils.closeResource(connection, null);        }    }    @Test    public void updateById() {        Connection connection = null;        try {            connection = JDBCUtils.getConnection();            Book book = new Book(7, "夏雨而", "XY@qq.com", new Date(1242141235345L));            dao.updateById(connection, book);            System.out.println("");        } catch (Exception e) {            e.printStackTrace();        } finally {            JDBCUtils.closeResource(connection, null);        }    }    @Test    public void getBookById() {        Connection connection = null;        try {            connection = JDBCUtils.getConnection();            Book book = dao.getBookById(connection, 3);            System.out.println("查询成功" + book);        } catch (Exception e) {            e.printStackTrace();        } finally {            JDBCUtils.closeResource(connection, null);        }    }    @Test    public void getAllBooksById() {        Connection connection = null;        try {            connection = JDBCUtils.getConnection();            List
allBooksById = dao.getAllBooksById(connection); System.out.println("查询成功"); for (Book book : allBooksById) { System.out.println(book); } } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.closeResource(connection, null); } } @Test public void getCount() { Connection connection = null; try { connection = JDBCUtils.getConnection(); System.out.println("查询成功"); Long count = dao.getCount(connection); System.out.println("查询到的记录总数为:" + count); } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.closeResource(connection, null); } } @Test public void getMaxBirth() { Connection connection = null; try { connection = JDBCUtils.getConnection(); System.out.println("查询成功"); Date maxBirth = dao.getMaxBirth(connection); System.out.println("最年轻的人出生日期为:" + maxBirth); } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.closeResource(connection, null); } }}

4. 优化说明

1. BaseDAO类的泛型处理优化

为了解决在DAO实现类中反射获取字段名与类属性名不一致的问题,我们在BaseDAO中引入了泛型机制:

private Class
clazz;{ // 获取当前BaseDAO的子类继承的父类中的泛型类型 Type genericSuperclass = this.getClass().getGenericSuperclass(); ParameterizedType pty = (ParameterizedType) genericSuperclass; // 获取父类的泛型参数(可能多个,但获取父类泛型类型就是第一个) Type[] actualTypeArguments = pty.getActualTypeArguments(); // 泽然型的第一个参数 clazz = (Class
) actualTypeArguments[0];}

通过上述方式,在子类实例化时,BaseDAO自动获取子类的泛型类型,避免了在每个实现类中手动定义泛型类型,减少了代码冗余。

2. 查询操作的优化

在查询操作中,我们采用了以下优化措施:

  • 移除参数化的方法:将查询方法的参数从泛型化的方法中移除,改用具体的String参数,避免了泛型类型在运行时的确定问题。

  • 统一预编译Statement:通过预编译Statement对象,减少了每次查询时的prepareStatement操作,提升了性能表现。

  • ResultSetMetaData优化:通过ResultSetMetaData获取列名,支持字段名与类属性名不一致的情况,提高了灵活性。

  • 3. 事务管理优化

    在增删改操作中,实现了事务管理,确保数据库连接自动提交或回滚,避免了数据库连接泄漏问题。

    4. 测试验证

    通过测试类验证了每个DAO操作的正确性,包括插入、删除、更新、查询等功能。每个测试方法都清晰地描述了操作内容,便于后续的功能扩展和维护。

    通过以上优化方案,实现了对数据库操作的高效管理,同时保持了代码的可维护性和可扩展性。

    上一篇:JavaScript数组(2):使用数组对象
    下一篇:JavaScript数组(1):定义数组、使用数组

    发表评论

    最新留言

    路过,博主的博客真漂亮。。
    [***.116.15.85]2025年03月30日 06时35分52秒