【推荐】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();
        }
    }
}
                    来源:oschina
链接:https://my.oschina.net/u/1398304/blog/3147327