JAVA WEB DAY 11_ JDBC & 连接池

这篇博客详细介绍了JDBC的基本操作,包括注册驱动、获取连接、使用Statement和PreparedStatement执行SQL,以及ResultSet的使用。此外,还深入探讨了事务处理,并通过实例展示了C3P0和DRUID两种连接池的配置与使用。最后,提供了JDBC工具类的创建,旨在简化数据库操作。
摘要由CSDN通过智能技术生成

JDBC & 连接池

目标

  • 能够理解JDBC的概念
  • 能够使用Connection接口
  • 能够使用Statement接口
  • 能够使用ResultSet接口
  • 能够使用JDBC实现对单表数据增、删、改、查
  • 能够使用JDBC操作事务
  • 能够完成JDBC实现登录案例
  • 能够使用C3P0连接池
  • 能够使用DRUID连接池
  • 能够编写连接池工具类

01_ JDBC 概述-[★★]

  1. JDBC 是什么:
    英文:Java DataBase Connectivity
    中午:Java 数据库连接技术

  2. JDBC 的作用:
    与数据库建立连接并对数据库执行操作:增删改查操作

  3. JDBC 的组成:
    由一组官方定义的接口(规范)组成:接口实现类由数据库厂商提供:数据库驱动(实现操作数据库接口的类)

  4. JDBC 的好处:
    代码不依赖于任何的数据库
    只需要修改少量配置就可以方便切换到其他厂商数据库

02_ JDBC 核心 API 概述-[★★]

JDBC 核心类和接口说明
DriveManager 工具类1. 用于注册数据库驱动
2.用于获取连接对象
Connection 接口连接对象
与数据库建立连接并形成数据传输通道
Statement 接口SQL 语句发送对象
作用:将 SQL 语句发送给数据库执行并获得执行结果
ResultSet 接口结果集对象
作用:用来封装满足查询条件的记录信息
Drive 接口数据库驱动对象

03_ JDBC 之注册驱动-[★★★]

  • 注册驱动的作用:告诉JVM接下来要操作哪个厂商的数据库了
注册驱动方法说明
static registerDriver(Driver driver)驱动会注册两次
Class.forName(“com.mysql.jdbc.Driver”);只会注册一次
  • 示例代码
/**
  目标:
     1. 理解注册驱动的作用:告诉JVM接下来要操作哪个厂商的数据库了
     2. 掌握注册驱动的方式
     
    DriverManger工具类与注册驱动相关的方法
        * static registerDriver(Driver driver)
        * 注册数据库驱动
        * 存在问题:驱动会被注册两次
 */
public class Demo01 {
    public static void main(String[] args) throws Exception{
        // 方式1:存在问题:驱动会被注册两次
        // 创建驱动对象(Driver是mysql厂商提供Driver接口的实现类)
        /*Driver driver = new Driver();
        // 注册驱动
        DriverManager.registerDriver(driver);*/

        // 方式二:利用反射触发Driver实现类的加载实现驱动注册
        Class.forName("com.mysql.jdbc.Driver");
    }
}

04_ JDBC 之获取连接对象-[★★★]

  • DriverManager类与数据库建立连接的方法
DriverManager类与数据库建立连接的方法说明
static Connection getConnetion(
String url,
String username,
String password)
获得连接对象
url:连接字符串
username:用户名
password:密码
static Connection getConnection(
String url, Properties info)
获得连接对象

DriverManager工具类与获得连接对象相关的方法

  • static Connection getConnection(String url, String user, String password)
      与数据库建立连接并返回连接对象
      url: 数据库连接字符串
      user: 用户名 root
      password: 密码 root

  • static Connection getConnection(String url, Properties info)
      与数据库建立连接并返回连接对象
      url: 数据库连接字符串
      info: 属性集合(双列集合,用法和map一样):用来存储用户名和密码
       可以将用户名和密码配置在文件中

数据库连接字符串格式:

  • 完整格式:JDBC协议:子协议://数据库服务器地址:端口号/数据库名
    * JDBC协议:固定值是:jdbc
    * 子协议:一般是数据库厂商的名字,比如mysql或oracle
  • 省略格式:JDBC协议:子协议:/// 数据库名
    * 前提条件:操作本机数据库且端口号是默认值3306

MySQL数据库连接字符串完整格式:jdbc:mysql://localhost:3306/day11
MySQL数据库连接字符串省略格式:jdbc:mysql:///day11

  • 示例代码
/**
   目标:与数据库建立连接并获得Connection对象
 */
