编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

Java操作数据库——结果集映射,DbUtils的快速上手

wxchong 2024-09-19 06:01:11 开源技术 15 ℃ 0 评论

DbUtils的快速入门

1 简介

我们先来简单看下,DbUtils是干什么的。

这图大家简单看下就好,我下面会总结一下(噗,就是为了证明我是从官网找的233)

简而言之:DbUtils可以高效地使用JDBC进行开发,让你更加专注于查询和更新数据(可以自动完成实体类等的映射)。

特点:

  • Small—— DbUtils内容不多,上手非常快,主要有两个核心:QueryRunner和ResultSetHandler。
  • Transparent—— 你只需要负责操作(写sql)即可,DbUtils会执行sql返回结果并关闭资源
  • Fast—— 引入DbUtils即可使用,不需要额外操作。

2 `QueryRunner`和`ResultSetHandler`

QueryRunner和ResultSetHandler是DbUtils的两个核心。


2.1 QueryRunner介绍

QueryRunner的作用主要是:处理sql语句,进行增删改查等。

常用构造器:

// Constructor for QueryRunner that takes a DataSource to use.
// 传入一个连接池给QR使用
QueryRunner(DataSource ds)

常用CRUD的API我会在章节4进行演示。


2.2 ResultSetHandler介绍

