BaseDao封装JavaWeb的增删改查

目录

什么是BaseDao?

为什么需要BaseDao?

BaseDao的实现逻辑

查询任意目标数据特殊处理万能方法:


什么是BaseDao?

Basedao 是一种基于数据访问对象(Data Access Object)模式的设计方法。它是一个用于处理数据库操作的基础类,负责封装数据库访问的底层操作,提供通用的数据库访问方法。

Basedao 主要用于简化数据库操作的代码开发,并提供一致性可维护性。它通常包含有对数据库的增加、删除、修改和查询等操作方法,以及一些基本的事务处理功能。

Basedao 可以通过继承来扩展具体的数据库操作方法,使得在具体的业务实现中可以更加专注于业务逻辑的实现,而不需要关注底层数据库的细节。

通过使用 Basedao,开发人员可以更加高效地进行数据库操作的开发,减少了重复的代码编写,提高了代码的可维护性可读性

为什么需要BaseDao?

BaseDao 的优点包括:

  1. 代码复用(共性抽取):BaseDao 封装了常见的数据库操作方法,可以被不同的业务逻辑类多次调用,避免了重复编写相同的数据库操作代码,提高了代码的复用性。
  2. 提高开发效率:BaseDao 提供了高级的数据库操作方法,开发人员可以直接调用这些方法,减少了重复的开发工作,提高了开发效率。
  3. 降低代码耦合度:BaseDao 封装了底层数据库的细节,通过调用 BaseDao 的方法,业务逻辑类可以和具体的数据库实现解耦,减少了业务逻辑类和数据库之间的直接依赖,提高了代码的可维护性和可扩展性。
  4. 提供事务支持:BaseDao 通常会提供事务处理的功能,可以保证数据库操作的一致性。开发人员可以通过 BaseDao 来处理事务,确保在一次操作中,要么全部成功,要么全部失败,避免了数据不一致的情况。

总的来说,BaseDao 通过封装数据库操作,提供高级的数据库操作方法,降低代码耦合度,提供事务支持等优点,可以提高开发效率,简化数据库操作,提高代码的可维护性和可扩展性。

BaseDao的实现逻辑

简单来说BaseDao就是对数据库底层操作业务进行共性抽取,下面就以学生信息为例~

1、在学生信息管理系统中,不论增删改查还是特殊业务都离不开每次访问数据库的配置驱动以及获取连接关闭连接,所以这两步是必然封装的

/**
 * 获取数据库连接对象
 */
public Connection getConnection() throws Exception {  //获取连接对象方法
    //加载配置文件
    Properties properties = new Properties();
    properties.load(Files.newInputStream(Paths.get("D:\\druid.properties")));

    //创建一个指定参数的数据库连接池
    DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
    return dataSource.getConnection();  //返回连接对象
}

因为当时博主访问数据库是采用Druid连接池,所以配置驱动就使用配置文件的方式,配置文件( .properties )代码如下:

driverClassName = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/student?useServerPrepStmts=true
username = root
password = root
initialSize = 10
maxActive = 30
maxWait = 1000

关闭连接方法封装代码如下:

/**
 * 关闭数据库连接
 * @param conn 数据库连接
 * @param stmt PreparedStatement预处理对象
 * @param rs 结果集
 */