public class Demo01 {
    public static void main(String[] args) throws Exception{
        // 方式1: 获得连接对象
        // test01();

        // 方式2:获得连接对象
        test02();

    }

    /**
     * 获得连接对象
     */
    private static void test02() throws Exception {
        // 1. 注册驱动
        Class.forName("com.mysql.jdbc.Driver");
        // 2. 创建属性集对象
        // 键和值都是String类型
        Properties info = new Properties();
        // 创建输入流关联配置文件
        InputStream in = Demo01.class.getResourceAsStream("/jdbc.properties");
        // 从文件中加载数据到集合中
        info.load(in);
        System.out.println(info);// {user=root, password=root}
        /*info.setProperty("user", "root");
        info.setProperty("password", "root");*/

        // 2. 获得连接对象
        Connection conn = DriverManager.getConnection("jdbc:mysql:///day11", info);
        System.out.println(conn);
    }

    /**
     *  获得连接对象
     */
    private static void test01() throws Exception{
        // 1. 注册驱动
        Class.forName("com.mysql.jdbc.Driver");
        // 2. 获得连接对象
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day11", "root", "root");
        System.out.println(conn);
    }
}

05_ JDBC 之 Statement 对象概述-[★★★]

  • Statement 对象的作用:将 SQL 语句发送给数据库执行并获取结果

  • 如何获得 Statement 对象:通过连接对象的方法获得:Statement createStatement();

Statement对象常用方法说明
boolean execute(String sql)可以执行任意SQL语句
一般用来执行DDL语句:创库或创表
int executeUpdate(String sql)用于执行增删改语句:返回影响的行数
只要不是查询都称为更新操作
ResultSet executeQuery(String sql)用于执行查询语句

06_ JDBC 之执行 DDL 语句_创建表-[★★★]

使用JDBC在数据库创建数据表的步骤

  1. 注册驱动:Class.forName("驱动类全名字符串");
  2. 获得连接对象:Connection conn = DriverManger.getConnection("连接字符串","用户名","密码");
  3. 获得SQL语句发送对象:Statement stmt = conn.createStatement();
  4. 准备SQL语句:String sql="....";
  5. 调用SQL语句发送对象的方法:stmt.execute...(sql);
  6. 关闭连接释放资源
  • 示例代码
/**
    目标:使用JDBC在MySQL的数据库中创建一张学生表
     1)	id 是主键,整数类型,自增长
     2)	name 是varchar(20),非空
     3)	性别 是char类型
     4)	生日 是date类型
 */
public class Demo01 {
    public static void main(String[] args) throws Exception{
        // 1. 注册驱动
        Class.forName("com.mysql.jdbc.Driver");
        // 2. 获得连接对象
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day11", "root", "root");
        // 3. 获得SQL语句发送对象
        Statement stmt = conn.createStatement();
        // 4. 准备SQL语句
        String sql = "create table student(" +
                "id int primary key auto_increment," +
                "name varchar(20) not null," +
                "gender char(1)," +
                "birthday date);";
        // 5. 调用发送对象的方法执行SQL
        stmt.execute(sql);
        // 6. 释放资源
        stmt.close();
        conn.close();
    }
}

07_JDBC 之执行 DML 语句_增删改-[★★★]

使用JDBC在数据库创建数据表的步骤

  1. 注册驱动:Class.forName("驱动类全名字符串");
  2. 获得连接对象:Connection conn = DriverManger.getConnection("连接字符串","用户名","密码");
  3. 获得SQL语句发送对象:Statement stmt = conn.createStatement();
  4. 准备SQL语句:String sql="....";
  5. 调用SQL语句发送对象的方法:stmt.execute...(sql);
  6. 关闭连接释放资源
  • 示例代码
/**
  目标:使用JDBC实现增删改功能
 */
public class Demo01 {
    public static void main(String[] args) throws Exception{
        // 插入数据
        // testInsert();

        // 更新数据
        // testUpdate();

        // 删除数据
        testDelete();
    }


    // 插入数据
    public static void testInsert()throws Exception{
        // 1. 注册驱动
        Class.forName("com.mysql.jdbc.Driver");
        // 2. 获得连接对象
        Connection conn = DriverManager.getConnection("jdbc:mysql:///day11", "root", "root");
        // 3. 获得SQL语句发送对象
        Statement stmt = conn.createStatement();
        // 4. 准备SQL语句
        String sql = "insert into student values(null,'rose','女','2000-12-20'),(null,'luck','男','1990-02-21');";
        // 5. 调用SQL语句发送对象的方法
        int row = stmt.executeUpdate(sql);
        System.out.println("row = " + row);
        // 6. 关闭连接释放资源
        stmt.close();
        conn.close();
    }

