JDBC学习文档

115 阅读6分钟

JDBC

  • sun公司提供的一套用于数据库操作的接口,java程序员只需要面向这套接口编程即可
  • 不同的数据库厂商需要针对这套接口,提供不同的实现,不同的实现的集合,就是不同数据库的驱动——面向接口编程

JDBC的体系结构

面向应用的API:开发人员编程使用(链接数据库,执行SQL语句等)

面向数据库的API:供开发商数据库驱动程序用

链接方式

  • 五种迭代

第五种

1.配置文件JDBC.properties

user=root
password=zmj.666.999
url=jdbc:mysql://localhost:3306/test?serverTimezone=UTC
driverClass=com.mysql.jdbc.Driver

2.JDBC_Connection.java

import org.junit.Test;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Properties;

/**
 * Created by KingsLanding on 2022/6/4 16:17
 */
public class JDBC_Connection {

    @Test
    public void getConnection() throws Exception {
        //读取配置文件中的4个基本信息
        InputStream is = JDBC_Connection.class.getClassLoader().getResourceAsStream("JDBC.properties");
        Properties pros = new Properties();
        pros.load(is);

        String user = pros.getProperty("user");
        String password = pros.getProperty("password");
        String url = pros.getProperty("url");
        String driverClass = pros.getProperty("driverClass");

        //2.加载驱动
        Class.forName(driverClass);

        //3.获取链接
        Connection conn= DriverManager.getConnection(url,user,password);
        System.out.println(conn);
    }
}

Statement——>PreparedStatement

  • Statement会导致SQL注入的问题,所以使用Statement的子接口PreparedStatement替换

数据插入

package statement;

import connection.JDBC_Connection;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;


/**
 * 使用PreparedStatement替换Statement实现对数据表的增删改查
 *
 * Created by KingsLanding on 2022/6/4 18:30
 */
