JDBC进阶使用

JDBC的事务

1. 什么是事务

事务是指逻辑上的一组操作,组成这组操作各个逻辑单元具有不可分割性,要么全部成功,要么全部失败。

2. 事务的操作方法

修饰符方法描述
voidcommit()使自上次提交/回滚以来所做的所有更改都将永久性,并释放此 Connection对象当前持有的任何数据库锁。
voidsetAutoCommit(boolean autoCommit)将此连接的自动提交模式设置为给定状态。
booleangetAutoCommit()检索此 Connection对象的当前自动提交模式。
voidrollback()撤销在当前事务中所做的所有更改,并释放此Connection对象当前持有的任何数据库锁。(自动提交关闭时可用)

3. 事务的使用

Connection conn = null;
PreparedStatement pstmt = null;
String name1 = "崔二二";
String name2 = "陈憨憨";
int money = 3000;

try{

    //编写sql语句
    String sql = "update accounts set money = money + ? where id = (select id from user where user_name = ?)";
    //创建连接
    conn = JDBCUtils.getConnection();
    //!!!!开启事务,并取消自动提交
    conn.setAutoCommit(false);
    //预编译
    pstmt = conn.prepareStatement(sql);
    //设置参数
    pstmt.setInt(1, money);
    pstmt.setString(2, name1);
    pstmt.addBatch();
    pstmt.executeBatch();

    //int i = 1 / 0;

    pstmt.setInt(1, -money);
    pstmt.setString(2, name2);
    pstmt.addBatch();

    //执行批处理
    pstmt.executeBatch();
    //清空批处理
    pstmt.clearBatch();
    //!!!!提交事务
    conn.commit();
} catch (Exception e){
    try {
        //!!!!!若出现错误,则进行回滚,这个回滚不会滚好像问题不大,因为事务没有执行成功的时候本身就没有进行修改。
        conn.rollback();
    } catch (SQLException throwables) {
        throwables.printStackTrace();
    }
    e.printStackTrace();
} finally {
        JDBCUtils.release(pstmt, conn);
}

JDBC的连接池

1. 什么是连接池

  • 连接池是创建和管理连接的缓冲池
  • 这些连接准备好被任何需要他们的线程使用

2. 为什么要使用连接池

  • 连接池是稀有的
  • 连接对象的创建和销毁往往需要消耗不少的资源
  • 在服务器初始化的时候就创建好连接池并放入内存中,使用的时候从内存中获取和归还,这样可以极高的提高运行效率

3. 连接池的基本原理

image-20201114222129251

4. 自定义连接池

1)自定义连接池实现的步骤
  • 实现DataSource接口
修饰符方法描述
ConnectiongetConnection()尝试建立与此 DataSource对象所代表的数据源的连接。
ConnectiongetConnection(String username, String password)尝试建立与此 DataSource对象所代表的数据源的连接。
  • 初始化多个连接到内存中
  • 实现归还连接的方法
2)自定义连接池的代码实现
package com.Utils;

import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

/**
 * @author YanceyGao
 * @createTime  2020/11/14 23:00
 * @className   MyDataSource
 * @description 连接池工具类
 * @packageName MyDataSource.java
 */
public class MyDataSource implements DataSource {
    private List<Connection> connList = new ArrayList<Connection>();

    /**
     * @author      YanceyGao
     * @createTime  2020/11/15 16:33
     * @methodName  MyDataSource
     * @description 初始化连接池
     * @param:    null
     * @return:    null
     */
    public MyDataSource() throws SQLException {
        for(int i = 1; i <= 3; ++i){
            connList.add(JDBCUtils.getConnection());
        }
    }

    /**
     * @author      YanceyGao
     * @createTime  2020/11/15 16:34
     * @methodName  getConnection
     * @description 获取链接
     * @param:    null
     * @return:    java.sql.Connection
     */
    @Override
    public Connection getConnection() throws SQLException {
        //通过remove实现获取到连接的同时,在连接池中删除连接
        Connection conn = connList.remove(0);
        return conn;
    }