`ResultSetHandler的作用主要是:完成结果映射(使用反射),比如我们查出的结果可以直接是一个User实体类。

常用构造器:

// Creates a new instance of BeanHandler.
// 这是BeanHandler的构造器,传入一个想要转换的实体类的Class类型,因为底层还是使用反射
// 其他类似
BeanHandler(Class<? extends T> type)


3 上手小案例

3.1 建立 user 表

大家简单建立个user表即可。

create database if not exists jdbc_demo

use jdbc_demo

create table user
(
    id bigint auto_increment,
    username varchar(64) not null comment '帐号',
    password varchar(64) not null comment '密码',
    constraint user_pk
        primary key (id)
)
comment '用户表';

INSERT INTO jdbc_demo.user (username, password) VALUES ('user1', '123');
INSERT INTO jdbc_demo.user (username, password) VALUES ('user2', '456');
INSERT INTO jdbc_demo.user (username, password) VALUES ('user3', '123456');


3.2 导入相关jar包

  • mysql-connector-java-8.0.19.jar —— mysql驱动
  • commons-dbutils-1.7.jar —— DbUtilsjar包下载地址(提取码:r7q9)
  • druid-1.1.22.jar —— druid


3.3 操作流程

这里分了 6 点,主要是为了大家能够方便理解(●'?'●)

// 1.获取连接池
DataSource dataSource = JDBCUtil.getDataSource();

// 2.建立QueryRunner,将连接池当成参数传进构造器中
QueryRunner queryRunner = new QueryRunner(dataSource);

// 3.创建相关的ResultSetHandle,形成结果映射
BeanHandler<User> userBeanHandler = new BeanHandler<>(User.class);

// 4.编写sql语句
String sql = "select * from jdbc_demo.user where id = ?";

// 5.执行qr的query方法
// 参数1:sql语句
// 参数2:ResultSetHandler
// 参数3:类似preparedStatement,完成对sql语句占位符的替换
// 这个query底层就是使用preparedStatement
User user = queryRunner.query(sql, userBeanHandler, 1);

// 6.查看结果
System.out.println(user);
// Perfect (●'?'●)
// User{id=1, username='user1', password='123'}

哈哈,通过这个小案例,我们成功获取了User实体类的相关信息。

是不是感觉很方便→ v →,别着急,更精彩的还在后面(●'?'●)!

4. 常用CRUD的API介绍

4.1 查找单个数据

使用ScalarHandler

// 1.创建QueryRunner
QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());

// 2. 查询,
// Tip:先写handler,再写sql语句,这样有提示
Long query = queryRunner.query("select count(*) from jdbc_demo.user", new ScalarHandler<>());

// 3.输入
System.out.println(query);
// 得到 3 


4.2 查找单条数据

使用BeanHandler

// 1.创建QueryRunner
QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());

// 2. 查询,
// Tip:先写handler,再写sql语句,这样有提示
User user = queryRunner.query(
    "select * from jdbc_demo.user where username = ?",
    new BeanHandler<>(User.class),
    "user2");

// 3.输入
System.out.println(user);
// 得到 User{id=2, username='user2', password='456'}

4.3 查找多条数据

使用BeanListHandler

// 1.创建QueryRunner
QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());

// 2. 查询,
// Tip:先写handler,再写sql语句,这样有提示
// 也可以使用where,这边只是举个例子
List<User> users = queryRunner.query(
        "select * from jdbc_demo.user",
        new BeanListHandler<>(User.class));

// 3.输出
System.out.println(users);
// 得到 
// [User{id=1, username='user1', password='123'}, 
// User{id=2, username='user2', password='456'}, 
// User{id=3, username='user3', password='123456'}]

4.4 增加

// 1.创建QueryRunner
QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());

// 2. 操作,
// Tip:先写handler,再写sql语句,这样有提示
// 也可以使用where,这边只是举个例子
// 增删改 都是 update
int res = queryRunner.update("insert into jdbc_demo.user values (null,'user4','user4')");

// 3.输出
System.out.println(res);
// 得到 1 说明成功(●'?'●)

我们可以看到数据库确实有新的数据。

4.5 更新

// 1.创建QueryRunner
QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());

// 2. 操作,
// Tip:先写handler,再写sql语句,这样有提示
// 增删改 都是 update
int res = queryRunner.update(
    "update jdbc_demo.user set password = '123456' where username = ?",
    "user4");

// 3.输出
System.out.println(res);
// 得到 1 说明成功(●'?'●)

可以看到,数据库的数据已经被修改了。

4.6 删除

// 1.创建QueryRunner
QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());

// 2. 操作,
// Tip:先写handler,再写sql语句,这样有提示
// 增删改 都是 update
int res = queryRunner.update(
        "delete from jdbc_demo.user where username = ? ",
        "user4");

// 3.输出
System.out.println(res);
// 得到 1 说明成功(●'?'●)

可以看到,数据库中的user4已经被删除啦OvO

4.7 批量操作

这里我们介绍下批量插入, 删除和更新也是类似的。(记住数据库的url 要写上 rewriteBatchedStatements=true)

// 1.创建QueryRunner
QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());

// 2. 操作
// 使用batch方法,
// 参数1:批量操作的sql
// 参数2:二位数组,行数 -> 执行次数 ,列 -> 替换占位符
Object[][] params = new Object[10][];
for (int i = 0; i < params.length; i++) {
    params[i] = new Object[]{"lemonfish" + i, i};
}

// batch代表每行语句执行的结果
int[] batch = queryRunner.batch(
        "insert into jdbc_demo.user values (null,?,?)",
        params
);

// 3.输出
System.out.println(Arrays.toString(batch));
// 得到 [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] 说明全部成功(●'?'●)

可以看到,10条数据被成功插入啦

4.8 事务操作

事务操作和之前的有一些区别,QueryRunner操作事务,需要用到connection(其实还是原生的JDBC),这时候用我们自己封装的工具类获取connection就行。

// 1.创建QueryRunner
QueryRunner queryRunner = new QueryRunner();

// 2. 获取开启事务的connection
Connection connection = JDBCUtil.getConnectionWithTransaction();

// 3. 业务
// 3.1 删除、添加
try {
    int delete = queryRunner.update(connection,
                                    "delete from jdbc_demo.user where username = ? ",
                                    "user3");
    int insert = queryRunner.update(connection,
                                    "insert into jdbc_demo.user values (null,'user4','user4')");
    // 3.2 手动制造错误,查看回滚效果
    int error = 1 / 0;
    // 3.3 手动提交
    connection.commit();
} catch (SQLException throwables) {
    // 3.4 进行回滚
    connection.rollback();
    throwables.printStackTrace();
} finally{
    // 记住关闭
    connection.close();
}

rollback会在代码执行出错的情况下,回滚到connection执行sql语句前的状态。

5. 封装BaseDAO

哈哈,相信大家看到这里,是不是已经感觉相比原生JDBC,DbUtils用起来已经很爽了呢。

别急,还有更爽的呢→ v →

我们接下来封装一个BaseDAO ,封装一些常用的增删改查操作,然后使用子类继承的方式即可使用。

增删改查,一句sql搞定


这个就是BaseDAO的代码,基本就是整合了下前面的API。

/**
 * 封装基本的增删改查,以复用代码
 */
public class BaseDAO<T> {
    QueryRunner qr = new QueryRunner(JDBCUtil.getDataSource());

    /**
     * 增删改
     *
     * @param sql    sql语句
     * @param params 占位符
     * @return
     */
    public boolean update(String sql, Object... params) {
        int result = 0;
        try {
            result = qr.update(sql, params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return result > 0;
    }

    /**
     * 查询 单个值
     *
     * @param sql
     * @param params
     * @return
     */
    public Object selectScalar(String sql, Object... params) {
        try {
            return qr.query(sql, new ScalarHandler<>(), params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 查询 单行
     *
     * @param sql
     * @param clazz
     * @param params
     * @return
     */
    public T selectOne(String sql, Class<T> clazz, Object... params) {
        try {
            return qr.query(sql, new BeanHandler<>(clazz), params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 查询 多行
     *
     * @param sql
     * @param clazz
     * @param params
     * @return
     */
    public List<T> selectList(String sql, Class<T> clazz, Object... params) {
        try {
            return qr.query(sql, new BeanListHandler<>(clazz), params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 批量操作 增删改
     * @param sql
     * @param params
     * @return
     */
    public int[] batch(String sql,Object[][] params){

        int[] batch = new int[0]; 
        try {
            batch = qr.batch(sql,params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return batch;
    }
}

使用方式

  1. 编写一个UserDAO继承BaseDAO java public class UserDAO extends BaseDAO<User>{ // 可以自行拓展,BaseDAO只是封装了最基本的增删改查 }
  2. 使用实例 java // 1.获取UserDAO UserDAO userDAO = new UserDAO(); // 2.使用 User user = userDAO.selectOne("select * from user where username= ?", User.class, "user1"); // 3. 操作结果 System.out.println(user); // 输出结果:User{id=1, username='user1', password='123'}

哈哈!是不是简简单单一句sql就搞定查询啦OwO,增删改等等也是一样喔~~



DbUtils的底层实现主要是JDBC和反射(比如生成bean,然后调用setter等等),源码稍微看个大概不是很难,有兴趣的小伙伴可以自行阅读下。


6. 写在最后

看到这里,相信你对Java操作数据库又有了进一步的认识啦(●'?'●)

基本在接触持久层框架前,这算是比较好的处理办法啦。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表