Loading

JDBC和DBPool

JDBC

获取数据库连接

Driver接口实现类

Driver接口介绍

  • java.sql.Driver接口是所有的DBUtils驱动程序需要实现的接口。提供给不同的数据库厂商使用
  • 程序中不需要直接去访问实现了的Driver接口的类,而是有驱动程序管理器类(java.sql.DriverManager)去调用这些Driver实习
- Oracle的驱动:oracle.jdbc.driver.OracleDriver 
- mySql 的驱动:com.mysql.jdbc.Driver

加载与注册DBUtils驱动

  • 加载驱动:Class.forName("com.mysql.jdbc.Driver");

  • 注册驱动:DriverManager.registerDriver(com.mtsql.jdbc.Driver)

    • 通常不用显式调用 DriverManager 类的 registerDriver() 方法来注册驱动程序类的实例,因

      为 Driver 接口的驱动程序类包含了静态代码块,在这个静态代码块中,会调用

      DriverManager.registerDriver() 方法来注册自身的一个实例。

URL

  • URL的标准由三部分组成
    • jdbc:子协议:子名称
    • 协议:DBUtils URL中的协议总是jdbc
    • 子协议:用于标识一个数据库驱动
    • 子名称:用于定位数据库,包含主机名(对应服务器的ip地址)、端口号、数据库名
  • 常用的DBUtils URL
    • Mysql的连接URL编写方式:
      • jdbc:mysql://主机名称:mysql服务端口号/数据库名称
      • jdbc:mysql://localhost:3306/test
      • jdbc:mysql://localhost:3306/xinzhi?useUnicode=true&characterEncoding=utf8(如果程序与服务器端的字符集不一致,会导致乱码,那么可以通过参数指定服务器端的字符集)
      • 8.0后需要加上&useSSL=false&serverTimezone=UTC",MySQL在高版本需要指明是否进行SSL连(认证和加密),serverTimezone=Asia/Shanghai 使用UTC(世界统一时间)和中国的时间差八个小时
    • Oracle的连接URL编写方式:
      • jdbc:oracle:thin:@主机名称:oracle服务端口号:数据库名称
      • jdbc:oracle:thin:@localhost:1521:test
    • SQLServer的连接URL编写方式
      • jdbc:oracle:thin:@主机名称:sqlserver服务端口号:DatabaseName=数据库名称
      • jdba:sqlserver://localhost:1433:DatabaseName=test

用户名和密码

  • user,password可以用“属性名=属性值”方式告诉数据库
  • 可以调用DriverManager类的getConnection()方法建立到数据库的连接

数据库连接方式举例

数据库准备

create database test;
use test;
create table user(
	id int primary key auto_increment,
	username varchar(20),
	password varchar(20),
	nickname varchar(20)
);

INSERT INTO `USER` VALUES(null,'zs','123456','老张');
INSERT INTO `USER` VALUES(null,'ls','123456','老李');
INSERT INTO `USER` VALUES(null,'wangwu','123','东方不败');

连接数据库

/**
 * - 在java项目模块下,导入mysql驱动包
 * - 注册驱动
 * - 获得连接
 * - 创建执行sql语句对象
 * - 执行sql语句,处理结果
 * - 释放资源
 */
public class DemoConnection01 {
    public static void main(String[] args) throws SQLException, ClassNotFoundException {
        // 1.注册驱动(二选一,建议DriverManager)
        //Class.forName("com.mysql.jdbc.Driver");
        DriverManager.registerDriver(new Driver());

        // 2.获得连接
        String url = "jdbc:mysql://localhost:3306/test";
        String user = "root";
        String password = "root";
        Connection connection = DriverManager.getConnection(url, user, password);

        // 3.创建执行sql语句对象
        Statement statement = connection.createStatement();

        // 4.执行sql语句,处理结果
        String sql = "select * from user";

	    //接收结果集
        ResultSet resultSet = statement.executeQuery(sql);

        // 处理结果集
        while (resultSet.next()) {
            // 取数据
            System.out.println(resultSet.getObject("id"));
            System.out.println(resultSet.getObject("username"));
            System.out.println(resultSet.getObject("password"));
            System.out.println(resultSet.getObject("nickname"));
            System.out.println("--------------");
        }

        // 5.释放资源
        resultSet.close();
        statement.close();
        connection.close();
    }
}

JDBC API

image-20211022162030687

API-Drivermanager类

public static void registerDriver(Driver driver) ;注册驱动

com.mysql.jdbc.Driver类:
static {
	try {
		java.sql.DriverManager.registerDriver(new Driver());
	} catch (SQLException E) {
		throw new RuntimeException("Can't register driver!");
	}
}

翻阅源码发现,通过API的方式注册驱动,Driver会new两次,所有推荐这种写法:

