DbUtils手册

风格不统一 提交于 2019-12-25 17:46:14

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

DbUtils手册

简介

概述

Apache Commons DbUtils是 Java 编程中的数据库操作实用工具,小巧简单实用。

DBUtils 封装了对 JDBC 的操作,简化了 JDBC 操作,可以少写代码。

优点

无资源泄漏

DBUtils类确保不会发生资源泄漏。

清理和清除代码

DBUtils类提供干净清晰的代码来执行数据库操作,而无需编写任何清理或资源泄漏防护代码。

Bean映射

DBUtils类支持从结果集中自动填充javabeans。

设计原则

DBUtils库的体积很小,只有较少的类,因此易于理解和使用。

透明

DBUtils库在后台没有做太多工作,它只需查询并执行。

快速

DBUtils库类不会创建许多背景对象,并且在数据库操作执行中速度非常快。

入门

POM

<!-- https://mvnrepository.com/artifact/commons-dbutils/commons-dbutils -->
<dependency>
   <groupId>commons-dbutils</groupId>
   <artifactId>commons-dbutils</artifactId>
   <version>1.7</version>
</dependency>

依赖

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.9</version>
</dependency>

数据准备

创建一张数据表

现有一张 User 表,其表结构如下:

id name age email
1 张三 18 test1@163.com 2 李四 20 test2@163.com 3 王五 28 test3@163.com 4 侯六 21 test4@163.com 5 杨七 24 test5@163.com

数据库脚本

DROP TABLE IF EXISTS user;

CREATE TABLE user
(
	id BIGINT(20) NOT NULL COMMENT '主键ID',
	name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
	age INT(11) NULL DEFAULT NULL COMMENT '年龄',
	email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
	PRIMARY KEY (id)
);

数据库 Data

DELETE FROM user;

INSERT INTO user (id, name, age, email) VALUES
(1, '张三', 18, 'test1@163.com'),
(2, '李四', 20, 'test2@163.com'),
(3, '王五', 28, 'test3@163.com'),
(4, '侯六', 21, 'test4@163.com'),
(5, '杨七', 24, 'test5@163.com');

示例代码

User对象

package com.demo.dbutils;

public class User {

    private Long id;

    private String name;

    private Integer age;

    private String email;

    public Long getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

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

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", email='" + email + '\'' +
                '}';
    }
}

执行JDBC应用代码

package com.demo.dbutils;

import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class HelloWorld {

    private static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";

    private static final String URL = "jdbc:mysql://localhost:3306/test";

    private static final String USER = "root";

    private static final String PASSWORD = "root";


    public static void main(String[] args) throws SQLException {

        QueryRunner queryRunner = new QueryRunner();
        // 注册驱动
        DbUtils.loadDriver(JDBC_DRIVER);
        //加载连接
        Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);
        try {
            // 执行查询
            User user = queryRunner.query(connection, "SELECT * FROM user WHERE id=?",
                    new BeanHandler<User>(User.class), "1");
            //从结果集中提取数据
            System.out.println(user.toString());
        } finally {
            //清理环境
            DbUtils.close(connection);
        }
    }

}

执行上面的代码,它会产生以下结果

User{id=1, name='张三', age=18, email='test1@163.com'}

流程解析

构建JDBC应用程序涉及以下步骤

步骤 说明
注册JDBC驱动程序 需要初始化驱动程序,以便可以打开与数据库的通信通道。
打开连接 需要使用DriverManager.getConnection()方法创建一个Connection对象,该对象表示与数据库的物理连接。 执行查询 需要使用类型为Statement的对象来构建和提交SQL语句到数据库。
从结果集中提取数据 要求您使用适当的ResultSet.getXXX()方法从结果集中检索数据。
清理环境 需要显式关闭所有数据库资源而不依赖于JVM的垃圾收集。

基本用法CRUD

创建(Create)

在DBUtils中,使用Insert语句来创建记录。

语法

 String sql="INSERT INTO user (id, name, age, email) VALUES(?,?,?,?)";

            int total = queryRunner.update(connection, sql,8,"冯八", "15","test8@163.com");

示例代码

package com.demo.dbutils;