    // 修改数据:将id为3的学生性别修改为女,姓名修改为:lily
    public static void testUpdate()throws Exception{
        // 1. 注册驱动
        Class.forName("com.mysql.jdbc.Driver");
        // 2. 获得连接对象
        Connection conn = DriverManager.getConnection("jdbc:mysql:///day11", "root", "root");
        // 3. 获得SQL语句发送对象
        Statement stmt = conn.createStatement();
        // 4. 准备SQL语句
        String sql = "update student set gender = '女', name='lily' where id = 3;";
        // 5. 调用SQL语句发送对象的方法
        int row = stmt.executeUpdate(sql);
        System.out.println("row = " + row); // 1
        // 6. 关闭连接释放资源
        stmt.close();
        conn.close();
    }

    // 删除数据:把id为2的学生删除
    public static void testDelete() throws Exception{
        // 1. 注册驱动
        Class.forName("com.mysql.jdbc.Driver");
        // 2. 获得连接对象
        Connection conn = DriverManager.getConnection("jdbc:mysql:///day11", "root", "root");
        // 3. 获得SQL语句发送对象
        Statement stmt = conn.createStatement();
        // 4. 准备SQL语句
        String sql = "delete from student where id = 2";
        // 5. 调用SQL语句发送对象的方法
        int row = stmt.executeUpdate(sql);
        System.out.println("row = " + row); // 1
        // 6. 关闭连接释放资源
        stmt.close();
        conn.close();
    }
}

08_ JDBC 之 ResultSet 对象概述-[★★★]

  • ResultSet对象的作用:封装满足查询条件的记录信息
  • 如何获得ResultSet对象:通过Statement对象的方法获取:ResultSet executeQuery(String sql)
ResultSet对象常用方法说明
boolean next()将指针下移一行并判断当前位置是否有记录
有则返回true,否则返回false
Xxx getXxx(列号或列名)根据列号或列名获得当前行指定列的数据

09_ JDBC 之执行 DQL 语句_查询数据-[★★★]

  • 注意事项:
  1. 当指针执行结果集的第一行之前,调用了getXxx方法获取数据则会出现下面异常:
    java.sql.SQLException: Before start of result set
  2. 当指针执行结果集的最后一行之后,调用了getXxx方法获取数据则会出现下面异常:
    java.sql.SQLException: After end of result set
  • 需求:查询所有学生信息并输出到控制台
/**
  目标:使用JDBC实现查询功能
*/
public class Demo01 {
    public static void main(String[] args) throws Exception {
        // 1. 注册驱动
        Class.forName("com.mysql.jdbc.Driver");
        // 2. 获得连接对象
        Connection conn = DriverManager.getConnection("jdbc:mysql:///day11", "root", "root");
        // 3. 获得SQL语句发送对象
        Statement stmt = conn.createStatement();
        // 4. 准备SQL语句
        String sql = "select * from  student";
        // 5. 执行SQL语句并获得结果集对象
        ResultSet rs = stmt.executeQuery(sql);

        // 循环获取每一行数据
        // 将指针下移一行、
        while(rs.next()){
            // 根据列号获取每一列的值
           /* int id = rs.getInt(1);
            String name = rs.getString(2);
            String gender = rs.getString(3);
            String birthday = rs.getString(4);*/

            // 根据列名获取每一列的值
            int id = rs.getInt("id");
            String name = rs.getString("name");
            String gender = rs.getString("gender");
            Date birthday = rs.getDate("birthday");

            System.out.println(id+","+name+","+gender+"," + birthday);
        }

        // 6. 关闭连接释放资源
        rs.close();
        stmt.close();
        conn.close();
    }
}

10_ JDBC 事务-转账案例-[★★★★]

  • Connection接口中与事务相关的方法
Connection接口中与事务相关的方法说明
void setAutCommit(boolean b);设置是否自动提交事务,默认是true:自动提交
false:禁止自动提交,需要手动提交
void commit()提交事务
void rollback()回滚事务
  • 需求:jack 给 rose 转账 500
  • 准备数据:创建账号表和添加用户数据
  • 步骤分析
  1. 注册驱动
  2. 获得连接对象并开启事务
  3. 获取SQL发送对象
  4. 准备扣钱SQL语句
  5. 执行扣钱SQL语句
  6. 准备加钱SQL语句
  7. 执行加钱SQL语句
  8. 如果没有问题则提交事务,否则回滚事务
  9. 关闭资源
  • 示例代码