Class.forName("com.mysql.jdbc.Driver");  // 当获取Driver类的字节码对象,就会加载Driver类,执行静态代码块,执行静态代码块就会注册驱动

public static Connection getConnection(String url, String user, String password) ;与数据库建立连接

// 1.注册驱动(二选一,建议DriverManager)
//Class.forName("com.mysql.jdbc.Driver");
DriverManager.registerDriver(new Driver());

// 2.获得连接
String url = "jdbc:mysql://localhost:3306/test";
String user = "root";
String password = "root";
Connection connection = DriverManager.getConnection(url, user, password);

API-Connection接口

  1. 概述

    ​ 接口的实现在数据库驱动中。所有与数据库交互都是基于连接对象的。

  2. 常用方法

Statement createStatement();创建执行sql语句对象
    
PreparedStatement prepareStatement(String sql) 预编译sql语句,返回预编译sql语句对象
PreparedStatement继承statement接口
    
void setAutoCommit(boolean autoCommit) false--手动开启事务(start transaction)
void commit();提交事务
void rollback();回滚事务

API-Statement接口

  1. 概述

    ​ 接口的实现在数据库驱动中. 用来操作sql语句(增删改查),并返回sql语句的结果

  2. 作用

    ResultSet executeQuery(String sql)**** 根据查询语句返回结果集。只能执行select语句。

    int executeUpdate(String sql) 根据执行的DML(insert update delete)语句,返回受影响的行数。

    boolean execute(String sql) 此方法可以执行任意sql语句。返回boolean值. 【了解】

    ​ true: 执行select语句

    ​ false: 执行insert, delete,update语句

API-ResultSet接口

  1. 作用: 用来封装查询后的结果集,表示一个结果集对象;

    提供一个游标,默认游标指向结果集第一行之前。

    调用一次next(),游标向下移动一行。

    提供一些get方法。

  2. ResultSet接口常用API

    • boolean next();将光标从当前位置向下移动一行
    • int getInt(int colIndex)以int形式获取ResultSet结果集当前行指定列号值
    • int getInt(String colLabel)以int形式获取ResultSet结果集当前行指定列名值
    • float getFloat(int colIndex)以float形式获取ResultSet结果集当前行指定列号值
    • float getFloat(String colLabel)以float形式获取ResultSet结果集当前行指定列名值
    • String getString(int colIndex)以String 形式获取ResultSet结果集当前行指定列号值
    • String getString(String colLabel)以String形式获取ResultSet结果集当前行指定列名值
    • Date getDate(int columnIndex); 以Date 形式获取ResultSet结果集当前行指定列号值
    • Date getDate(String columnName);以Date形式获取ResultSet结果集当前行指定列名值
    • Object getObject(String columnLabel)以Object形式获取ResultSet结果集当前行指定列名值
    • ...
    • void close()关闭ResultSet 对象

简写连接数据库