import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class Create {


    private static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";

    private static final String URL = "jdbc:mysql://localhost:3306/test";

    private static final String USER = "root";

    private static final String PASSWORD = "root";


    public static void main(String[] args) throws SQLException {

        QueryRunner queryRunner = new QueryRunner();
        // 注册驱动
        DbUtils.loadDriver(JDBC_DRIVER);
        //加载连接
        Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);
        try {
            // 执行查询
            String sql="INSERT INTO user (id, name, age, email) VALUES(?,?,?,?)";

            int total = queryRunner.update(connection, sql,8,"冯八", "15","test8@163.com");

            //从结果集中提取数据
           System.out.println(total+" records inserted");
        } finally {
            //清理环境
            DbUtils.close(connection);
        }
    }
}

结果如下

1 records inserted

读取(Read)

在DBUtils的中,使用query查询来读取数据库表中的记录。

语法

 User user = queryRunner.query(connection, "SELECT * FROM user WHERE id=?",
                    new BeanHandler<User>(User.class), "1");

示例代码

package com.demo.dbutils;

import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class Read {

    private static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";

    private static final String URL = "jdbc:mysql://localhost:3306/test";

    private static final String USER = "root";

    private static final String PASSWORD = "root";


    public static void main(String[] args) throws SQLException {

        QueryRunner queryRunner = new QueryRunner();
        // 注册驱动
        DbUtils.loadDriver(JDBC_DRIVER);
        //加载连接
        Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);
        try {
            // 执行查询
            User user = queryRunner.query(connection, "SELECT * FROM user WHERE id=?",
                    new BeanHandler<User>(User.class), "1");
            //从结果集中提取数据
            System.out.println(user.toString()+" records read ");
        } finally {
            //清理环境
            DbUtils.close(connection);
        }
    }


}

执行结果

User{id=1, name='张三', age=18, email='test1@163.com'} records read 

更新(Update)

在DBUtils的中,使用update查询来读取数据库表中的记录。

语法

    String sql="Update user set age = ? where id =?";

    int total = queryRunner.update(connection, sql,8,1);

示例代码

package com.demo.dbutils;

import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class Update {


    private static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";

    private static final String URL = "jdbc:mysql://localhost:3306/test";

    private static final String USER = "root";

    private static final String PASSWORD = "root";


    public static void main(String[] args) throws SQLException {

        QueryRunner queryRunner = new QueryRunner();
        // 注册驱动
        DbUtils.loadDriver(JDBC_DRIVER);
        //加载连接
        Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);
        try {
            // 执行查询
            String sql="Update user set age = ? where id =?";

            int total = queryRunner.update(connection, sql,8,1);

            //从结果集中提取数据
            System.out.println(total+" records updated");
        } finally {
            //清理环境
            DbUtils.close(connection);
        }
    }
}

删除(Delete)

在DBUtils的中,使用update查询来读取数据库表中的记录。

语法

 String sql="DELETE FROM user where id =?";

 int total = queryRunner.update(connection, sql,8);

示例代码

package com.demo.dbutils;

import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class Delete {


    private static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";

    private static final String URL = "jdbc:mysql://localhost:3306/test";

    private static final String USER = "root";

    private static final String PASSWORD = "root";


    public static void main(String[] args) throws SQLException {

        QueryRunner queryRunner = new QueryRunner();
        // 注册驱动
        DbUtils.loadDriver(JDBC_DRIVER);
        //加载连接
        Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);
        try {
            // 执行查询
            String sql="DELETE FROM user where id =?";

            int total = queryRunner.update(connection, sql,8);

            //从结果集中提取数据
            System.out.println(total+" records deleted");
        } finally {
            //清理环境
            DbUtils.close(connection);
        }
    }
}

结果如下

1 records deleted

核心

QueryRunner中提供对sql语句操作的API

ResultSetHandler接口,用于定义select操作后,怎样封装结果集

DBUtils类,它就是一个工具类,定义了关闭资源与事务处理的方法

QueryRunner

org.apache.commons.dbutils.QueryRunner类是DBUtils库中的中心类。

它执行带有可插入策略的SQL查询来处理ResultSets。

这个类是线程安全的。

QueryRunner(DataSourcr ds)
提供数据源(连接池),DbUtils底层自动维护连接connection

update(String sql,Obj...params)
执行更新数据

query(String sql,ResultSetHandler<T>rsh,Object...panrams)
执行查询

ResultSetHandler

org.apache.commons.dbutils.ResultSetHandler接口负责将ResultSets转换为对象。

ArrayHandler:
适合取1条记录,把结果集中的第一行数据转成对象数组。

ArrayListHandler:
适合取多条记录,把结果集中的每一行数据都转成一个对象数组,再存放到List中。
 
BeanHandler:
将结果集中的第一行数据封装到一个对应的JavaBean实例中(把每条记录封装成对象,适合取一条记录)