    /**
     * @author      YanceyGao
     * @createTime  2020/11/15 16:34
     * @methodName  getConnection
     * @description 获取连接
     * @param1    username:       用户名
     * @param2    password:       密码
     * @return:    java.sql.Connection
     */
    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return null;
    }

    /**
     * @author      YanceyGao
     * @createTime  2020/11/15 16:35
     * @methodName  addBackConnection
     * @description 返还连接
     * @param1    conn: 要返还的连接
     * @return:    void
     */
    public void addBackConnection(Connection conn){
        connList.add(conn);
    }

    /**
     * @author      YanceyGao
     * @createTime  2020/11/15 16:48
     * @methodName  release
     * @description 销毁Statement,归还连接
     * @param1    stmt:Statement
     * @param2    conn:连接
     * @return:    void
     */
    public void release(Statement stmt, Connection connection){
        //it is a good idea to release
        //resources in a finally() block
        //in reverse-order of their creation
        //if they are no-longer needed

        if(stmt != null){
            try{
                stmt.close();
            }catch(SQLException sqlEx){
                //ignore
                sqlEx.printStackTrace();
            }
            stmt = null;
        }

        this.addBackConnection(connection);

    }

    /**
     * @author      YanceyGao
     * @createTime  2020/11/15 16:50
     * @methodName  release
     * @description 归还连接
     * @param1    rs: 结果集
     * @param2    stmt:Statement
     * @param3    conn:连接
     * @return:    void
     */
    public void release(ResultSet rs, Statement stmt, Connection conn){
        //it is a good idea to release
        //resources in a finally() block
        //in reverse-order of their creation
        //if they are no-longer needed

        if(rs != null){
            try{
                rs.close();
            }catch(SQLException sqlEx){
                //ignore
            }

            rs = null;
        }

        if(stmt != null){
            try{
                stmt.close();
            }catch(SQLException sqlEx){
                //ignore
                sqlEx.printStackTrace();
            }
            stmt = null;
        }

        this.addBackConnection(conn);
    }








    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return null;
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return false;
    }

    @Override
    public PrintWriter getLogWriter() throws SQLException {
        return null;
    }

    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {

    }

    @Override
    public void setLoginTimeout(int seconds) throws SQLException {

    }

    @Override
    public int getLoginTimeout() throws SQLException {
        return 0;
    }

    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }
}
3)自定义连接池的使用
package com.RunTestDemo;

import com.Utils.JDBCUtils;
import com.Utils.MyDataSource;

import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

/**
 * @author YanceyGao
 * @createTime  2020/11/14 23:06
 * @className   JDBCConnectionPoolDemo
 * @description JDBC连接池测试
 * @packageName JDBCConnectionPoolDemo.java
 */
public class JDBCConnectionPoolDemo {

    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        MyDataSource myDataSource = null;

        try {
            //实例化工具类
            myDataSource = new MyDataSource();
            //获得连接
            connection = myDataSource.getConnection();
            //编写sql
            String sql = "select * from user";
            //预编译
            preparedStatement = connection.prepareStatement(sql);
            resultSet = preparedStatement.executeQuery();

            while(resultSet.next()){
                System.out.print(resultSet.getInt("id") + "\t");
                System.out.print(resultSet.getString("user_name") + "\t");
                System.out.print(resultSet.getString("user_sex") + "\t");
                System.out.println(resultSet.getInt("user_age"));
            }

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            myDataSource.release(resultSet, preparedStatement, connection);
        }

    }

}
4)自定义连接池的常见问题
  • 使用接口的实现类完成的构造

    • MyDataSource myDataSource = new MyDataSource();
      
    • 这种写法不方便程序的扩展。

  • 额外提供了方法(归还链接)

    • myDataSource.release(resultSet, preparedStatement, connection);
      
    • 这种方式增加了连接池使用的难度

5)常见问题的解决
  • 使用接口名实现接口
  • 不提供额外的方法,可以选择增强原来的类中的方法
    • 方法一:
      • 概述:采用继承的方式,继承原有的类并重写原方法
      • 条件:只能增强可以实例化的类(比如驱动包中实现的接口类就无法使用该方式,mysql.Connection就不行)
    • 方法二:
      • 概述:采用装饰者模式,就是包装
      • 条件:
        • 增强的类和被增强的类要实现相同的接口
        • 在增强的类中获得被增强的类的引用
    • 方法三:
      • 概述:使用动态代理

装饰者模式概述:

允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。

这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