public void closeAll(Connection conn, PreparedStatement stmt, ResultSet rs) {  //关闭连接方法
        // 若结果集对象(RresuleSet)不为空,则关闭
        if (rs != null) {
            try {
                rs.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        // 若预处理对象(PreparedStatement)不为空,则关闭
        if (stmt != null) {
            try {
                stmt.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        // 若数据库连接对象(Connection)不为空,则关闭
        if (conn != null) {
            try {
                conn.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

2、通过第一步的调用能够返回一个连接对象,那么接下来就可以进行基本的增删改查操作, 增删改都属于对数据做更新,所以先做增删改

/**
 * 增、删、改的操作
 * @param preparedSql 预编译的 SQL 语句
 * @param param 参数的字符串数组
 * @return 影响的行数
 */
public int updateRow (String preparedSql, Object[] param) throws Exception {  //增删改操作的方法
    PreparedStatement preparedStatement = null;  //创建预处理对象并初始为空(通过预处理可以防止SQL恶意注入)
    int row = 0;  //初始受影响行数(当受影响行数大于0时,说明执行成功数据则更新)
    Connection connection = getConnection();  //调用getConnection()方法获取数据库连接
    try {
        preparedStatement = connection.prepareStatement(preparedSql);  //对sql形参预处理
        if (param != null) {  //形参数组(注入参数)不为空时,循环遍历对预处理sql注入参数
            for (int i = 0; i < param.length; i++) {
                //为预编译sql设置参数
                preparedStatement.setObject(i + 1, param[i]);
            }
        }
        row = preparedStatement.executeUpdate();  //执行sql语句并得到受影响的行数
        closeAll(connection,preparedStatement,null);  //调用closeAll()方法关闭资源,因为执行操作不含查询,则将结果集的实参传空
    } catch (SQLException e) {
        e.printStackTrace();
    }
    return row;  //返回受影响行数
}

因为sql语句中需要的参数类型是不确定的,则用Object类型数组作为容器

3、至此就剩查询操作了,在封装前需要创建一个实体类,以至于后续每个实体类都可以代表为一行数据,代码如下:

public class Student {
    //初始字段
    private int id;
    private String name;
    private int age;

    public Student(int id, String name, int age) {  //构造函数
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {  //toString方法
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

实体对象有了,那么走你:

public List<Student> queryData (String sql, Object[] param) throws Exception {  //查询操作的方法
    PreparedStatement preparedStatement = null;  //创建预处理对象并初始为空(通过预处理可以防止SQL恶意注入)
    Connection connection = getConnection();  //调用getConnection()方法获取数据库连接
    preparedStatement = connection.prepareStatement(sql);  //调用getConnection()方法获取数据库连接
    if (param != null) {  //形参数组(注入参数)不为空时,循环遍历对预处理sql注入参数
        for (int i = 0; i < param.length; i++) {
            //为预编译sql设置参数
            preparedStatement.setObject(i + 1, param[i]);
        }
    }
    ResultSet resultSet = preparedStatement.executeQuery();  //得到返回的结果集
    List<Student> list = new ArrayList<Student>();  //创建List接口对象,泛型为指定Student对象类型,代表每个实体对象都是一行数据
    while (resultSet.next()) {  //循环遍历结果集,将每行数据封装成Student对象,并添加到List集合中
        Student student= new Student(resultSet.getInt(1), resultSet.getString(2), resultSet.getInt(3));  //获取结果集中的数据存入Student对象中
        list.add(student);  //将Student对象存入list接口中
    }
    closeAll(connection,preparedStatement,resultSet);  //调用closeAll()方法关闭数据库连接
    return list;  //返回List集合对象 
}

接下来创建一个测试类进行检查:

1、增删改测试

//增删改测试
BaseDao baseDao = new BaseDao();  //创建BaseDao对象
String sql = "insert into student(id,name,age) values(?,?,?)";  //定义预处理sql
Object[] list = {6, "老八", 35};  //将sql需要的参数存入至Object类型的数组
int add = baseDao.updateRow(sql, list); //调用增删改的方法并接收返回的受影响行数
if (add > 0) {  //受影响行数大于0则说明数据更新成功
    System.out.println("新增成功!受影响行数:" + add);
}
/* 删除、修改也是一样 */

控制台:

2、查询测试 

//查询测试
BaseDao baseDao = new BaseDao();  //创建BaseDao对象
String sql = "select * from student";  //定义预处理sql
List<Student> list = baseDao.queryData(sql, null);  //创建List接口,泛型为Student对象类型,用于存储查询返回的数据
for (Student student : list) {
    System.out.println(student.getId() + "\t\t" + student.getName() + "\t\t" + student.getAge());  //输出数据
}

控制台:

这么一来,JavaWeb中的每次增删改查都可以简明的实现,增删改查以外的特殊性业务功能可在BaseDao对象中具体实现方法

查询任意目标数据特殊处理万能方法:

public List<Map<String, String>> returnArbitraryDataStringType (String sql, Object... param) throws Exception {  //万能查询的方法
    PreparedStatement preparedStatement;  //创建预处理对象并初始为空(通过预处理可以防止SQL恶意注入)
    Connection connection = getConnection();  //调用getConnection()方法获取数据库连接
    preparedStatement = connection.prepareStatement(sql);  //调用getConnection()方法获取数据库连接
    if (param != null) {  //形参数组(注入参数)不为空时,循环遍历对预处理sql注入参数
        for (int i = 0; i < param.length; i++) {
            //为预编译sql设置参数
            preparedStatement.setObject(i + 1, param[i]);
        }
    }
    ResultSet resultSet = preparedStatement.executeQuery();  //得到返回的结果集

    int column = 0;  //初始化结果集的总列数
    ResultSetMetaData metaData = resultSet.getMetaData();  //得到结果集的元数据对象
    column = metaData.getColumnCount();  //获取结果集的总列数
    System.out.println("总列:" + column);

    List<Map<String, String>> list = new ArrayList<>();  //创建初始List集合对象用于存放查询到的任意目标数据
    while (resultSet.next()) {  //循环遍历结果集
        Map<String, String> map = new HashMap<>();  //创建临时Map集合对象用于存放查询到的任意目标数据(每个Map对象就是一条数据)
        for (int i = 0; i < column; i++) {  //循环遍历结果集的每一列
            //将结果集中的数据存入Map集合中(key为列名,value为列值)
            map.put(metaData.getColumnName(i + 1), resultSet.getString(i + 1));
        }
        list.add(map);  //将Map集合对象存入List集合中
    }

    closeAll(connection,preparedStatement,resultSet);  //关闭资源
    return list;  //返回List集合对象
}

此方法可以查询任意目标数据,不论多少行多少列都能根据源数据精准获取及存放,返回的List集合对象中每一个Map集合对象都是一行数据,键名=列名 / 键值=列值

注意:若使用该方法,在建表增数据时特别对于连表查询列名一定不能重复,因为获取时是根据源数据的,即便给列起了别名但在处理时同样只认准源列名,若列名重复会导致始终只有一个列,只是值在一直被替换(例如A、B两表都有ID、Name列,那么在建表增数据时就不能都是ID、Name,可以AID、AName和BID、BName这样命名各表的ID、Name列)

  • 16
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是一个简单的BaseDao类,封装了增加、删除、查询、更新四个方法: ``` import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class BaseDao { // 定义数据库连接对象 private Connection conn = null; // 构造方法,初始化数据库连接对象 public BaseDao() { conn = DBUtil.getConnection(); } // 增加数据方法 public int add(String sql, Object... params) { int count = 0; PreparedStatement pstmt = null; try { pstmt = conn.prepareStatement(sql); // 设置占位符参数 for (int i = 0; i < params.length; i++) { pstmt.setObject(i + 1, params[i]); } // 执行增加操作 count = pstmt.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } finally { DBUtil.closeAll(null, pstmt, null); } return count; } // 删除数据方法 public int delete(String sql, Object... params) { int count = 0; PreparedStatement pstmt = null; try { pstmt = conn.prepareStatement(sql); // 设置占位符参数 for (int i = 0; i < params.length; i++) { pstmt.setObject(i + 1, params[i]); } // 执行删除操作 count = pstmt.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } finally { DBUtil.closeAll(null, pstmt, null); } return count; } // 查询数据方法 public ResultSet query(String sql, Object... params) { ResultSet rs = null; PreparedStatement pstmt = null; try { pstmt = conn.prepareStatement(sql); // 设置占位符参数 for (int i = 0; i < params.length; i++) { pstmt.setObject(i + 1, params[i]); } // 执行查询操作 rs = pstmt.executeQuery(); } catch (SQLException e) { e.printStackTrace(); } return rs; } // 更新数据方法 public int update(String sql, Object... params) { int count = 0; PreparedStatement pstmt = null; try { pstmt = conn.prepareStatement(sql); // 设置占位符参数 for (int i = 0; i < params.length; i++) { pstmt.setObject(i + 1, params[i]); } // 执行更新操作 count = pstmt.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } finally { DBUtil.closeAll(null, pstmt, null); } return count; } } ``` 在使用该类时,可以通过继承的方式来实现具体的操作,例如: ``` public class UserDao extends BaseDao { // 添加用户 public int addUser(User user) { String sql = "insert into user(username, password, age) values(?,?,?)"; return super.add(sql, user.getUsername(), user.getPassword(), user.getAge()); } // 删除用户 public int deleteUser(int id) { String sql = "delete from user where id=?"; return super.delete(sql, id); } // 查询用户 public User getUser(int id) { User user = null; String sql = "select * from user where id=?"; ResultSet rs = super.query(sql, id); try { if (rs.next()) { user = new User(); user.setId(rs.getInt("id")); user.setUsername(rs.getString("username")); user.setPassword(rs.getString("password")); user.setAge(rs.getInt("age")); } } catch (SQLException e) { e.printStackTrace(); } return user; } // 更新用户 public int updateUser(User user) { String sql = "update user set username=?, password=?, age=? where id=?"; return super.update(sql, user.getUsername(), user.getPassword(), user.getAge(), user.getId()); } } ``` 这样,我们就可以通过继承BaseDao类来实现具体的增、删、查、改操作了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值