JDBC(Java数据库连接)

文章目录

1、JDBC快速入门

1.1 JDBC的概念

1.2 JDBC的本质

1.3 JDBC的快速入门程序

1.3.1 导入jar包

1.3.2 注册驱动 

1.3.3 获取连接

1.3.4 获取执行者对象

1.3.5 执行sql语句,并接收返回结果

1.3.6 处理结果

1.3.7 释放资源

2、JDBC各个功能类详解

2.1 DriverManager

2.2 Connection

2.3 Statement

2.4 ResultSet

3、JDBC案例student学生表的CRUD

3.1 数据准备

3.2 需求一:查询全部

3.3 需求二:条件查询

5、SQL注入攻击

5.1 sql注入攻击的演示

5.2 sql注入攻击的原理

5.3 PreparedStatement的介绍

5.4 PreparedStatement的使用

7、数据库连接池

7.1 数据库连接池的概念

​编辑7.2 Data Source

7.2.1 DataSource接口概述

7.2.2 自定义数据库连接池

 7.2.3 自定义数据库连接池的测试

7.2.4 归还连接


1、JDBC快速入门

1.1 JDBC的概念

        JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系型数据库提供统一访问,它是由一组用Java语言编写的类和接口组成的。

1.2 JDBC的本质

        其实就是java官方提供的一套规范(接口)。用于帮助开发人员快速实现不同关系型数据库的连接!

1.3 JDBC的快速入门程序

1.3.1 导入jar包

1.3.2 注册驱动 

Class.forName("com.mysql.jdbc.Driver");

1.3.3 获取连接

Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/db2", "root", "root");

1.3.4 获取执行者对象

Statement stat = con.createStatement();

1.3.5 执行sql语句,并接收返回结果

String sql = "SELECT * FROM user";
ResultSet rs = stat.executeQuery(sql);

1.3.6 处理结果

while(rs.next()) {
    System.out.println(rs.getInt("id") + "\t" + rs.getString("name"));
}

1.3.7 释放资源

con.close();
stat.close();
rs.close();

2、JDBC各个功能类详解

2.1 DriverManager

  • DriverManager:驱动管理对象

    • 注册驱动(告诉程序该使用哪一个数据库驱动)

      • static void registerDriver(Driver driver):注册与给定的驱动程序 DriverManager

      • 写代码使用:Class.forName("com.mysql.jdbc.Driver");

      • 通过查看源码发现:在com.mysql.jdbc.Driver类中存在静态代码块

      static {
          try {
              java.sql.DriverManager.registerDriver(new Driver());
          } catch (SQLException E) {
              throw new RuntimeException("Can't register driver!");
          }
      }
      • 注意:mysql5之后的驱动jar包可以省略注册驱动的步骤。在jar包中,存在一个java.sql.Driver配置文件,文件中指定了com.mysql.jdbc.Driver

    • 获取数据库连接(获取到数据库的连接并返回连接对象)

      • static Connection getConnection(String url, String user, String password);

        • 返回值:Connection数据库连接对象

        • 参数

          • url:指定连接的路径。语法:jdbc:mysql://ip地址(域名):端口号/数据库名称

          • user:用户名

          • password:密码

2.2 Connection

  • Connection:数据库连接对象

    • 获取执行者对象

      • 获取普通执行者对象:Statement createStatement();

      • 获取预编译执行者对象:PreparedStatement prepareStatement(String sql);

    • 管理事务

      • 开启事务:setAutoCommit(boolean autoCommit); 参数为false,则开启事务。

      • 提交事务:commit();

      • 回滚事务:rollback();

    • 释放资源

      • 立即将数据库连接对象释放:void close();

2.3 Statement

  • Statement:执行sql语句的对象

    • 执行DML语句:int executeUpdate(String sql);

      • 返回值int:返回影响的行数。

      • 参数sql:可以执行insert、update、delete语句

    • 执行DQL语句:ResultSet executeQuery(String sql);

      • 返回值ResultSet:封装查询的结果。

      • 参数sql:可以执行select语句

    • 释放资源

      • 立即将执行者对象释放:void close();

2.4 ResultSet

  • ResultSet:结果集对象

    • 判断结果集中是否还有数据:boolean next();

      • 有数据返回true,并将索引向下移动一行

      • 没有数据返回false

    • 获取结果集中的数据:XXX getXxx("列名");

      • XXX代表数据类型(要获取某列数据,这一列的数据类型)

      • 例如:String getString("name"); int getInt("age");

    • 释放资源

      • 立即将结果集对象释放:void close();

3、JDBC案例student学生表的CRUD

3.1 数据准备

  • 数据库和数据表