6)通过装饰者模式增强Connection实现类
  • 继承原有Connection的接口
  • 获取创建的连接
  • 增强close()方法
package com.Utils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;

/**
 * @author YanceyGao
 * @createTime  2020/11/16 10:15
 * @className   MyConnectionWrapper
 * @description 使用装饰者模式增强Connection接口实现类中的Close方法
 * @packageName MyConnectionWrapper.java
 */
public class MyConnectionWrapper extends ConnectionTemplate {
	//ConnectionTemplate为模板类,只是继承并返回了原有的值
    private List<Connection> connectionList = null;
    Connection connection = null;

    public MyConnectionWrapper(Connection connection, List<Connection> connectionList){
        super(connection);
        this.connection = connection;
        this.connectionList = connectionList;
    }

    /**
     * @author      YanceyGao
     * @createTime  2020/11/16 9:01
     * @methodName  close
     * @description 增强close方法
     * @param:		null
     * @return: 	void
     */
    @Override
    public void close() throws SQLException {
        //super.close();

        this.connectionList.add(connection);

    }

}
  • 使用
/**
 * @author      YanceyGao
 * @createTime  2020/11/15 16:34
 * @methodName  getConnection
 * @description 获取链接
 * @param:    null
 * @return:    java.sql.Connection
 */
@Override
public Connection getConnection() throws SQLException {
    //通过remove实现获取到连接的同时,在连接池中删除连接
    Connection conn = connList.remove(0);
    MyConnectionWrapper myConnectionWrapper = new MyConnectionWrapper(conn, connList);
    return myConnectionWrapper;
}

5. 开源连接池的使用

1)Druid(德鲁伊)
  • 阿里巴巴旗下的开源连接池(数据源),可以通过Spring框架进行快速整合。
Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        DruidDataSource druidDataSource = null;
        DataSource dataSource = null;
        Properties properties = new Properties();

        try {
            properties.load(new FileInputStream("src/main/java/mysqlConnectionUtils.properties"));
            //实例化德鲁伊
            druidDataSource = new DruidDataSource();
            //手动设置连接参数,像个憨憨一样
//            druidDataSource.setUrl(properties.getProperty("url"));
//            druidDataSource.setUsername(properties.getProperty("username"));
//            druidDataSource.setPassword(properties.getProperty("password"));
//            druidDataSource.setDriverClassName(properties.getProperty("driverClassName"));
            //自动配置连接参数,通过德鲁伊的数据源工厂加载配置文件
            dataSource = DruidDataSourceFactory.createDataSource(properties);
            //获取连接
            //connection = druidDataSource.getConnection();
            connection = dataSource.getConnection();
            String sql = "select user.id, user_name, user_age, user_sex, user_tele, money from accounts, user where accounts.id = user.id";
            preparedStatement = connection.prepareStatement(sql);
            resultSet = preparedStatement.executeQuery();
            while(resultSet.next()){
                System.out.print(resultSet.getInt("id") + "\t");
                System.out.print(resultSet.getString("user_name") + "\t");
                System.out.print(resultSet.getInt("user_age") + "\t");
                System.out.print(resultSet.getString("user_sex") + "\t");
                System.out.print(resultSet.getString("user_tele") + "\t");
                System.out.println(resultSet.getInt("money"));
            }
        } catch (SQLException | FileNotFoundException throwables) {
            throwables.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.release(resultSet, preparedStatement, connection);
        }
2)C3P0
  • C3P0是一个开源的连接池,它实现了数据源和JNDI的绑定,支持JDBC3规范和JDBC2的标准扩展,目前使用它的开源项目有Hibernate、Spring等。