public class PreparedStatement {
    @Test
    public void getConnection(){
        //读取配置文件中的4个基本信息
        Connection conn= null;
        java.sql.PreparedStatement ps = null;
        try {
            InputStream is = PreparedStatement.class.getClassLoader().getResourceAsStream("JDBC.properties");
            Properties pros = new Properties();
            pros.load(is);

            String user = pros.getProperty("user");
            String password = pros.getProperty("password");
            String url = pros.getProperty("url");
            String driverClass = pros.getProperty("driverClass");

            //2.加载驱动
            Class.forName(driverClass);

            //3.获取链接
            conn = DriverManager.getConnection(url,user,password);
            System.out.println(conn);//测试是否链接成功

            //4.预编译sql语句,返回PreparedStatement实例
            String sql="insert into user(id,username,password)value(?,?,?)";//?是占位符
            ps = conn.prepareStatement(sql);
            ps.setInt(1,3);
            ps.setString(2,"张千一");
            ps.setString(3,"190321435");

            //6.执行操作
            ps.execute();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //7.资源关闭
            try {
                if(conn!=null)
                    conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                if(conn!=null);
                     ps.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

JDBC_Util通用工具类

package jdbcUtil;

import org.junit.Test;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

/**JDBC链接和关闭工具类
 * 静态方法能被类调用
 * Created by KingsLanding on 2022/6/5 12:55
 */

public class JDBC_Util {
    public static Connection getConnection() throws Exception{

        //读取配置文件中的4个基本信息
        InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("JDBC.properties");
        Properties pros = new Properties();
        pros.load(is);

        String user = pros.getProperty("user");
        String password = pros.getProperty("password");
        String url = pros.getProperty("url");
        String driverClass = pros.getProperty("driverClass");

        //2.加载驱动
        Class.forName(driverClass);

        //3.获取链接
        Connection conn= DriverManager.getConnection(url,user,password);
        System.out.println(conn);
        return conn;
    }

    /**
     * 关闭Connection和Statement
     * @param conn
     * @param ps
     */
    public static void closeResource(Connection conn, Statement ps){
        try {
            if(conn!=null)
                conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if(conn!=null);
            ps.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

调用工具类执行操作

package statement;

import jdbcUtil.JDBC_Util;
import org.junit.Test;

import java.sql.Connection;
import java.sql.PreparedStatement;

/**
 * Created by KingsLanding on 2022/6/5 13:18
 */
public class PreparedStatementUpdate {
    @Test
    public void testUpdate() {
        Connection conn= null;
        java.sql.PreparedStatement ps = null;
        //1.链接数据库
        try {
            conn = JDBC_Util.getConnection();//类调用数据库链接方法
            //2.预编译sql语句,返回PreparedStatement实例
            String sql="update user set username = ?,password = ? where id=3";
            ps = conn.prepareStatement(sql);

            //3.填充占位符
            ps.setString(1,"张干一");
            ps.setString(2,"1223000000");
            //4.执行
            ps.execute();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //5.资源关闭
            JDBC_Util.closeResource(conn,ps);//类调用资源关闭方法
        }

    }
}

增删改通用

  • 将sql和占位符以形参的方式在方法中定义

  • 占位符用可变参数设置,for循环填入占位符

  • 调用通用数据库操作方法,设置参数update(sql,args);

            for(int i=0;i<args.length;i++){
                //i+1是占位符位置,从1开始,args[i]是数据库属性名从0开始
                ps.setObject(i+1,args[i]);
            }
    
package statement;

import jdbcUtil.JDBC_Util;
import org.junit.Test;

import java.sql.Connection;
import java.sql.PreparedStatement;

/**
 * 通用的增删改操作
 * Created by KingsLanding on 2022/6/5 14:26
 */
public class Update {
    //可变形参...arg必须和sql中的占位符对应
    public void update(String sql,Object ...args){
        Connection conn =null;
        PreparedStatement ps=null;
        try {
            //1.链接数据库
            conn = JDBC_Util.getConnection();
            //2.预编译sql语句,返回PreparedStatement实例
            ps = conn.prepareStatement(sql);
            //3.填充占位符
            for(int i=0;i<args.length;i++){
                //i+1是占位符位置,从1开始,args[i]是数据库属性名从0开始
                ps.setObject(i+1,args[i]);
            }
            //4.执行
            ps.execute();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //5.资源关闭
            JDBC_Util.closeResource(conn,ps);
        }
    }

    //插入数据操作
    @Test
    public void insert(){
        String sql="insert into user(id,username,password)value(?,?,?)";
        update(sql,5,"张明均","1902421140");
    }

    @Test
    //删除数据操作
    public void delete(){
        String sql="delete from user where id=?";
        update(sql,2);
    }
    /**
        @Test
    //删除数据操作
    public void delete(){
        String sql="delete from user where id=?";
        Object[] args={1};
        update(sql,args);
    }
    */

}

javaBean

  • 1、根据数据表结构定义响应数据类型的对象
  • 2、无参构造器
  • 3、有参构造器
  • 4、get() set()方法
  • 5、toString()方法

ORM编程思想(Object,relational,mapping)

package user;

/**
 * Created by KingsLanding on 2022/6/4 18:39
 * ORM编程思想(Object,relational,mapping)
 * 表中的一条记录对应java类的一个对象
 * 表中的字段对应java类的一个属性(数据类型)
 */
public class User {
    private int id;
    private String username;
    private String password;

    public User() {

    }

    public User(int id, String username, String password) {//带参构造器
        this.id = id;
        this.username = username;
        this.password = password;
    }

    public int getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

查询ResultSet

package statement;

import jdbcUtil.JDBC_Util;
import org.junit.Test;
import user.User;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

/**
 * Created by KingsLanding on 2022/6/5 17:16
 */
public class Select {
    @Test
    public void select() {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            //获取链接
            conn = JDBC_Util.getConnection();
            //预编译
            String sql="select * from user where id=?";
            ps = conn.prepareStatement(sql);

            ps.setInt(1,3);

            //执行,并返回结果集
            rs = ps.executeQuery();
            //处理结果集
            if(rs.next()){//判断结果是否有数据,有返回true 同时指针指向下一位

                //获取当前这条数据的各个字段值
                int id = rs.getInt(1);
                String username = rs.getString(2);
                String password = rs.getString(3);

                //方式一:直接显示
                //System.out.println("username"+username+"password"+password);

                //方式二:存到数组里
                //Object[] ob = {username, password};

                //方式三:JavaBean,将要操作的数据封装成一个个对象
                User user = new User(id, username, password);
                System.out.println(user);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            JDBC_Util.closeResource(conn,ps,rs);
        }
    }
}

查询通用

package statement;

import jdbcUtil.JDBC_Util;
import jdk.nashorn.internal.scripts.JD;
import org.junit.Test;
import user.User;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;

/**
 * Created by KingsLanding on 2022/6/6 13:04
 */
public class Select{

    public User select(String sql, Object ...args){

        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            conn = JDBC_Util.getConnection();

            ps = conn.prepareStatement(sql);
            for (int i=0;i<args.length;i++){
                ps.setObject(i+1,args[i]);
            }

            rs = ps.executeQuery();

            //获取结果集的元数据
            ResultSetMetaData rsmd = rs.getMetaData();
            //通过ResultSetMetaData获取结果集中的列数
            int columnCount = rsmd.getColumnCount();

            if(rs.next()){
                User user = new User();
                //处理结果集一行数据中的每一列
                for(int i=0;i<columnCount;i++){
                    //获取列值
                    Object columnValue = rs.getObject(i + 1);
                    //获取每个列的列名
                    String columnName = rsmd.getColumnName(i+1);

                    //给user对象指定的columnName属性,赋值为columnValue,通过反射
                    Field field = User.class.getDeclaredField(columnName);
                    field.setAccessible(true);
                    field.set(user,columnValue);
                }
                return user;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBC_Util.closeResource(conn,ps,rs);
        }

        return null;
    }

    @Test
    public void selectTest(){
        String sql="select * from user where id=?";
        User user1 = select(sql, 3);
        System.out.println(user1);

    }
}

查询获取列名——>获取别名

  • 使用getColumnLabel替换getColumnName来获取列的别名
//获取每个列的列名getColumnName
//getColumnName()方法要求表的字段名,必须与javaBean类中的属性名相同,不推荐使用
String columnName = rsmd.getColumnName(i+1);
//获取每个列的别名
//别名的命名必须与javaBean类的属性名相同
String columnLabel = rsmd.getColumnLabel(i + 1);
    /**
     * 针对表的字段名与类的属性名不同的情况
     * 1.必须声明sql时,使用类的属性来命名字段的别名
     * 2.使用ResultSetMetaData获取结果集的元数据,使用getColumnLabel替换getColumnName
     *   获取列的别名
     *  说明:如果sql声明中没有字段的别名(字段名与属性名相同)getColumnLabel
     *        同样能获取列名
     */

    @Test
    public void selectTest2(){
        String sql ="select id ID,username userName,password pwd from user where id=?";
        select(sql,3);
    }

集合 不同数据表的通用查询

//创建集合对象 ArrayList list = new ArrayList<>();

package statement;

import jdbcUtil.JDBC_Util;
import org.junit.Test;
import user.Car;
import user.User;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;

/**
 * Created by KingsLanding on 2022/6/6 17:06
 */
public class List {

    public <T> ArrayList<T> getForList(Class<T> clazz, String sql, Object ...args){

        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            conn = JDBC_Util.getConnection();

            ps = conn.prepareStatement(sql);
            for (int i=0;i<args.length;i++){
                ps.setObject(i+1,args[i]);
            }

            rs = ps.executeQuery();

            //获取结果集的元数据
            ResultSetMetaData rsmd = rs.getMetaData();
            //通过ResultSetMetaData获取结果集中的列数
            int columnCount = rsmd.getColumnCount();

            //创建集合对象
            ArrayList<T> list = new ArrayList<>();
            while (rs.next()){
                T t = clazz.newInstance();
                //处理结果集一行数据中的每一列;给t对象指定的属性赋值
                for(int i=0;i<columnCount;i++){
                    //获取列值
                    Object columnValue = rs.getObject(i + 1);
                    //获取每个列的列名getColumnName
                    //getColumnName()方法要求表的字段名,必须与javaBean类中的属性名相同,不推荐使用
                    //String columnName = rsmd.getColumnName(i+1);
                    //获取每个列的别名
                    //别名的命名必须与javaBean类的属性名相同
                    String columnLabel = rsmd.getColumnLabel(i + 1);

                    //给user对象指定的columnName属性,赋值为columnValue,通过反射
                    Field field = clazz.getDeclaredField(columnLabel);
                    field.setAccessible(true);
                    field.set(t,columnValue);
                }
                list.add(t);
            }
            return list;

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBC_Util.closeResource(conn,ps,rs);
        }
        return null;
    }

    @Test
    public void selectTest(){
        String sql="select * from user where id<?";
        ArrayList<User> forList = getForList(User.class, sql, 6);
        forList.forEach(System.out::println);

    }

    @Test
    public void selectTest01(){
        String sql="select * from car where id<?";
        ArrayList<Car> forList = getForList(Car.class, sql, 5);
        forList.forEach(System.out::println);
    }

}

两种技术

  • JDBC结果集的元数据:ResultSetMetaData
  • 获取列数:getColumnCount()
  • 获取列的别名:getColumnLabel()
  • 通过反射,创建指定类的对象,获取指定的属性并赋值

事务

  • 数据库事务定义:

    1.一组逻辑操作单元,使数据从一种状态变换到另一种状态

    2.一组逻辑操作单元:一个或多个DML操作:增删改查(insert,delect,update,select)

  • 事务处理的原则:保证所有事务都作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式。

    就是说当一个事务中在执行多个操作时,要么所有操作都被提交,这些数据都将永久保存下来;要么数据库管理系统放弃所做的一切修改,整个事务回滚(rollback)最初状态。

  • 数据一旦提交,就将不能在回滚,意味着回滚必须在事务提交之前,一旦连接关闭,当前事务就会直接提交,所以回滚也必须在数据库链接关闭之前

  • 那些操作会导致数据的自动提交?

    1.DDL操作一旦执行,都会自动提交:set autocommit = false 对DDL操作失效

    2.DML默认情况下,一旦执行,就会自动提交:可以通过set autocommit = false的方式取消DML的自动提交

  • 默认关闭连接是,会自动提交数据

考虑事务

  • 调用 Connection 对象的 setAutoCommit(false); 以取消自动提交事务
  • 在所有的 SQL 语句都成功执行后,调用 commit(); 方法提交事务
  • 在出现异常时,调用 rollback(); 方法回滚事务
package test;

import jdbcUtil.JDBC_Util;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * Created by KingsLanding on 2022/6/8 12:30
 */
public class UpdateTure {

    public static void main(String[] args) {
        Connection conn=null;
        try {
            //1.在此处连接数据库
            conn = JDBC_Util.getConnection();
            //2.取消数据的自动提交
            conn.setAutoCommit(false);
            String sql="update user set username = ?,password = ? where id=3";
            update(conn,sql,"张二","1234567");

//            System.out.println(10/0);//模拟故障

            String sql2="update user set username = ?,password = ? where id=4";
            update(conn,sql2,"张万","12344556");
            //3.完成提交数据
            conn.commit();
            System.out.println("转账成功");

        } catch (Exception e) {
            e.printStackTrace();
            //4.数据回滚
            try {
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        } finally {
            JDBC_Util.closeResource(conn,null);
        }
    }

    //可变形参...arg必须和sql中的占位符对应
    public static int update(Connection conn,String sql, Object... args) {
        PreparedStatement ps = null;
        try {
            //数据库链接,造的地方链接
            //2.预编译sql语句,返回PreparedStatement实例
            ps = conn.prepareStatement(sql);
            //3.填充占位符
            for (int i = 0; i < args.length; i++) {
                //i+1是占位符位置,从1开始,args[i]是数据库属性名从0开始
                ps.setObject(i + 1, args[i]);
            }
            //4.执行
            /**
             * ps.execute()
             * 如果执行的是查询操作,则返回true
             * 如果执行的是增删改操作,则返回false
             */
            // ps.execute();
            return ps.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //5.资源关闭
            JDBC_Util.closeResource(null, ps);
        }
        return 0;
    }
}

事务的ACID属性

  1. 原子性(Atomicity) 原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
  2. 一致性(Consistency) 事务必须使数据库从一个一致性状态变换到另外一个一致性状态。
  3. 隔离性(Isolation) 事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
  4. 持久性(Durability) 持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响。

6.3.1 数据库的并发问题

  • 对于同时运行的多个事务, 当这些事务访问数据库中相同的数据时, 如果没有采取必要的隔离机制, 就会导致各种并发问题:
    • 脏读: 对于两个事务 T1, T2, T1 读取了已经被 T2 更新但还没有被提交的字段。之后, 若 T2 回滚, T1读取的内容就是临时且无效的。
    • 不可重复读: 对于两个事务T1, T2, T1 读取了一个字段, 然后 T2 更新了该字段。之后, T1再次读取同一个字段, 值就不同了。
    • 幻读: 对于两个事务T1, T2, T1 从一个表中读取了一个字段, 然后 T2 在该表中插入了一些新的行。之后, 如果 T1 再次读取同一个表, 就会多出几行。
  • 数据库事务的隔离性: 数据库系统必须具有隔离并发运行各个事务的能力, 使它们不会相互影响, 避免各种并发问题。
  • 一个事务与其他事务隔离的程度称为隔离级别。数据库规定了多种事务隔离级别, 不同隔离级别对应不同的干扰程度, 隔离级别越高, 数据一致性就越好, 但并发性越弱。

四种隔离级别

  • 数据库提供的4种事务隔离级别:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oFEbbexm-1601475477320)(尚硅谷_宋红康_JDBC.assets/1555586275271.png)]

  • Oracle 支持的 2 种事务隔离级别:READ COMMITED, SERIALIZABLE。 Oracle 默认的事务隔离级别为: READ COMMITED

  • Mysql 支持 4 种事务隔离级别。Mysql 默认的事务隔离级别为: REPEATABLE READ。

在MySql中设置隔离级别

  • 每启动一个 mysql 程序, 就会获得一个单独的数据库连接. 每个数据库连接都有一个全局变量 @@tx_isolation, 表示当前的事务隔离级别。

  • 查看当前的隔离级别:

    SELECT @@tx_isolation;
    1
    
  • 设置当前 mySQL 连接的隔离级别:

    set  transaction isolation level read committed;
    1
    
  • 设置数据库系统的全局的隔离级别:

    set global transaction isolation level read committed;
    1
    
  • 补充操作:

    创建mysql数据库用户:

    create user tom identified by 'abc123';
    1
    

    授予权限

    #授予通过网络方式登录的tom用户,对所有库所有表的全部权限,密码设为abc123.
    grant all privileges on *.* to tom@'%'  identified by 'abc123'; 
    
     #给tom用户使用本地命令行方式,授予atguigudb这个库下的所有表的插删改查的权限。
    grant select,insert,delete,update on atguigudb.* to tom@localhost identified by 'abc123'; 
    

德鲁伊线程池

druid闸瓦包下载地址

repo1.maven.org/maven2/com/…

properties配置文件

username=root
password=zmj.666.999
url=jdbc:mysql://localhost:3306/jdbctest?serverTimezone=UTC
driverClass=com.mysql.jdbc.Driver

建立链接

/**
 * Created by KingsLanding on 2022/6/10 13:10
 */
public class Druid_JDBC {

    @Test
    public static Connection getDruidConnection() throws Exception{
        Properties pros = new Properties();

        //读取druid.properties配置文件
        InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("druid.properties");
        //使用反射动态获取连接
       	//InputStream is = DruidUtils.class.getClassLoader().getResourceAsStream("druid.properties");
        //从流中加载数据
        pros.load(is);
        //创建数据库连接池
        DataSource source = DruidDataSourceFactory.createDataSource(pros);
        //获取链接
        Connection conn = source.getConnection();
        System.out.println(conn);

        return conn;
    }
}

DbUtils工具类

  • Apache-DBUtils简介 commons-dbutils是Apache组织提供的一个开源JDBC工具类库,它是对JDBC的简单封装,学习成本极 低,并且使用dbutils能极大简化jdbc编码的工作量,同时也不会影响程序的性能。

  • API介绍:

    org.apache.commons.dbutils .QueryRunner org.apache.commons.dbutils ResultSetHandler 工具类: org.apache.commons.dbutils.DbUtils

DBUtils闸瓦包下载地址

repo1.maven.org/maven2/comm…

操作测试

插入数据测试

(正常操作需要使用try-catch-finally)

public class InsertTest {

    @Test
    public void Insert()throws Exception{
        //获取连接
        Connection conn = Druid_JDBC.getDruidConnection();
		//DBUtils工具类中的QueryRunner()
        QueryRunner runner = new QueryRunner();
        String sql="insert into user(name,age,phone)value(?,?,?)";
		//DBUtils中提供的update方法
        int insertCount = runner.update(conn, sql, "zmj", 22, "122343235");
        System.out.println("插入了"+insertCount+"条数据");

        //JDBC_Util.closeResource(conn,null);
        //closeQuietly()关闭连接
        DbUtils.closeQuietly(conn);

    }
}

查询操作测试

/**
 * Created by KingsLanding on 2022/7/9 15:19
 */
public class SelectTest {
    /*
    测试查询

        BeanHandler:是ResultSetHandler接口的实现类,用于封装表中的一条数据
     */

    @Test
    public void QueryTest() throws Exception{

        Connection conn = Druid_JDBC.getDruidConnection();

        QueryRunner runner = new QueryRunner();

        String sql="select id,name,age,phone from user where id=?";
        
        BeanHandler<userBean> handler = new BeanHandler<>(userBean.class);
        
        userBean query = runner.query(conn, sql, handler, 1);
        System.out.println(query);

        DbUtils.closeQuietly(conn);
    }

    /*
        BeanListHandler 是ResultSetHandler<List<T>>接口的实现类,用于封装表中的多组数据
     */
    @Test
    public void selectTest2() throws Exception{

        Connection conn = Druid_JDBC.getDruidConnection();

        QueryRunner runner = new QueryRunner();
        String sql="select id,name,age,phone from user where id<=?";
        BeanListHandler<userBean> listHandler = new BeanListHandler<>(userBean.class);
        List<userBean> query = runner.query(conn, sql, listHandler, 3);

//        System.out.println(query);
        //使用增强for循环遍历数据
//        for (Object obj:query){
//            System.out.println(obj);
//        }

        //使用迭代器遍历数据
        Iterator<userBean> iterator = query.iterator();
        while (iterator.hasNext()){
            userBean next = iterator.next();
            System.out.println(next);
        }
        DbUtils.closeQuietly(conn);
    }

    /*
        MapHandler:是ResultSetHandler接口的实现类,对应表中的一条数据
        将字段及相应的字段的值作为map中的key和value
     */
    @Test
    public void selectTest3()throws Exception{
        Connection conn = Druid_JDBC.getDruidConnection();
        QueryRunner runner = new QueryRunner();
        String sql="select id,name,age,phone from user where id=?";
        MapHandler mapHandler = new MapHandler();
        Map<String, Object> query = runner.query(conn, sql, mapHandler, 3);
        System.out.println(query);

        DbUtils.closeQuietly(conn);
    }

    /*
    查询特殊数据的操作ScalarHandler()
     */
    @Test
    public void test4() throws Exception{
        Connection conn = Druid_JDBC.getDruidConnection();

        QueryRunner runner = new QueryRunner();

        String sql="select count(*) from user";

        ScalarHandler scalarHandler = new ScalarHandler();

        Long query = (Long) runner.query(conn, sql, scalarHandler);

        System.out.println(query);

        DbUtils.closeQuietly(conn);
    }

    @Test
    public void test5() throws Exception{
        Connection conn = Druid_JDBC.getDruidConnection();

        QueryRunner runner = new QueryRunner();

        String sql="select Max(age) from user";

        ScalarHandler scalarHandler = new ScalarHandler();

        Integer query =(Integer) runner.query(conn, sql, scalarHandler);

        System.out.println(query);

        DbUtils.closeQuietly(conn);
    }
}