@Test
public void test2() throws Exception  {
    //1.数据库连接的4个基本要素
    String url = "jdbc:mysql://localhost:3308/test";
    String user = "root";
    String password = "asd";
    String driverName = "com.mysql.jdbc.Driver";

    //实例化Driver,加载驱动(可忽略)
    //        Class<?> clazz = Class.forName(driverName);
    //        Driver driver = (Driver) clazz.newInstance();

    //3.注册驱动(可忽略)
    //        DriverManager.registerDriver(driver);

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

将基本要素放入properties

mysql.username=root
mysql.password=asd
mysql.url=jdbc:mysql://localhost:3308/test?rewriteBatchedStatements=true
mysql.dirvername=com.mysql.jdbc.Driver
@Test
public void test4() throws Exception {
    InputStream is = com.ccl.jdbcTest.class.getClassLoader().getResourceAsStream("jdbc.properties");
    Properties properties = new Properties();
    properties.load(is);

    //        Properties properties = new Properties();
    //        properties.load(com.ccl.jdbcTest.class.getClassLoader().getResourceAsStream("jdbc-study/jdbc.properties"));
    String url = properties.getProperty("mysql.url");
    String user = properties.getProperty("mysql.username");
    String password = properties.getProperty("mysql.password");

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

}

将连接数据库的代码封装为一个工具类

public class jdbcUtil {
    public static void closeResourse(Connection conn, Statement ps, ResultSet resultSet){
        try {
            if (conn != null){
                conn.close();
            }
        }catch (SQLException e){
            e.printStackTrace();
        }

        try {
            if (ps != null){
                ps.close();
                System.out.println("Close");
            }
        }catch (SQLException e){
            e.printStackTrace();
        }
        
        try {
            if (resultSet != null){
                resultSet.close();
                System.out.println("Close");
            }
        }catch (SQLException e){
            e.printStackTrace();
        }
    }

    public static Connection getConnection() {
        Connection conn = null;
        try {
            InputStream is = jdbcTest.class.getClassLoader().getResourceAsStream("jdbc.properties");
            Properties properties = new Properties();
            properties.load(is);

            String url = properties.getProperty("mysql.url");
            String user = properties.getProperty("mysql.username");
            String password = properties.getProperty("mysql.password");

            //4.获取连接
            conn = DriverManager.getConnection(url, user, password);
        } catch (IOException | SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }
}

JDBC 事务

  • 管理事务的功能类:Connection接口

    • 开启事务:setAutoCommit(boolean autoCommit); 参数为false,则开启事务。
    • 提交事务:commit();
    • 回滚事务:rollback();
  • 案例:

    public class Test1_事务入门 {
        // 修改id为6的密码
        public static void main(String[] args) {
            Connection connection = null;
            PreparedStatement ps = null;
            try {
                // 1.注册驱动,获得连接
                connection = JDBCUtils.getConnection();
    
                // 2.开启事务
                connection.setAutoCommit(false);
    
                // 3.预编译sql语句,得到预编译对象
                String sql = "update user set password = ? where id = ?";
                ps = connection.prepareStatement(sql);
    
                // 4.设置参数
                ps.setString(1,"abcdef");
                ps.setInt(2,6);
    
                // 5.执行sql语句,处理结果
                int rows = ps.executeUpdate();
                System.out.println("受影响的行数:"+rows);
    
                // 发生异常
                int i = 1/0;
    
                // 6.没有异常提交事务
                connection.commit();
    
            } catch (Exception e) {
                // 7.有异常回滚事务
                try {
                    connection.rollback();
                } catch (SQLException e1) {
                    e1.printStackTrace();
                }
    
            } finally {
                // 8.释放资源
                JDBCUtils.release(null,ps,connection);
            }
    
        }
    }
    
    

转账案例

  • 案例的准备工作
create table account(
    id int primary key auto_increment,
    name varchar(20),
    money double
);

insert into account values (null,'zs',1000);
insert into account values (null,'ls',1000);
insert into account values (null,'ww',1000);

1.需求

​ zs给ls转100, 使用事务进行控制

2.分析

  • 1.注册驱动,获得连接
  • 2.开启事务
  • 3.预编译sql语句,得到预编译对象
  • 4.设置sql语句参数
  • 5.执行sql语句,处理结果
  • 6.提交事务或者回滚事务
  • 7.释放资源

3.实现

public class Test2_事务转账案例 {
    public static void main(String[] args)  {
        Connection connection = null;
        PreparedStatement ps1 = null;
        PreparedStatement ps2 = null;
        try {
            //- 1.注册驱动,获得连接
            connection = JDBCUtils.getConnection();

            //- 2.开启事务
            connection.setAutoCommit(false);

            //- 3.预编译sql语句,得到预编译对象
            String sql1 = "update account set money = money - ? where name = ?";
            String sql2 = "update account set money = money + ? where name = ?";
            ps1 = connection.prepareStatement(sql1);
            ps2 = connection.prepareStatement(sql2);

            //- 4.设置sql语句参数
            ps1.setDouble(1,100);
            ps1.setString(2,"zs");

            ps2.setDouble(1,100);
            ps2.setString(2,"ls");

            //- 5.执行sql语句,处理结果
            int rows1 = ps1.executeUpdate();
            int rows2 = ps2.executeUpdate();
            System.out.println("rows1:"+rows1);
            System.out.println("rows2:"+rows2);

            int i = 1/0;

            if (rows1 > 0  && rows2 > 0){
                //- 6.提交事务
                connection.commit();
            } else{
                //- 6.回滚事务
                try {
                    connection.rollback();
                } catch (SQLException e1) {
                    e1.printStackTrace();
                }
            }

        } catch (Exception e) {
            //- 6.回滚事务
            try {
                connection.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }

        } finally {
            //- 7.释放资源
            JDBCUtils.release(null,ps1,connection);
            JDBCUtils.release(null,ps2,null);
        }

    }
}

DBPool

C3P0

硬编码使用

  • 思路:

    • 创建C3P0连接池对象
    • 设置连接池参数
    • 获得连接
    • 预编译sql语句,得到预编译对象
    • 设置sql语句参数
    • 执行sql语句,处理结果
    • 释放资源
import TheConnection.JDBCUtils;
import TheConnection.User;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.junit.Test;

import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

@Test
public void test01() throws PropertyVetoException, SQLException {
        //- 创建C3P0连接池对象
        ComboPooledDataSource dataSource = new ComboPooledDataSource();

        //- 设置连接池参数
        dataSource.setDriverClass("com.mysql.jdbc.Driver");
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/day19_1");
        dataSource.setUser("root");
        dataSource.setPassword("root");
        dataSource.setInitialPoolSize(5);

        //- 获得连接
        Connection connection = dataSource.getConnection();

        // 预编译sql语句,得到预编译对象
        String sql = "select * from user where id = ?";
        PreparedStatement ps = connection.prepareStatement(sql);

        // 设置参数
        ps.setInt(1, 7);

        // 执行sql语句,处理结果
        ResultSet resultSet = ps.executeQuery();
        // 定义User变量
        User user = null;
        while (resultSet.next()) {
            // 创建User对象
            user = new User();
            // 取值,赋值
            user.setId(resultSet.getInt("id"));
            user.setUsername(resultSet.getString("username"));
            user.setPassword(resultSet.getString("password"));
            user.setNickname(resultSet.getString("nickname"));
        }

        // 释放资源
        JDBCUtils.release(resultSet,ps,connection);
        System.out.println(user);
    }
}

通过配置文件使用

  • 思路:

    • 拷贝c3p0-config.xml配置文件到src路径下,然后修改配置文件中的参数值
      • 配置文件名一定不能修改
      • 配置文件一定要放在src路径下
      • 配置文件中标签的name属性值要与setXXX方法的方法名对应( set方法去掉set,然后首字母变小写)
    • 创建C3P0连接池对象------>自动读取src路径下的c3p0-config.xml配置文件
    • 通过连接池对象获得连接对象
    • 预编译sql语句,得到预编译对象
    • 设置参数
    • 执行sql语句,处理结果
    • 释放资源
import TheConnection.JDBCUtils;
import TheConnection.User;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.junit.Test;

import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

@Test
public void test02() throws SQLException, InterruptedException {
// 创建C3P0连接池对象
    ComboPooledDataSource dataSource = new ComboPooledDataSource();

    // 获取连接
    Connection connection = dataSource.getConnection();

    // 预编译sql语句,得到预编译对象
    String sql = "select * from user where id = ?";
    PreparedStatement ps = connection.prepareStatement(sql);

    // 设置参数
    ps.setInt(1, 7);

    // 执行sql语句,处理结果
    ResultSet resultSet = ps.executeQuery();
    // 定义User变量
    User user = null;
    while (resultSet.next()) {
        // 创建User对象
        user = new User();
        // 取值,赋值
        user.setId(resultSet.getInt("id"));
        user.setUsername(resultSet.getString("username"));
        user.setPassword(resultSet.getString("password"));
        user.setNickname(resultSet.getString("nickname"));
    }

    System.out.println("正在使用的:"+dataSource.getNumBusyConnections());// 正在使用连接数
    System.out.println("正在空闲的:"+dataSource.getNumIdleConnections());// 空闲连接数
    System.out.println("总的连接数:"+dataSource.getNumConnections());// 总连接数

    // 释放资源
    JDBCUtils.release(resultSet,ps,connection);
    System.out.println(user);

    Thread.sleep(5000);
    System.out.println("正在使用的:"+dataSource.getNumBusyConnections());// 正在使用连接数
    System.out.println("正在空闲的:"+dataSource.getNumIdleConnections());// 空闲连接数
    System.out.println("总的连接数:"+dataSource.getNumConnections());// 总连接数
}

c3p0-config.xml

<c3p0-config>
    <default-config>
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/day18</property>
        <property name="user">root</property>
        <property name="password">Caichuanliang001</property>
        <property name="initialPoolSize">5</property>
    </default-config>
</c3p0-config>

使用C3P0改写工具类

  • 问题: 每次需要连接的时候,都需要创建连接池对象,用完了就销毁,所以就会不断的创建连接池,销毁连接池

  • 解决: 整个程序只需要创建一个连接池对象,其余地方直接使用这个唯一的连接池对象获得连接即可

  • 工具类:

    • 思路:

      • 创建唯一的连接池对象---->private static final修饰
      • 提供一个获取连接池对象的静态方法
      • 提供一个获取连接的静态方法
      • 提供一个释放资源的静态方法
@Test
public void test03() throws SQLException, InterruptedException {
	// 获得连接
    Connection connection = C3P0Utils.getConnection();

    // 预编译sql语句,得到预编译对象
    String sql = "select * from user where id = ?";
    PreparedStatement ps = connection.prepareStatement(sql);

    // 设置参数
    ps.setInt(1, 7);

    // 执行sql语句,处理结果
    ResultSet resultSet = ps.executeQuery();
    // 定义User变量
    User user = null;
    while (resultSet.next()) {
        // 创建User对象
        user = new User();
        // 取值,赋值
        user.setId(resultSet.getInt("id"));
        user.setUsername(resultSet.getString("username"));
        user.setPassword(resultSet.getString("password"));
        user.setNickname(resultSet.getString("nickname"));
    }

    // 释放资源
    JDBCUtils.release(resultSet, ps, connection);
    System.out.println(user);
}
import com.mchange.v2.c3p0.ComboPooledDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * @Author:pengzhilin
 * @Date: 2021/4/28 11:18
 */
public class C3P0Utils {
    // 定义为一个私有静态的连接池常量
    private static final ComboPooledDataSource DATA_SOURCE = new ComboPooledDataSource();

    // 提供一个公共的静态方法获得连接池
    public static DataSource getDataSource(){
        return DATA_SOURCE;
    }

    // 提供一个公共的静态方法获得连接
    public static Connection getConnection() throws SQLException {
        return DATA_SOURCE.getConnection();
    }

    // 提供一个公共的静态方法是否资源
    /**
     * 释放资源
     *
     * @param resultSet
     * @param statement
     * @param connection
     */
    public static void release(ResultSet resultSet, Statement statement, Connection connection) {
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        
        if (connection != null) {
            try {
            connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

Druid

通过硬编码方式

  • 思路:

    • 创建Druid连接池对象
    • 设置连接池的配置参数
    • 通过连接池获得连接
    • 预编译sql语句,得到预编译对象
    • 设置sql语句参数
    • 执行sql语句,处理结果
    • 释放资源
@Test
public void test01() throws SQLException {
    //- 创建Druid连接池对象
    DruidDataSource dataSource = new DruidDataSource();

    //- 设置连接池的配置参数
    dataSource.setDriverClassName("com.mysql.jdbc.Driver");
    dataSource.setUrl("jdbc:mysql://localhost:3306/day19_1");
    dataSource.setUsername("root");
    dataSource.setPassword("root");
    dataSource.setInitialSize(5);

    //- 通过连接池获得连接
    DruidPooledConnection connection = dataSource.getConnection();

    // 预编译sql语句,得到预编译对象
    String sql = "select * from user where id = ?";
    PreparedStatement ps = connection.prepareStatement(sql);

    // 设置参数
    ps.setInt(1, 7);

    // 执行sql语句,处理结果
    ResultSet resultSet = ps.executeQuery();
    // 定义User变量
    User user = null;
    while (resultSet.next()) {
        // 创建User对象
        user = new User();
        // 取值,赋值
        user.setId(resultSet.getInt("id"));
        user.setUsername(resultSet.getString("username"));
        user.setPassword(resultSet.getString("password"));
        user.setNickname(resultSet.getString("nickname"));
    }

    // 释放资源
    JDBCUtils.release(resultSet,ps,connection);
    System.out.println(user);
}

通过配置文件来使用

  • 思路:

    • 导入Druid的jar包
    • 拷贝druid.properties配置文件到src路径下
      • 配置文件名可以修改
      • 配置文件建议放在src路径下
      • 配置文件中键名与setXXX方法的方法名对应( set方法去掉set,然后首字母变小写)
    • 使用:
      • 创建Properties对象,加载配置文件中的数据
      • 创建Druid连接池对象,传入Properties对象--->不会自动读src路径下的配置文件
      • 通过连接池获得连接
      • 预编译sql语句,得到预编译对象
      • 设置sql语句参数
      • 执行slq语句,处理结果
      • 释放资源
@Test
public void test02() throws Exception {
    //- 创建Properties对象,加载配置文件中的数据
    Properties pro = new Properties();
    InputStream is = Test2_配置文件.class.getClassLoader().getResourceAsStream("druid.properties");
    pro.load(is);

    //- 创建Druid连接池对象,传入Properties对象--->不会自动读src路径下的配置文件
    DataSource dataSource = DruidDataSourceFactory.createDataSource(pro);

    //- 通过连接池获得连接
    Connection connection = dataSource.getConnection();

    // 预编译sql语句,得到预编译对象
    String sql = "select * from user where id = ?";
    PreparedStatement ps = connection.prepareStatement(sql);

    // 设置参数
    ps.setInt(1, 7);

    // 执行sql语句,处理结果
    ResultSet resultSet = ps.executeQuery();
    // 定义User变量
    User user = null;
    while (resultSet.next()) {
        // 创建User对象
        user = new User();
        // 取值,赋值
        user.setId(resultSet.getInt("id"));
        user.setUsername(resultSet.getString("username"));
        user.setPassword(resultSet.getString("password"));
        user.setNickname(resultSet.getString("nickname"));
    }

    // 释放资源
    JDBCUtils.release(resultSet,ps,connection);
    System.out.println(user);
}

druid.properties

# 数据库连接参数
url=jdbc:mysql://localhost:3306/day18
username=root
password=Caichuanliang001
driverClassName=com.mysql.jdbc.Driver
# 连接池的参数
initialSize=10
maxActive=10
maxWait=2000

Druid工具类的制作

  • 步骤:
    • 0.定义一个DataSource成员变量
    • 1.在静态代码块中,加载配置文件,创建Druid连接池对象
    • 2.提供一个公共的静态方法获得连接池
    • 3.提供一个公共的静态方法获得连接
    • 4.提供一个公共的静态方法是否资源
@Test
public void test03() throws SQLException {
    DataSource dataSource = DruidUtils.getDataSource();

    Connection connection = dataSource.getConnection();
    String sql = "select * from user where id = ?";
    PreparedStatement ps = connection.prepareStatement(sql);
    ps.setInt(1, 1);
    ResultSet resultSet = ps.executeQuery();


    User user = null;
    while (resultSet.next()) {
        // 创建User对象
        user = new User();
        // 取值,赋值
        user.setId(resultSet.getInt("id"));
        user.setUsername(resultSet.getString("username"));
        user.setPassword(resultSet.getString("password"));
        user.setNickname(resultSet.getString("nickname"));
    }


    DruidUtils.release(resultSet, ps, connection);
    System.out.println(user);
}
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.ConnectionEvent;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class DruidUtils {
    // - 0.定义一个DataSource成员变量
    private static DataSource dataSource;

    // - 1.在静态代码块中,加载配置文件,创建Druid连接池对象
    static {
        try {
            //- 创建Properties对象,加载配置文件中的数据
            Properties pro = new Properties();
            InputStream is = DruidUtils.class.getClassLoader().getResourceAsStream("druid.properties");
            pro.load(is);

            //- 创建Druid连接池对象,传入Properties对象--->不会自动读src路径下的配置文件
            dataSource = DruidDataSourceFactory.createDataSource(pro);

        } catch (Exception e) {

        }
    }

    // - 2.提供一个公共的静态方法获得连接池
    public static DataSource getDataSource() {
        return dataSource;
    }

    // - 3.提供一个公共的静态方法获得连接
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    // - 4.提供一个公共的静态方法是否资源
    // 提供一个公共的静态方法是否资源

    /**
     * 释放资源
     *
     * @param resultSet
     * @param statement
     * @param connection
     */
    public static void release(ResultSet resultSet, Statement statement, Connection connection) {
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

DBUtils

DBUtils的介绍

DBUtils的概述

​ DbUtils是Apache组织提供的一个对JDBC进行简单封装的开源工具类库,使用它能够简化JDBC应用程序的开发,同时也不会影响程序的性能

DBUtils的常用API介绍

  1. 创建QueryRunner对象的API

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

  2. QueryRunner执行增删改的SQL语句的API

    int update(String sql, Object... params), params参数就是可变参数,参数个数取决于语句中问号的个数

    • eg参数1: update user set password = ? where username = ?

    • eg参数2: "123456","zs"

  3. 执行查询的SQL语句的API

    query(String sql, ResultSetHandler<T> rsh, Object... params),其中ResultSetHandler是一个接口,表示结果集处理者

    • eg参数1: select * from user where username = ? and password = ?
    • eg参数2: 指定查询结果封装的类型
    • eg参数3: zs , 123456

DBUtils完成增删改

  • 实现步骤:

    • 导入DButils的jar包---->mysql驱动包,第三方数据库连接池的jar包,配置文件,工具类
    • 创建QueryRunner对象,传入连接池对象
    • 调用update方法执行sql语句
@Test
public void insert() throws Exception{
    // 1.创建QueryRunner对象,传入连接池
    QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());

    // 2.调用update方法执行sql语句
    int rows = qr.update("insert into user values(null,?,?,?)", "zl", "123456", "老赵");
    System.out.println("rows:" + rows);
}
@Test
public void update() throws Exception{
    // 1.创建QueryRunner对象,传入连接池
    QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());

    // 2.调用update方法执行sql语句
    int rows = qr.update("update user set password = ? where id = ?", "abcdef",8);
    System.out.println("rows:" + rows);
}
@Test
public void delete() throws Exception{
    // 1.创建QueryRunner对象,传入连接池
    QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());

    // 2.调用update方法执行sql语句
    int rows = qr.update("delete from user where id = ?", 8);
    System.out.println("rows:" + rows);
}

JavaBean

  1. JavaBean说白了就是一个类, 用来封装数据用的

  2. JavaBean要求

    • 私有字\成员变量
    • 提供公共的get/set方法
    • 无参构造
    • 建议满参构造
    • 实现Serializable
  3. 字段(成员变量)和属性

    • 字段: 成员变量 eg: private String username;
    • 属性: set\get方法去掉get或者set首字母变小写 eg: setUsername()方法-去掉set->Username-->首字母变小写->username

    一般情况下,我们通过IDEA直接生成的set/get 习惯把字段和属性搞成一样而言

  4. 注意:

    • 使用DBUtils查询得到的结果可以自动封装成员一个对象,但有一个前提条件就是该对象所属的类的属性名必须和表中的字段名一致,否则封装失败
    • 也就是说: 类的set\get方法去掉set\get,然后首字母变小写之后得到的名称,必须和表中的列名一致
    • 学习完DBUtils完成查询操作后,进行测试
public class User implements Serializable {
    private Integer id;
    private String username;
    private String password;
    private String nickname;

    public User(Integer id, String username, String password, String nickname) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.nickname = nickname;
    }

    public User() {
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer 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;
    }

    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }

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

使用DBUtils完成查询

ResultSetHandler结果集处理接口的实现类介绍

ArrayHandler: 适合封装查询结果为一条记录,会把这条记录中每个字段的值封装到Object[]数组中
ArrayListHandler:适合封装查询结果为多条记录,会把每条记录中的值封装到一个数组中,再把这些数组存储到List集合
BeanHandler:适合封装查询结果为一条记录的,把这条记录的数据封装到一个指定的对象中
BeanListHandler:适合封装查询结果为多条记录,会把每条记录中的值封装到一个对象中,再把这些对象存储到List集合
ColunmListHandler:适合封装查询结果为单列多行的,会把当前列中所有的值存储到List集合
KeyedHandler:适合封装查询结果为多条记录的,会把每一条记录封装成一个Map集合,再把Map集合存储到另一个Map集合中
MapHandler: 适合封装查询结果为一条记录的,会把这条记录中每个字段的值封装到Map集合中
MapListHandler:适合封装查询结果为多条记录,会把每条记录中的值封装到一个Map集合中,再把这些Map集合存储到List集合    
ScalarHandler:适合查询结果为单个值的   

ArrayHandler: 适合封装查询结果为一条记录,会把这条记录中每个字段的值封装到Object[]数组中

//ArrayHandler: 适合封装查询结果为一条记录,会把这条记录中每个字段的值封装到Object[]数组中
@Test
public void test01() throws SQLException {
    QueryRunner qr = new QueryRunner(DruidUtils.getDataSource());

    String sql = "select * from user where id = ?";
    Object[] arr = qr.query(sql, new ArrayHandler(), 2);
    System.out.println(Arrays.toString(arr)); //[2, ls, 123456, 老李]
}

ArrayListHandler:适合封装查询结果为多条记录,会把每条记录中的值封装到一个数组中,再把这些数组存储到List集合

//ArrayListHandler:适合封装查询结果为多条记录,会把每条记录中的值封装到一个数组中,再把这些数组存储到List集合
@Test
public void test04() throws SQLException {
    QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
    String sql = "select * from user";
    List<Object[]> query = qr.query(sql, new ArrayListHandler());
    for (Object[] objects : query) {
        System.out.println(Arrays.toString(objects));
        /**
             * [2, ls, 123456, 老李]
             * [3, test, 123, test1]
             * [4, zl, 123456, 赵六]
             * [5, wangwu, sadsad, 王五]
             * [6, zl, 123456, 老赵]
             * [7, zl, 123456, 老赵]
             * [8, zl, 123456, 老赵]
             * [9, zl, 123456, 老赵]
             * [10, zl, 123456, 老赵]
             */
    }
}

BeanHandler:适合封装查询结果为一条记录的,把这条记录的数据封装到一个指定的对象中

//BeanHandler:适合封装查询结果为一条记录的,把这条记录的数据封装到一个指定的对象中
@Test
public void test02() throws SQLException {
    QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
    String s = "select * from user where id = ?";
    User query = queryRunner.query(s, new BeanHandler<User>(User.class), 2);
    System.out.println(query); //User{id=2, username='ls', password='123456', nickname='老李'}
}

BenListHandler:适合封装查询结果为多条记录,会把每条记录中的值封装到一个对象中,再把这些对象存储到List集合

//BeanListHandler:适合封装查询结果为多条记录,会把每条记录中的值封装到一个对象中,再把这些对象存储到List集合
@Test
public void test05() throws SQLException {
    QueryRunner qr = new QueryRunner(DruidUtils.getDataSource());
    String sql = "select * from user";
    List<User> users = qr.query(sql, new BeanListHandler<User>(User.class));
    for (User user : users) {
        System.out.println(user);
        /**
             * User{id=2, username='ls', password='123456', nickname='老李'}
             * User{id=3, username='test', password='123', nickname='test1'}
             * User{id=4, username='zl', password='123456', nickname='赵六'}
             * User{id=5, username='wangwu', password='sadsad', nickname='王五'}
             * User{id=6, username='zl', password='123456', nickname='老赵'}
             * User{id=7, username='zl', password='123456', nickname='老赵'}
             * User{id=8, username='zl', password='123456', nickname='老赵'}
             * User{id=9, username='zl', password='123456', nickname='老赵'}
             * User{id=10, username='zl', password='123456', nickname='老赵'}
             */
    }
}

ColunmListHandler:适合封装查询结果为单列多行的,会把当前列中所有的值存储到List集合

//ColumnListHandler:适合封装查询结果为单列多行的,会把当前列中所有的值存储到List集合
@Test
public void test08() throws SQLException {
    QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
    String sql = "select username from user";
    List<Object> list = qr.query(sql, new ColumnListHandler());
    System.out.println(list); //[ls, test, zl, wangwu, zl, zl, zl, zl, zl]

}

KeyedHandler:适合封装查询结果为多条记录的,会把每一条记录封装成一个Map集合,再把Map集合存储到另一个Map集合中

//KeyedHandler:适合封装查询结果为多条记录的,会把每一条记录封装成一个Map集合,再把Map集合存储到另一个Map集合中
@Test
public void test09() throws SQLException {
    QueryRunner qr = new QueryRunner(DruidUtils.getDataSource());
    String sql = "select * from user";
    Map<Object, Map<String, Object>> allId = qr.query(sql, new KeyedHandler("id"));
    Set<Object> idArr = allId.keySet();
    for (Object id : idArr) {
        System.out.print(id + ":");
        System.out.println(allId.get(id));
        /**
             * 2:{password=123456, nickname=老李, id=2, username=ls}
             * 3:{password=123, nickname=test1, id=3, username=test}
             * 4:{password=123456, nickname=赵六, id=4, username=zl}
             * 5:{password=sadsad, nickname=王五, id=5, username=wangwu}
             * 6:{password=123456, nickname=老赵, id=6, username=zl}
             * 7:{password=123456, nickname=老赵, id=7, username=zl}
             * 8:{password=123456, nickname=老赵, id=8, username=zl}
             * 9:{password=123456, nickname=老赵, id=9, username=zl}
             * 10:{password=123456, nickname=老赵, id=10, username=zl}
             */
    }
}

MapHandler: 适合封装查询结果为一条记录的,会把这条记录中每个字段的值封装到Map集合中

//MapHandler: 适合封装查询结果为一条记录的,会把这条记录中每个字段的值封装到Map集合中
@Test
public void test03() throws SQLException {
    QueryRunner qr = new QueryRunner(DruidUtils.getDataSource());
    String sql = "select * from user where id = ?";
    Map<String, Object> query = qr.query(sql, new MapHandler(), 2);
    System.out.println(query); //{password=123456, nickname=老李, id=2, username=ls}
}

MapListHandler:适合封装查询结果为多条记录,会把每条记录中的值封装到一个Map集合中,再把这些Map集合存储到List集合

//MapListHandler:适合封装查询结果为多条记录,会把每条记录中的值封装到一个Map集合中,再把这些Map集合存储到List集合
@Test
public void test06() throws SQLException {
    QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
    String sql = "select * from user";
    List<Map<String, Object>> list = qr.query(sql, new MapListHandler());
    for (Map<String, Object> stringObjectMap : list) {
        System.out.println(stringObjectMap);
        /**
             * {password=123456, nickname=老李, id=2, username=ls}
             * {password=123, nickname=test1, id=3, username=test}
             * {password=123456, nickname=赵六, id=4, username=zl}
             * {password=sadsad, nickname=王五, id=5, username=wangwu}
             * {password=123456, nickname=老赵, id=6, username=zl}
             * {password=123456, nickname=老赵, id=7, username=zl}
             * {password=123456, nickname=老赵, id=8, username=zl}
             * {password=123456, nickname=老赵, id=9, username=zl}
             * {password=123456, nickname=老赵, id=10, username=zl}
             */
    }
}

ScalrHandler:适合查询结果为单个值的

//ScalarHandler:适合查询结果为单个值的
@Test
public void test07() throws SQLException {
    QueryRunner qr = new QueryRunner(DruidUtils.getDataSource());
    String sql = "select count(*) from user";
    Object query = qr.query(sql, new ScalarHandler());
    System.out.println(query); //9
    /*long count = (long) qr.query(sql, new ScalarHandler());
        System.out.println(count);
        long user = (long) qr.query(sql, new ScalarHandler());
        System.out.println(user);*/

}
posted @ 2021-10-22 18:31  yonugleesin  阅读(70)  评论(0编辑  收藏  举报