//代码使用的是手动配置的方式,因为idea的自动配置不知道怎么回事,无法加载配置文件,后面找到原因后会进行更新
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
//创建连接池
ComboPooledDataSource dataSource = new ComboPooledDataSource();
Properties properties = new Properties();
try {
    //c3p0不需要获取配置文件,在创建连接池时会自动在类路径下自动查找属性文件
    properties.load(new FileInputStream("src/main/java/mysqlConnectionUtils.properties"));
    //配置参数
    dataSource.setDriverClass(properties.getProperty("driverClassName"));
    dataSource.setJdbcUrl(properties.getProperty("url"));
    dataSource.setUser(properties.getProperty("username"));
    dataSource.setPassword(properties.getProperty("password"));

    connection = dataSource.getConnection();
    String sql = "select user.id, user_name, user_age, user_sex, user_tele, money from accounts, user where accounts.id = user.id";
    preparedStatement = connection.prepareStatement(sql);
    resultSet = preparedStatement.executeQuery();
    while(resultSet.next()){
        System.out.print(resultSet.getInt("id") + "\t");
        System.out.print(resultSet.getString("user_name") + "\t");
        System.out.print(resultSet.getInt("user_age") + "\t");
        System.out.print(resultSet.getString("user_sex") + "\t");
        System.out.print(resultSet.getString("user_tele") + "\t");
        System.out.println(resultSet.getInt("money"));
    }

} catch (SQLException | PropertyVetoException | FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    JDBCUtils.release(resultSet, preparedStatement, connection);
}

6. DBUtils

1)DBUtils概述
  • DBUtils是Apache提供的一个对JDBC进行简单封装的开源工具类库,使用它能够简化JDBC应用程序的开发。同时,也不会影响程序的性能。
  • 因为JDBC有大量重复代码,比如获得连接,预编译SQL,释放资源等,往往自行封装浪费了不少时间因此将类似的工具类进行封装,可以减少重复开发。
2)DBUtils的API概述
a. QueryQunner对象:核心运行类

构造函数

//无参,有事务管理时使用
public QueryRunner() {}
//有参,无事务管理时使用
public QueryRunner(DataSource ds) {
        super(ds);
}

方法

//插入方法,可以进行增删改,有事务管理时使用
public int update(Connection conn, String sql, Object... params)
//插入方法重载,无事务管理时使用
public int update(String sql, Object... params)
//查询方法,无事务管理时使用
public <T> T query(String sql, ResultSetHandler<T> rsh, Object... params) 
//查询方法重载,有事务管理时使用
public <T> T query(Connection conn, String sql, ResultSetHandler<T> rsh, Object... params)
//批处理
public int[] batch(Connection conn, String sql, Object[][] params)
//批处理重载
public int[] batch(String sql, Object[][] params)
b. DBUtils对象:事务操作

方法

//事务提交
public static void commitAndCloseQuietly(Connection conn)
//事务回滚
public static void rollbackAndCloseQuietly(Connection conn)
3)DBUtils的使用
package com.RunTestDemo;

import com.Domain.Account;
import com.Utils.JDBCUtils;
import com.Utils.JDBCUtilsPro;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;
import org.omg.PortableInterceptor.SYSTEM_EXCEPTION;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author      YanceyGao
 * @createTime  2020/11/17 9:57
 * @projectName DemoTest
 * @packageName com.RunTestDemo
 * @className   JDBCDBUtilsTestDemo
 * @description DBUtils的使用
 */
public class JDBCDBUtilsTestDemo {

    public static void main(String[] args) throws SQLException {
        JDBCDBUtilsTestDemo jdbcdbUtilsTestDemo = new JDBCDBUtilsTestDemo();

        String sql = "insert into user values(null, ?, ?, ?, ?)";

//        jdbcdbUtilsTestDemo.insertTest(sql);
        jdbcdbUtilsTestDemo.selectTest("select * from user where id in(?, ?, ?, ?, ?)");
    }

    /**
     * @author      YanceyGao
     * @createTime  2020/11/18 8:37
     * @methodName  selectTest
     * @description 查询
     * @param1		sql: SQL语句
     * @return: 	void
     */
    public void selectTest(String sql) throws SQLException {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        DataSource source = JDBCUtilsPro.getDataSource();

        QueryRunner queryRunner = new QueryRunner(source);
        //Account是一个封装好的实体对象,内容是数据库中表accounts的属性和get、set方法。
        final List<Account> accountList =  queryRunner.query(sql, new ResultSetHandler<List<Account>>(){
            @Override
            public List<Account> handle(ResultSet resultSet) throws SQLException {
                List<Account> accountList = new ArrayList();
                while(resultSet.next()){
                    Account account = new Account();
                    account.setId(resultSet.getInt("id"));
                    account.setUserName(resultSet.getString("user_name"));
                    account.setUserSex(resultSet.getString("user_sex"));
                    account.setUserAge(resultSet.getInt("user_age"));
                    account.setUserTele(resultSet.getString("user_tele"));
                    accountList.add(account);
                }

                return accountList;
            }
        }, 1, 2, 3, 4, 5);

        for(Account account : accountList){
            System.out.println(account);
            /*System.out.print(account.getId() + "\t");
            System.out.print(account.getUserName() + "\t");
            System.out.print(account.getUserSex() + "\t");
            System.out.print(account.getUserAge() + "\t");
            System.out.println(account.getUserTele());*/
        }
    }