-- 创建db14数据库
CREATE DATABASE db14;
​
-- 使用db14数据库
USE db14;
​
-- 创建student表
CREATE TABLE student(
    sid INT PRIMARY KEY AUTO_INCREMENT, -- 学生id
    NAME VARCHAR(20),                   -- 学生姓名
    age INT,                            -- 学生年龄
    birthday DATE                       -- 学生生日
);
​
-- 添加数据
INSERT INTO student VALUES (NULL,'张三',23,'1999-09-23'),(NULL,'李四',24,'1998-08-10'),(NULL,'王五',25,'1996-06-06'),(NULL,'赵六',26,'1994-10-20');
  • 实体类

    • Student类,成员变量对应表中的列

    • 注意:所有的基本数据类型需要使用包装类,以防null值无法赋值

package com.itheima02.domain;

import java.util.Date;

public class Student {
    private Integer sid;
    private String name;
    private Integer age;
    private Date birthday;

    public Student() {
    }

    public Student(Integer sid, String name, Integer age, Date birthday) {
        this.sid = sid;
        this.name = name;
        this.age = age;
        this.birthday = birthday;
    }

    public Integer getSid() {
        return sid;
    }

    public void setSid(Integer sid) {
        this.sid = sid;
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getBirthday() {
        return birthday;
    }

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

    @Override
    public String toString() {
        return "Student{" +
                "sid=" + sid +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", birthday=" + birthday +
                '}';
    }
}

3.2 需求一:查询全部