BeanListHandler:
将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里。

MapHandler:
将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值。

MapListHandler:
将结果集中的每一行数据都封装到一个Map里,然后再存放到List

ColumnListHandler:
将结果集中某一列的数据存放到List中。

KeyedHandler(name):
将结果集中的每一行数据都封装到一个Map里(List<Map>),再把这些map再存到一个map里,其key为指定的列。

ScalarHandler:将结果集第一行的某一列放到某个对象中。

BeanHandler

org.apache.commons.dbutils.BeanHandler是ResultSetHandler接口的实现,负责将第一个ResultSet行转换为JavaBean。

这个类是线程安全的。

BeanListHandler

org.apache.commons.dbutils.BeanListHandler是ResultSetHandler接口的实现,负责将ResultSet行转换为Java Bean列表。

ArrayListHandler

org.apache.commons.dbutils.ArrayListHandler是ResultSetHandler接口的实现,负责将ResultSet行转换为object[]。 这个类是线程安全的。

MapListHandler

org.apache.commons.dbutils.MapListHandler是ResultSetHandler接口的实现,负责将ResultSet行转换为Maps列表。 这个类是线程安全的。

高级

自定义处理程序

可以通过实现ResultSetHandler接口或扩展任何现有的ResultSetHandler实现来创建自己的自定义处理程序。 如果用户要想自定义业务返回类型

public class CustomerResultSetHandler <T> implements ResultSetHandler<T> {
    @Override
    public T handle(ResultSet rs) throws SQLException {
        return null;
    }

}

示例代码

package com.demo.dbutils;

import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class UserHandlerQuery {

    private static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";

    private static final String URL = "jdbc:mysql://localhost:3306/test";

    private static final String USER = "root";

    private static final String PASSWORD = "root";


    public static void main(String[] args) throws SQLException {

        QueryRunner queryRunner = new QueryRunner();
        // 注册驱动
        DbUtils.loadDriver(JDBC_DRIVER);
        //加载连接
        Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);
        try {
            // 执行查询
            User user = queryRunner.query(connection, "SELECT * FROM user WHERE id=?",
                    new UserHandler(), "1");
            //从结果集中提取数据
            System.out.println(user.toString());
        } finally {
            //清理环境
            DbUtils.close(connection);
        }
    }

}

结果如下

User{id=1, name='张三', age=8, email='张三@163.com'}

自定义行处理器

如果数据库表中的列名和等价的javabean对象名称不相似,那么我们可以通过使用自定义的BasicRowProcessor对象来映射它们。

package com.demo.dbutils;

import org.apache.commons.dbutils.BasicRowProcessor;
import org.apache.commons.dbutils.BeanProcessor;
import org.apache.commons.dbutils.handlers.BeanHandler;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

public class UserRowHandler extends BeanHandler<User> {

    public UserRowHandler() {
        super(User.class, new BasicRowProcessor(new BeanProcessor(mapColumnsToFields())));
    }

    @Override
    public User handle(ResultSet rs) throws SQLException {
        User user = super.handle(rs);
        user.setEmail(user.getName() +"@163.com");
        return user;
    }

    public static Map<String, String> mapColumnsToFields() {
        Map<String, String> columnsToFieldsMap = new HashMap<>();
        columnsToFieldsMap.put("ID", "id");
        columnsToFieldsMap.put("AGE", "age");
        return columnsToFieldsMap;
    }

}

使用DataSource

到目前为止,我们在使用QueryRunner时都是使用Connection对象。 也可以使用数据源。

使用dbcp数据库连接池

Maven

<dependency>
    <groupId>commons-dbcp</groupId>
    <artifactId>commons-dbcp</artifactId>
    <version>1.4</version>
</dependency>

它自己会依赖

<dependency>
      <groupId>commons-pool</groupId>
      <artifactId>commons-pool</artifactId>
      <version>1.5.4</version>
</dependency>

示例代码

package com.demo.dbutils;

import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;

import java.sql.SQLException;

public class DataSourceQuery {

    public static void main(String[] args) throws SQLException {
        QueryRunner queryRunner = new QueryRunner(CustomDataSource.getInstance());
        // 执行查询
        User user = queryRunner.query("SELECT * FROM user WHERE id=?",
                new BeanHandler<User>(User.class), "1");
        //从结果集中提取数据
        System.out.println(user.toString());
    }
}

使用c3p0数据库连接池

<dependency>
    <groupId>c3p0</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.1.1</version>
</dependency>

大字典clob