    /**
     * @author      YanceyGao
     * @createTime  2020/11/17 10:30
     * @methodName  insertTest
     * @description 插入操作
     * @param:		null
     * @return: 	void
     */
    public void insertTest(String sql) throws SQLException {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        DataSource source = JDBCUtilsPro.getDataSource();

        QueryRunner queryRunner = new QueryRunner(source);

        int ans = queryRunner.update(sql, "嘤嘤嘤", "female", 21, "187-9876-5678");

        System.out.println(ans);

        /*
        while(rs.next()){
            System.out.print(rs.getInt("id") + " ");
            System.out.print(rs.getString("user_name") + " ");
            System.out.print(rs.getString("user_sex") + " ");
            System.out.print(rs.getInt("user_age") + " ");
            System.out.println(rs.getString("user_tele"));
        }
        */
    }

}

package com.Utils;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * @author YanceyGao
 * @createTime 2020/11/17 10:04
 * @projectName DemoTest
 * @packageName com.Utils
 * @className JDBCUtilsPro
 * @description JDBCUtilsPro使用了Druid的连接池。
 */
public class JDBCUtilsPro {

    private static final Properties properties = new Properties();
    private static List<Connection> connList = new ArrayList<Connection>();
    private static DataSource dataSource = null;

    static{
        try {
            properties.load(new FileInputStream("src/main/java/mysqlConnectionUtils.properties"));
            dataSource = DruidDataSourceFactory.createDataSource(properties);;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * @author      YanceyGao
     * @createTime  2020/11/17 10:13
     * @methodName  getConnection
     * @description 获得连接
     * @param:		null
     * @return: 	java.sql.Connection
     */
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    /**
     * @author      YanceyGao
     * @createTime  2020/11/17 10:13
     * @methodName  getDataSource
     * @description 获得连接池
     * @param:		null
     * @return: 	javax.sql.DataSource
     */
    public static DataSource getDataSource(){
        return dataSource;
    }


    /**
     * @author      YanceyGao
     * @createTime  2020/11/17 10:14
     * @methodName  release
     * @description 归还链接
     * @param1		rs: 结果集
     * @param2		stmt: 执行
     * @param3		conn: 连接
     * @return: 	void
     */
    public static void release(ResultSet rs, Statement stmt, Connection conn){
        //it is a good idea to release
        //resources in a finally() block
        //in reverse-order of their creation
        //if they are no-longer needed

        if(rs != null){
            try{
                rs.close();
            }catch(SQLException sqlEx){
                //ignore
            }

            rs = null;
        }

        if(stmt != null){
            try{
                stmt.close();
            }catch(SQLException sqlEx){
                //ignore
                sqlEx.printStackTrace();
            }
            stmt = null;
        }

        if(conn != null){
            try{
                conn.close();
            }catch(SQLException sqlEx){
                //ignore
                sqlEx.printStackTrace();
            }
            conn = null;
        }
    }
}

4)ResultSetHandler的使用
a. BeanHandler和BeanListHandler

BeanHandler

将一条记录封装到一个JavaBean中

BeanListHandler

将多条记录封装到一个装有JavaBean的List集合中

/**
 * @author      YanceyGao
 * @createTime  2020/11/18 9:14
 * @methodName  useBeanHandler
 * @description 多条记录封装
 * @param1    sql:
 * @return:    void
 */
public void useBeanHandler(String sql) throws SQLException {
    QueryRunner queryRunner = new QueryRunner(JDBCUtilsPro.getDataSource());
    Connection connection = null;
    PreparedStatement preparedStatement = null;
    ResultSet resultSet = null;

    //通过Bean方式实现的话,Account属性名称要和数据库中属性名称一致。不光属性名要一样,get和set方法名也要一样,淦
    List<Account> accountList = queryRunner.query(sql, new BeanListHandler<Account>(Account.class), 1, 2, 3, 4, 5);

    //要想这样输出必须重写类的toString()方法,不然默认调用Object的toString()方法输出
    // 这样输出结果为account.getClass().getName() + '@' + Integer.toHexString(hashCode()).
    //就是类的名字加上16进制的哈希值。
    for(Account account : accountList){
        System.out.println(account);
        /*System.out.print(account.getId() + "\t");
        System.out.print(account.getUser_name() + "\t");
        System.out.print(account.getUser_sex() + "\t");
        System.out.print(account.getUser_age() + "\t");
        System.out.println(account.getUser_tele());*/
    }
}
b. MapHandler和MapListHandler

MapHandler

将一条记录封装到一个Map集合中,Map的key是列名,Map的value就是表中列的记录。

MapListHandler

将多条记录封装到一个装有Map的List集合中。

/**
 * @author      YanceyGao
 * @createTime  2020/11/18 9:18
 * @methodName  useMapHandler
 * @description mapHander的使用
 * @param1    sql: sql语句
 * @return:    void
 */
public void useMapHandler(String sql) throws SQLException {
    QueryRunner queryRunner = new QueryRunner(JDBCUtilsPro.getDataSource());

    List<Account> ans = new ArrayList<Account>();

    List<Map<String, Object>> mapList = queryRunner.query(sql, new MapListHandler(), 1, 2, 3, 4, 5);

    for(Map<String, Object> map : mapList){
        Account account = new Account();
        account.setId((Integer) map.get("id"));
        account.setUser_name((String) map.get("user_name"));
        account.setUser_sex((String) map.get("user_sex"));
        account.setUser_age((Integer) map.get("user_age"));
        account.setUser_tele((String) map.get("user_tele"));
        ans.add(account);
    }

    for(Account account : ans){
        System.out.println(account);
    }
}
c. ColumnListHandler、ScalarHandler、KeyedHandler

ColumnListHandler

将数据中的某列封装到List集合中。

/**
     * @author      YanceyGao
     * @createTime  2020/11/18 9:37
     * @methodName  useColumnHandler
     * @description ColumnHandler的使用
     * @param1		sql:
     * @return: 	void
     */
    public void useColumnHandler(String sql) throws SQLException {
        QueryRunner queryRunner = new QueryRunner(JDBCUtilsPro.getDataSource());
        //为了维持数据的通用性,最好用Object
        List<Object> name = queryRunner.query(sql, new ColumnListHandler<Object>("user_name"), 1, 2, 3, 4, 5);

        for(Object account : name){
            System.out.println(account);
        }
    }

ScalarHandler

将单个值进行封装。

/**
 * @author      YanceyGao
 * @createTime  2020/11/18 9:41
 * @methodName  useScalarHandler
 * @description ScalarHander的使用,单值封装
 * @param1    sql: SQL语句
 * @return:    void
 */
public void useScalarHandler(String sql) throws SQLException {
    QueryRunner queryRunner = new QueryRunner(JDBCUtilsPro.getDataSource());

    //注意sql使用Count聚合函数返回值为long类型,不能使用Integer接收。
    Object query = queryRunner.query(sql, new ScalarHandler<Object>(), 1, 2, 3);

    System.out.println(query);
}

KeyedHandler

将一条记录封装到一个Map集合中,将多条记录封装到一个装有Map集合的Mao集合中,并且外层的Map的key自定义。和MapListHandler的区别是,KeyedHandler外层是Map(好一个套娃小能手),MapListHandler外层是List。

/**
 * @author      YanceyGao
 * @createTime  2020/11/18 9:56
 * @methodName  useKeyedHandler
 * @description keyedHandler的使用,套娃是Map,可以指定外层key值
 * @param1    sql:sql语句
 * @return:    void
 */
public void useKeyedHandler(String sql) throws SQLException {
    QueryRunner queryRunner = new QueryRunner(JDBCUtilsPro.getDataSource());

    //指定key值
    Map<Object, Map<String, Object>> mapMap = queryRunner.query(sql, new KeyedHandler<Object>("user_name"), 1, 2, 3, 4, 5);

    System.out.println(mapMap);
}

Q.E.D.


If you don't come, I will snow.