  • 持久层

/*
     查询所有学生信息
*/
@Override
public ArrayList<Student> findAll() {
    ArrayList<Student> list = new ArrayList<>();
    Connection con = null;
    Statement stat = null;
    ResultSet rs = null;
    try{
        //1.注册驱动
        Class.forName("com.mysql.jdbc.Driver");
​
        //2.获取数据库连接
        con = DriverManager.getConnection("jdbc:mysql://192.168.59.129:3306/db14", "root", "itheima");
​
        //3.获取执行者对象
        stat = con.createStatement();
​
        //4.执行sql语句,并且接收返回的结果集
        String sql = "SELECT * FROM student";
        rs = stat.executeQuery(sql);
​
        //5.处理结果集
        while(rs.next()) {
            Integer sid = rs.getInt("sid");
            String name = rs.getString("name");
            Integer age = rs.getInt("age");
            Date birthday = rs.getDate("birthday");
​
            //封装Student对象
            Student stu = new Student(sid,name,age,birthday);
​
            //将student对象保存到集合中
            list.add(stu);
        }
​
    } catch(Exception e) {
        e.printStackTrace();
    } finally {
        //6.释放资源
        if(con != null) {
            try {
                con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
​
        if(stat != null) {
            try {
                stat.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
​
        if(rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    //将集合对象返回
    return list;
}
  • 业务层
/*
    查询所有学生信息
*/
@Override
public ArrayList<Student> findAll() {
    return dao.findAll();
}
  • 控制层
/*
    查询所有学生信息
*/
@Test
public void findAll() {
    ArrayList<Student> list = service.findAll();
    for(Student stu : list) {
        System.out.println(stu);
    }
}

3.3 需求二:条件查询

  • 持久层

/*
    条件查询,根据id查询学生信息
*/
@Override
public Student findById(Integer id) {
    Student stu = new Student();
    Connection con = null;
    Statement stat = null;
    ResultSet rs = null;
    try{
        //1.注册驱动
        Class.forName("com.mysql.jdbc.Driver");

        //2.获取数据库连接
        con = DriverManager.getConnection("jdbc:mysql://192.168.59.129:3306/db14", "root", "itheima");

        //3.获取执行者对象
        stat = con.createStatement();

        //4.执行sql语句,并且接收返回的结果集
        String sql = "SELECT * FROM student WHERE sid='"+id+"'";
        rs = stat.executeQuery(sql);

        //5.处理结果集
        while(rs.next()) {
            Integer sid = rs.getInt("sid");
            String name = rs.getString("name");
            Integer age = rs.getInt("age");
            Date birthday = rs.getDate("birthday");

            //封装Student对象
            stu.setSid(sid);
            stu.setName(name);
            stu.setAge(age);
            stu.setBirthday(birthday);
        }

    } catch(Exception e) {
        e.printStackTrace();
    } finally {
        //6.释放资源
        if(con != null) {
            try {
                con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

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

        if(rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    //将对象返回
    return stu;
}
  •  业务层
/*
    条件查询,根据id查询学生信息
*/
@Override
public Student findById(Integer id) {
    return dao.findById(id);
}
  •  控制层
/*
    条件查询,根据id查询学生信息
*/
@Test
public void findById() {
    Student stu = service.findById(3);
    System.out.println(stu);
}

5、SQL注入攻击

5.1 sql注入攻击的演示

  • 在登录界面,输入一个错误的用户名或密码,也可以登录成功

 

5.2 sql注入攻击的原理

  • 按照正常道理来说,我们在密码处输入的所有内容,都应该认为是密码的组成

  • 但是现在Statement对象在执行sql语句时,将一部分内容当做查询条件来执行了

5.3 PreparedStatement的介绍

  • 预编译sql语句的执行者对象。

    • 在执行sql语句之前,将sql语句进行提前编译。明确sql语句的格式后,就不会改变了。剩余的内容都会认为是参数!

    • sql语句中的参数使用?作为占位符

  • 为?参数赋值的方法:setXxx(参数1,参数2);

    • Xxx代表:数据类型

    • 参数1:?的位置编号(编号从1开始)

    • 参数2:?的实际参数

  • 执行sql语句的方法

    • 执行insert、update、delete语句:int executeUpdate();

    • 执行select语句:ResultSet executeQuery();

5.4 PreparedStatement的使用

/*
	 使用PreparedStatement的登录方法,解决注入攻击
*/
@Override
public User findByLoginNameAndPassword(String loginName, String password) {
    //定义必要信息
    Connection conn = null;
    PreparedStatement pstm = null;
    ResultSet rs = null;
    User user = null;
    try {
        //1.获取连接
        conn = JDBCUtils.getConnection();
        //2.创建操作SQL对象
        String sql = "SELECT * FROM user WHERE loginname=? AND password=?";
        pstm = conn.prepareStatement(sql);
        //3.设置参数
        pstm.setString(1,loginName);
        pstm.setString(2,password);
        System.out.println(sql);
        //4.执行sql语句,获取结果集
        rs = pstm.executeQuery();
        //5.获取结果集
        if (rs.next()) {
            //6.封装
            user = new User();
            user.setUid(rs.getString("uid"));
            user.setUcode(rs.getString("ucode"));
            user.setUsername(rs.getString("username"));
            user.setPassword(rs.getString("password"));
            user.setGender(rs.getString("gender"));
            user.setDutydate(rs.getDate("dutydate"));
            user.setBirthday(rs.getDate("birthday"));
            user.setLoginname(rs.getString("loginname"));
        }
        //7.返回
        return user;
    }catch (Exception e){
        throw new RuntimeException(e);
    }finally {
        JDBCUtils.close(conn,pstm,rs);
    }
}

7、数据库连接池

7.1 数据库连接池的概念

  • 数据库连接背景

    • 数据库连接是一种关键的、有限的、昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出。对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标。数据库连接池正是针对这个问题提出来的。

  • 数据库连接池

    • 数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个。这项技术能明显提高对数据库操作的性能。

  • 数据库连接池原理

7.2 Data Source

7.2.1 DataSource接口概述

  • javax.sql.DataSource接口:数据源(数据库连接池)。Java官方提供的数据库连接池规范(接口 )
  • 如果想完成数据库连接池技术,就必须实现DataSource接口
  • 核心功能:获取数据库连接对象:Connection getConnection();

7.2.2 自定义数据库连接池

  1. 定义一个类,实现DataSource接口
  2. 定义一个容器,用于保存多个Connection连接对象
  3. 定义静态代码块,通过jdbc工具类获取10个连接保存到容器中
  4. 重写getConnection方法,从容器中获取一个连接并返回
  5. 定义getSize方法,用于获取连接池容器的大小并返回

 7.2.3 自定义数据库连接池的测试

  1. 创建连接池对象
  2. 获取数据库连接对象
  3. 查询学生表全部信息,并将查询的结果进行处理
  4. 释放资源

7.2.4 归还连接

1、继承(无法解决)

  • 通过打印连接对象,发现DriverManager获取的连接实现类是JDBC4Connection。

  • 自定义一个类,继承JDBC4Connection这个类,重写close()方法,完成连接对象的归还。

 2、继承方式归还数据库连接的实现步骤

  1. 定义一个类,继承JDBC4Connection
  2. 定义Connection连接对象和连接池容器对象的成员变量
  3. 通过有参构造方法完成对成员变量的赋值
  4. 重写close方法,将连接对象添加到池中

3、继承方式归还数据库连接存在的问题

        通过查看JDBC工具类获取连接的方法发现:我们虽然自定义了一个子类,完成了归还连接的

操作。但是DriverManager获取的还是JDBC4Connection这个对象,并不是我们的子类对象。

而我们又不能整体去修改驱动包中类的功能,所以继承这种方式行不通!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值