public void testClob() throws Exception {
    QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());
    String sql = "insert into clob values(?)";
    File file = new File("c:/a.txt");
    Long l = file.length();
    char[] buffer = new char[l.intValue()];
    FileReader reader = new FileReader(file);
    reader.read(buffer);
    SerialClob clob = new SerialClob(buffer);
    queryRunner.update(sql, clob);
}

二进制blob

public void testBlob() throws Exception{
    QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());
    String sql = "insert into blob values(?)";
    File file = new File("c:/a.jpg");
    Long l = file.length();
    byte[] buffer = new byte[l.intValue()];
    FileInputStream input = new FileInputStream(file);
    input.read(buffer);
    SerialBlob blob = new SerialBlob(buffer);
    queryRunner.update(sql,blob);
}

事务操作

事务案例

使用ThreadLocal类,传递事务连接

public class JdbcKit {

    /**
     * 获取连接池
     */
    public static ComboPooledDataSource ds = new ComboPooledDataSource();
    /**
     * 线程共享变量
     */
    public static ThreadLocal<Connection> container = new ThreadLocal<Connection>();

    /**
     * 获取线程变量
     *
     * @return
     */
    public static ThreadLocal<Connection> getContainer() {
        return container;
    }
  public static DataSource getDataSource() {
        return ds;
    }

    /**
     * 开启事务
     */
    public static void startTransaction() {
        Connection conn = container.get();
        if (conn == null) {
            conn = getConnection();
            container.set(conn);
        }
        try {
            conn.setAutoCommit(false);
        } catch (SQLException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    /**
     * 提交事务
     */
    public static void commit() {
        Connection conn = container.get();
        if (conn != null) {
            try {
                conn.commit();
            } catch (SQLException e) {
                throw new RuntimeException(e.getMessage(), e);
            }
        }
    }

    /**
     * 回滚事务
     */
    public static void rollback() {
        Connection conn = container.get();
        if (conn != null) {
            try {
                conn.rollback();
            } catch (SQLException e) {
                throw new RuntimeException(e.getMessage(), e);
            }
        }
    }

    /**
     * 关闭连接
     */
    public static void close() {
        Connection conn = container.get();
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                throw new RuntimeException(e.getMessage(), e);
            } finally {
                container.remove();
            }
        }
    }


    /**
     * 获取数据库连接
     *
     * @return
     */
    public static Connection getConnection() {
        try {
            return ds.getConnection();
        } catch (Exception e) {
            throw new RuntimeException();
        }
    }


}

模拟银行卡转账

账户模型

public class Account {

    private Integer id;

    private BigDecimal money;

    public Integer getId() {
        return id;
    }

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

    public BigDecimal getMoney() {
        return money;
    }

    public void setMoney(BigDecimal money) {
        this.money = money;
    }
}

账户持久化

public class AccountDAO {

    /**
     * 连接
     */
    private Connection conn;

    public AccountDAO() {
        this.conn = JdbcKit.getContainer().get();
    }


    /**
     * 查询账户ID
     *
     * @param id
     * @return
     */
    public Account findAccount(int id) {
        //处理事务 ,无参构造
        QueryRunner runner = new QueryRunner();
        String sql = "select * from account where id=?";
        Object[] params = {id};
        try {
            //附加连接 处理者为BeanHandler
            return (Account) runner.query(conn, sql, params, new
                    BeanHandler(Account.class));
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    /**
     * 更新账户
     *
     * @param a
     */
    public void updateAccount(Account a) {
        QueryRunner runner = new QueryRunner();
        String sql = "update account set money=? where id=?";
        Object[] params = {a.getMoney(), a.getId()};
        try {
            runner.update(conn, sql, params);
        } catch (SQLException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }
}

账户转账操作

public class AccountService {

    /**
     * 转账方法
     *
     * @param fromID 原始账户
     * @param toID   目标账户
     * @param money  转入多少钱
     */

    public void trafferAccount(int fromID, int toID, BigDecimal money) {
        try {
            JdbcKit.startTransaction();
            AccountDAO dao = new AccountDAO();
            Account from = dao.findAccount(fromID);
            Account to = dao.findAccount(toID);
            from.setMoney(from.getMoney().subtract(money));
            to.setMoney(to.getMoney().add(money));
            dao.updateAccount(from);
            dao.updateAccount(to);
            JdbcKit.commit();
        } catch (Exception e) {
            JdbcKit.rollback();
            throw new RuntimeException();
        } finally {
            JdbcKit.close();
        }
    }
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!