/**
  目标:使用JDBC实现事务管理
  需求:Jack给rose转500块

  Connection对象与事务管理相关的方法
    * void setAutoCommit(boolean b)
        * 设置是否自动提交事务
        * b:true 自动提交,默认值
        * b:false 禁止自动提交 ==> 相当于start transaction;手动开启事务
    * void commit();
        * 提交事务
    * void rollback();
        * 回滚事务
 */
public class Demo01 {
    public static void main(String[] args){
        // 声明连接对象
        Connection conn = null;
        Statement stmt = null;
        try{
           // 1. 注册驱动
           Class.forName("com.mysql.jdbc.Driver");
           // 2. 获得连接对象
           conn = DriverManager.getConnection("jdbc:mysql:///day11", "root", "root");

           // 开启事务:等价start transaction;
           conn.setAutoCommit(false);

           // 3. 获取SQL发送对象
           stmt = conn.createStatement();
           // 4. 准备扣钱SQL语句
           String sql01 = "update account set balance = balance - 500 where id = 1";
           // 5. 执行扣钱SQL语句
           int row = stmt.executeUpdate(sql01);
           System.out.println("扣钱:" + row);

           // 模拟异常
           System.out.println(10/0);

           // 6. 准备加钱SQL语句
           String sql02 = "update account set balance = balance + 500 where id = 2";
           // 7. 执行加钱SQL语句
           row = stmt.executeUpdate(sql02);
           System.out.println("加钱:" + row);
           // 提交事务
           conn.commit();
       } catch(Exception e){
           System.out.println("回滚了事务...");
            try {
                if (conn != null)
                    conn.rollback(); // 回滚事务
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        } finally {
            // 8. 关闭资源
            if (stmt != null){
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn !=null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

11_创建 JDBC 工具类-[★★★★]

创建工具类的目的:将重复的代码定义到某个类的方法中,直接调用方法,可以简化代码。
实现工具类的步骤
1. 将固定字符串定义为常量
2. 在静态代码块中注册驱动(只注册一次)
3. 提供一个获取连接的方法:static Connection getConneciton();
4. 定义关闭资源的方法:close(Connection conn, Statement stmt, ResultSet rs)
5. 重载关闭方法:close(Connection conn, Statement stmt)

public class JDBCUtil {

    // 1. 将固定字符串定义为常量
    private static final String DRIVER_CLASS = "com.mysql.jdbc.Driver";
    private static final String URL = "jdbc:mysql:///day11";
    private static final String USER = "root";
    private static final String PASSWORD = "root";

    /**
     * 2. 在静态代码块中注册驱动(只注册一次)
     */
    static {
        try {
            // 1. 注册驱动
            Class.forName(DRIVER_CLASS);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /*
    * 3. 提供一个获取连接的方法:static Connection getConnection();
    * */
    public static Connection getConnection() {

      try{
          return DriverManager.getConnection(URL, USER,PASSWORD);
      } catch(Exception e){
          // return null;
          // 将编译时异常包装成运行时异常
          throw new RuntimeException(e);
      }
    }

    // 4. 定义关闭资源的方法:close(Connection conn, Statement stmt, ResultSet rs)
    public static void close(Connection conn, Statement stmt, ResultSet rs){
        /**
         关闭资源注意事项:先开后关(先创建的后关闭)
         1. 创建顺序:Connection ==> Statement ==> ResultSet
         2. 关闭顺序:ResultSet ==> Statement ==> Connectio
         */
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (stmt != null){
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn !=null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    //  5. 重载关闭方法:close(Connection conn, Statement stmt)
    public static void close(Connection conn, Statement stmt){
        close(conn, stmt, null);
    }
}

12_ JDBC 实现登录案例-[★★★★]

实现步骤:
1. 创建键盘录入对象:Scanner
2. 接收用户名和密码
3. 获得连接对象
4. 获得SQL语句发送对象
5. 准备要执行的SQL语句:登录SQL
6. 执行查询语句获得结果集对象
7. 判断是否登录成功
8. 释放资源

  • 示例代码
  1. 准备数据表和用户数据
create table user(
	id int primary key auto_increment,
	username varchar(20) not null unique,
	password varchar(20) not null
);
insert into user(username,password)  values('jack','rose'),('rose','laowang');
select * from user;

select * from user where username = 'jack' and password = 'rose';
/**
 * 目标:实现用户登录
 */
public class LoginDemo {
    public static void main(String[] args) throws Exception{
        // 1. 创建键盘录入对象:Scanner
        Scanner sc = new Scanner(System.in);
        // 2. 接收用户名和密码
        System.out.println("请输入用户名:"); // jack
        String username = sc.nextLine();
        System.out.println("请输入密码:");  // rose
        String password = sc.nextLine();

        // 3. 获得连接对象
        Connection conn = JDBCUtil.getConnection();
        // 4. 获得SQL语句发送对象
        Statement stmt = conn.createStatement();
        // 5. 准备要执行的SQL语句:登录SQL
        String sql = "select * from user where username = '"+username+"' and password = '"+password+"';";
        System.out.println("sql = " +sql);
        // 6. 执行查询语句获得结果集对象
        ResultSet rs = stmt.executeQuery(sql);
        // 7. 判断是否登录成功
        if (rs.next()){
            System.out.println("欢迎你:" +username);
        } else {
            System.out.println("用户名或密码错误");
        }
        // 8. 释放资源
        JDBCUtil.close(conn, stmt, rs);
    }
}

13_ SQL 注入概述和演示-[★★]

  1. 什么是SQL注入:
    用户输入的内容和SQL语句进行了拼接,用户输入的内容作为了SQL语法的一部分,改变了原有SQL语句的含义。
  • SQL 注入演示
请输入用户名:
hehe
请输入密码:
a' or '1'='1
  • 问题分析
// 代码中的SQL语句
"SELECT * FROM user WHERE name='" + name + "' AND password='" + password + "';";
// 将用户输入的账号密码拼接后
"SELECT * FROM user WHERE name='hehe' AND password='a' or '1'='1';"

14_PreparedStatement 接口概述-[★★★]

  • PreparedStatement 接口的继承体系:继承 Statement
  • PreparedStatement 对象的作用:用来发送 SQL 语句到数据库执行增删改查操作
  • 如何 PreparedStatement 对象:通过连接对象的方法获取:PreparedStatement ps = conn.prepareStatement(String sql);
PreparedStatement接口常用方法说明
int executeUpdate();执行DML语句
返回影响的行数
ResultSet executeQuery();执行DQL语句
返回满足查询条件的结果集对象

15_PreparedStatement 解决 SQL 注入-[理解]

解决SQL注入问题的核心思想是:
1. 用户输入的内容不要和SQL语句进行拼接
2. 使用PreparedStateme对象执行SQL语句

  • 需求:使用 PreparedStatement 改造登录案例解决 SQL 注入问题

  • 示例代码

/**
    如何解决SQL注入问题:用户输入的内容不要和SQL语句进行拼接,此时不能使用Statement来发送SQL,需要使用PreparedStatement
    来发送SQL语句到数据库执行了。
 sql = select * from user where username = 'jack' and password = 'a' or '1'='1';

  使用PreparedStatement解决SQL注入问题
 */
public class LoginDemo02 {
    public static void main(String[] args) throws Exception{
        // 1. 创建键盘录入对象:Scanner
        Scanner sc = new Scanner(System.in);
        // 2. 接收用户名和密码
        System.out.println("请输入用户名:"); // jack
        String username = sc.nextLine();
        System.out.println("请输入密码:");  // rose
        String password = sc.nextLine();

        // 3. 获得连接对象
        Connection conn = JDBCUtil.getConnection();
        // 4. 准备要执行的SQL语句:登录SQL
        // 4.1 未知内容使用占位符?代替:用户名和密码就属于未知内容
        String sql = "select * from user where username = ? and password = ? ;";
        System.out.println("sql = " +sql);
        // 5. 获得预编译对象:PreparedStatement
        PreparedStatement ps = conn.prepareStatement(sql);

        // 5.1 使用真实数据替换占位符?:给占位符问号赋值具体内容
        // 参数1:占位符的索引值,默认是从1开始
        // 参数2:占位符问号赋值的具体内容
        ps.setString(1,username);
        ps.setString(2,password);

        // 6. 执行查询语句获得结果集对象
        ResultSet rs = ps.executeQuery();
        // 7. 判断是否登录成功:  a' or '1'='1
        if (rs.next()){
            System.out.println("欢迎你:" +username);
        } else {
            System.out.println("用户名或密码错误");
        }
        // 8. 释放资源
        JDBCUtil.close(conn, ps, rs);
    }
}

16_ PreparedStatement 和 Statement 区别-[面试题]

相同点:都可以对数据库执行增删改查操作。

不同点:
1. PreparedStatement有预编译功能,Statement没有预编译功能。
2. PreparedStatement有缓存功能(缓存SQL语句的编译结果),Statement没有缓存功能。
3. PreparedStatement没有SQL注入,更安全,Statement有SQL注入,不安全。

17_ PreparedStatement 实现增删改操作-[★★★★★]

PreparedStatement实现增删改的步骤

  1. 获得连接对象
  2. 准备SQL语句:未知内容使用占位符?代替
  3. 根据SQL获得预编译对象
  4. 给占位符?赋值
  5. 执行SQL语句并获得结果
  6. 释放资源
  • 示例代码
/**
 * 需求:使用PreparedStatement实现增删改操作
 */
public class Demo01 {

    public static void main(String[] args) throws Exception{
        // 添加数据: 向学生表添加3条记录
        // insertStudent();

        // 修改数据: 将 id 为 2的用户,姓名更新为 "嫦娥 "  性别换成女,
        // updateStudent();

        // 删除数据: 删除id为2的学生
        deleteStudent();
    }

    // 添加数据: 向学生表添加3条记录
    public static void insertStudent() throws Exception {
        // 1. 获得连接对象
        Connection conn = JDBCUtil.getConnection();
        // 2. 准备SQL语句:未知内容使用占位符?代替
        String sql = "insert into student values(null,?,?,?)";
        // 3. 获得预编译对象
        PreparedStatement ps = conn.prepareStatement(sql);
        // 4. 给占位符赋值
        ps.setString(1, "小泽");
        ps.setString(2, "女");
        ps.setString(3, "1999-10-20");
        // 5. 执行SQL语句
        int row = ps.executeUpdate();
        System.out.println("row = " + row);

        // 5.1 重新给占位符赋值
        ps.setString(1, "小波");
        ps.setString(2, "男");
        ps.setString(3, "2009-09-21");
        row = ps.executeUpdate();
        System.out.println("row = " + row);

        // 5.2 重新给占位符赋值
        ps.setString(1, "小苍");
        ps.setString(2, "女");
        ps.setString(3, "2019-06-21");
        row = ps.executeUpdate();
        System.out.println("row = " + row);

        // 6. 释放资源
        JDBCUtil.close(conn, ps);
    }

    // 修改数据: 将 id 为 2的用户,姓名更新为 "嫦娥 "  性别换成女,
    public  static  void updateStudent() throws Exception {
        // 1. 获得连接对象
        Connection conn = JDBCUtil.getConnection();
        // 2. 准备SQL语句:未知内容使用占位符?代替
        String sql = "update student set name = ?, gender = ? where id = ?";
        // 3. 获得预编译对象
        PreparedStatement ps = conn.prepareStatement(sql);
        // 4. 给占位符赋值
        ps.setString(1, "嫦娥");
        ps.setString(2, "女");
        ps.setInt(3, 2);

        // 5. 执行SQL语句
        int row = ps.executeUpdate();
        System.out.println(row);

        // 6. 释放资源
        JDBCUtil.close(conn, ps);
    }

    // 删除数据: 删除id为2的学生
    public static void deleteStudent() throws Exception {
        // 1. 获得连接对象
        Connection conn = JDBCUtil.getConnection();
        // 2. 准备SQL语句:未知内容使用占位符?代替
        String sql = "delete from student where id = ?";
        // 3. 获得预编译对象
        PreparedStatement ps = conn.prepareStatement(sql);
        // 4. 给占位符赋值
        ps.setInt(1, 2);

        // 5. 执行SQL语句
        int row = ps.executeUpdate();
        System.out.println(row);

        // 6. 释放资源
        JDBCUtil.close(conn, ps);
    }
}

18_ PreparedStatment 实现查询操作-[★★★★★]

  • 需求:查询id小于4的学生信息,并保存将每一个记录封装成一个学生对象存储到List集合中

  • user 代码

public class Student {
    private int id;
    private String name;
    private String gender;
    private Date birthday;


    public Student() {
    }

    public Student(int id, String name, String gender, Date birthday) {
        this.id = id;
        this.name = name;
        this.gender = gender;
        this.birthday = birthday;
    }

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                ", birthday=" + birthday +
                '}';
    }
}
  • 示例代码
/**
 * 需求:查询所有学生信息并封装成Student对象存储到集合中。
 */
public class Demo02 {
    public static void main(String[] args) throws Exception {
        // 1. 获得连接对象
        Connection conn = JDBCUtil.getConnection();
        // 2. 准备SQL语句:未知内容使用占位符?代替
        String sql = "select * from student;";
        // 3. 根据SQL获得预编译对象
        PreparedStatement ps = conn.prepareStatement(sql);
        // 4. 执行SQL语句并获得结果
        ResultSet rs = ps.executeQuery();
        // 创建集合:存储学生对象
        List<Student> list = new ArrayList<>();
        // 5. 遍历结果集对象
        while(rs.next()){
            // 5.1 获得每一列的值
            int id = rs.getInt("id");
            String name = rs.getString("name");
            String gender = rs.getString("gender");
            Date birthday = rs.getDate("birthday");

            // 5.2 创建学生对象:封装每列的值
            Student student = new Student(id, name, gender, birthday);
            // 5.3 将学生对象添加到集合中
            list.add(student);
        }
        // 6. 释放资源
        JDBCUtil.close(conn, ps, rs);
        // 7. 输出集合学生信息
        for (Student stu : list) {
            System.out.println(stu);
        }
    }
}

19_连接池概述-[★★]

  1. 什么是连接池:
    一个负责创建和管理连接对象的容器(集合)

  2. 为什么需要使用连接池
    因为频繁的创建和销毁连接是很耗资源(内存资源和时间资源)的过程。
    使用连接池可以减少频繁创建和效率连接带来的系统开销。 从而提高访问数据库的效率

  3. 连接池的核心思想:连接复用

  4. 连接池规范:DataSource

20_ C3P0 连接池基本使用-[★★★★]

  • C3P0连接池API介绍
ComboPooledDataSource构造方法说明
ComboPooledDataSource()使用默认的配置default-config创建数据源对象
ComboPooledDataSource(命名配置)使用命名的配置named-config创建数据源对象
  • 配置文件模板:c3p0-config.xml
<c3p0-config>
  <!-- 使用默认的配置读取连接池对象 -->
  <default-config>
  	<!--  连接参数 -->
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/day25</property>
    <property name="user">root</property>
    <property name="password">root</property>
    
    <!-- 连接池参数 -->
    <property name="initialPoolSize">5</property>
    <property name="maxPoolSize">10</property>
    <property name="checkoutTimeout">2000</property>
    <property name="maxIdleTime">1000</property>
  </default-config>

  <named-config name="pkxingc3p0"> 
    <!--  连接参数 -->
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/day25</property>
    <property name="user">root</property>
    <property name="password">root</property>
    
    <!-- 连接池参数 -->
    <property name="initialPoolSize">5</property>
    <property name="maxPoolSize">15</property>
    <property name="checkoutTimeout">2000</property>
    <property name="maxIdleTime">1000</property>
  </named-config>
</c3p0-config>

使用步骤:

  1. 导入c3p0相关jar包
  2. 准备c3p0配置文件
    2.1 配置文件要求
     命名要求:c3p0-config.xml
     位置要求:在src目录下
    2.2 配置信息
     数据库信息:
      数据库驱动:com.mysql.jdbc.Driver
      数据库地址: url
      用户名: user
      密码:password
     连接池信息:
      初始化连接数:5
      最大连接数:10
      最大等待时间:3000毫秒
      最大空闲时间:3000毫秒
  3. 创建连接池对象
  4. 调用连接池对象的方法获得连接对象
  5. 关闭连接对象:不是真正的关闭,而是将连接对象放回连接池中等待复用。
  • 示例代码
/**
    目标:使用C3P0连接池获得连接对象
 */
public class Demo01 {
    public static void main(String[] args) throws Exception{
        // 3. 创建连接池对象
        // 使用默认配置创建
        // DataSource ds = new ComboPooledDataSource();

        // 使用命名配置创建
        DataSource ds = new ComboPooledDataSource("pkxingc3p0");

        // 循环从连接池中获取连接对象
        for (int i = 0; i < 16; i++) {
            // 调用连接池对象的方法获得连接对象
            Connection conn = ds.getConnection();
            System.out.println(i+ "==>" +conn);
            // ......
            if (i == 5){
                // 关闭连接对象:不是真正的关闭,而是将连接对象放回连接池中等待复用。
                conn.close();
            }
        }
    }
}

21_ DRUID 连接池基本使用-[★★★★]

  • API介绍
DruidDataSourceFactory类静态方法说明
public static DataSource createDataSource(Properties properties)创建连接池对象

我们可以看到DRUID连接池在创建的时候需要一个Properties对象来设置参数,所以我们使用properties文件来保存对应的参数。DRUID连接池的配置文件名称随便,建议放到src目录下面方便加载。druid.properties文件内容:

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/day25
username=root
password=root
initialSize=5
maxActive=10
maxWait=3000
maxIdle=6
minIdle=3

Druid连接池的使用步骤

  1. 导入相关jar
  2. 准备配置文件:xxx.properties
    2.1 配置数据库信息
    2.2 配置连接池信息
  3. 创建属性集对象:Properties
    3.1 加载配置文件信息到属性集对象中
  4. 通过Driud提供的工具类方法创建数据源对象
  5. 调用数据源对象的方法获得连接对象:getConnection
  6. 调用连接对象方法将连接对象关闭返回池中
  • 示例代码
/**
 * 目标:创建Druid连接池并从池中获得连接对象
 */
public class Demo01 {
    public static void main(String[] args)throws Exception {
        // 1. 创建集合用来存储配置信息
        Properties info = new Properties();
        System.out.println(info);
        // 2. 加载配置文件信息到集合中
        // 2.1 获得与配置文件关联的输入流
        // InputStream in = Demo01.class.getResourceAsStream("/druid.properties");
        info.load(Demo01.class.getResourceAsStream("/druid.properties"));
        System.out.println(info);
        // 3. 创建连接池对象
        DataSource ds = DruidDataSourceFactory.createDataSource(info);

        // 4. 从连接池中获得连接对象
        for (int i = 0; i < 11; i++) {
            Connection conn = ds.getConnection();
            System.out.println(i+"===>"+conn);
            // .....
            if (i==5){
                // 5. 关闭连接对象:不是真正关闭而是放回池中
                conn.close();
            }
        }

    }
}

22_连接池工具类-[★★★★]

数据源工具类实现步骤

  1. 创建私有静态数据源成员变量 DataSource ds
  2. 在静态代码块中创建连接池
    a) 创建属性集对象
    b) 从类路径下加载属性文件,得到输入流对象
    c) 通过工厂类创建一个数据源
  3. 创建公有的得到数据源的方法 getDataSource()
  4. 创建得到连接对象的方法 getConnection()
  5. 创建释放资源的方法 close(Connction conn, Statement stmt, ResultSet rs)
  • 数据源工具类代码
public class DataSourceUtil {
    //  1)	创建私有静态数据源成员变量 DataSource ds
    private static DataSource ds = null;

    // 2)	在静态代码块中创建连接池:只需要创建1个
    static {
       try{
           // a)	创建属性集对象
           Properties info = new Properties();
           // b)	从类路径下加载属性文件,得到输入流对象
           info.load(Demo01.class.getResourceAsStream("/druid.properties"));
           // c)	通过工厂类创建一个数据源
           ds = DruidDataSourceFactory.createDataSource(info);
       } catch(Exception e){
           e.printStackTrace();
       }
    }

    // 3)	创建公有的得到数据源的方法 getDataSource()
    public static DataSource getDataSource(){
        return ds;
    }

    // 4)	创建得到连接对象的方法 getConnection()
    public static Connection getConnection() {
        try{
            return ds.getConnection();
        } catch(Exception e){
            // 将编译时异常包装成运行时异常
            throw new RuntimeException(e);
        }
    }

    // 5. 定义关闭资源的方法:close(Connection conn, Statement stmt, ResultSet rs)
    public static void close(Connection conn, Statement stmt, ResultSet rs){
        /**
         关闭资源注意事项:先开后关(先创建的后关闭)
         1. 创建顺序:Connection ==> Statement ==> ResultSet
         2. 关闭顺序:ResultSet ==> Statement ==> Connectio
         */
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (stmt != null){
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn !=null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    //  重载关闭方法:close(Connection conn, Statement stmt)
    public static void close(Connection conn, Statement stmt){
        close(conn, stmt, null);
    }
}
  • 测试类代码
  • 需求:使用数据源工具类获得连接对象并执行数据库操作。
/**
 数据源工具类的测试
 */
public class DataSourceUtilDemo {
    public static void main(String[] args) throws Exception{
        // 获得连接对象
        Connection conn = DataSourceUtil.getConnection();
        // 获得预编译对象
        PreparedStatement ps = conn.prepareStatement("insert into student values(null,?,?,?)");
        // 给问号赋值
        ps.setString(1 ,"老王");
        ps.setString(2 ,"男");
        ps.setString(3 ,"2020-01-20");

        // 执行SQL语句
        int row = ps.executeUpdate();
        System.out.println(row);
        // 关闭资源
        DataSourceUtil.close(conn, ps);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值