JDBC基础篇

一、引言

1.1数据的存储

在单纯的开发java程序中,数据是储存在内存里的,关闭或重启程序,数据就会丢失没法长期保存。

这个时候有下面的解决方法

  1. I/O流,储存在本地磁盘,解决了长期保存的问题,但是没有结构和逻辑,不方便管理和维护
  2. 通过关系型数据库,如02-MySQl将数据交给数据库来管理。

1.2数据的操作

明确了数据存在哪,但想对数据做增删改查该怎么办,也就是用JDBC。

2.1JDBC的概念

  • JDBC就是java语言操作关系型数据库的一些api
  • java负责提供接口规范,数据库厂商负责实现,JDBC独立于任意一种数据库
  • 程序员去调用接口,接口去第哦啊用驱动的实现

三、JDBC快速入门

3.1JDBC

java

ini 复制代码
public class JDBCQuick {  
    public static void main(String[] args) throws Exception {  
        //1.注册驱动(jdk6之后甚至可以不写)  
        Class.forName("com.mysql.cj.jdbc.Driver");  
  
        //2.获取连接对象(在本机ip且端口没有改变的情况, localhost:3306可以省略)  
        String url="jdbc:mysql://localhost:3306/atguigu";//连接地址  
        String username="root";  
        String password="cby";  
        Connection connection = DriverManager.getConnection(url, username,  password);  
  
        //3.获取执行sql语句的对象  
        Statement statement = connection.createStatement();  
  
        //4.编写sql语句并执行,接受返回的结果集(也就是mysql的表格)  
        String sql="SELECT emp_id,emp_name,emp_salary,emp_age FROM t_emp";  
        ResultSet resultSet = statement.executeQuery(sql);  
  
        //5.处理结果:遍历resultSet结果集  
        while(resultSet.next()){  
            int empId = resultSet.getInt("emp_id");  
  
            String empName = resultSet.getString("emp_name");  
  
            double empSalary = resultSet.getDouble("emp_salary");  
  
            int empAge = resultSet.getInt("emp_age");  
  
            System.out.println(empId+"\t"+empName+"\t"+empSalary+"\t"+empAge);  
        }  
  
        //6.释放资源(先开后关)  
        resultSet.close();  
        statement.close();  
        connection.close();  
    } 
}

四、核心 API 理解

4.1 注册驱动

  • Class.forName("com.mysql.cj.jdbc.Driver");
  • 在 Java 中,当使用 JDBC连接数据库时,需要加载duiying1数据库特定的驱动程序,以便与数据库进行通信。
  • 从 JDK6 开始,不再需要显式地调用Class.forName()来加载 JDBC 驱动程序,只要在类路径中集成了对应的 jar 文件,会自动在初始化时注册驱动程序。

4.2 Connection

  • Connection 接口是 JDBC API 的重要接口,用于建立与数据库的通信通道。换而言之,Connection 对象不为空,则代表一次数据库连接。

  • 在建立连接时,需要指定数据库 URL、用户名、密码参数。

    • URL:jdbc:mysql://localhost:3306/atguigu
      String url="jdbc:mysql://localhost:3306/atguigu";//连接地址
      String username="root";
      String password="cby";
      Connection connection = DriverManager.getConnection(url, username, password);
  • Connection 接口还负责管理事务,Connection 接口提供了 commit 和 rollback 方法,用于提交事务和回滚事务。

  • 可以创建 Statement 对象,用于执行 SQL 语句并与数据库进行交互。

  • 在使用 JDBC 技术时,必须要先获取 Connection 对象,在使用完毕后,要释放资源,避免资源占用浪费及泄漏。

4.3 Statement

  • Statement 接口用于执行 SQL 语句并与数据库进行交互。它是 JDBC API 中的一个重要接口。通过 Statement 对象,可以向数据库发送 SQL 语句并获取执行结果。

  • 结果可以是一个或多个结果。

    1. 增删改:受影响行数单个结果。
    2. 查询:单行单列、多行多列、单行多列等结果。
  • 但是 Statement 接口在执行 SQL 语句时,会产生 SQL 注入攻击问题:

    • 当使用 Statement 执行动态构建的 SQL 查询时,往往需要将查询条件与 SQL 语句拼接在一起,直接将参数和 SQL 语句一并生成,让 SQL 的查询条件始终为 true 得到结果。

eg:

ini 复制代码
//3. 获取执行SQL语句对象
Statement statement = connection.createStatement();

System.out.println("请输入员工姓名:");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();

//4. 编写SQL语句,并执行,接受返回的结果
String sql = "SELECT emp_id,emp_name,emp_salary,emp_age FROM t_emp WHERE emp_name = '"+name+"'";
ResultSet resultSet = statement.executeQuery(sql);

如果输入的是xxx' or '1'= '1

那么在mysql里面就会是 :SELECT emp_id,emp_name,emp_salary,emp_age FROM t_emp WHERE emp_name = 'xxx' or '1'= '1'

结果一直为true,会把整个数据库遍历

4.4PreparedStatement

  • PrepareStatement 是 Statement 的子接口,用来执行预编译的 SQL 查询。作用:

    1. 预编译 SQL 语句,在执行到connection.prepareStatement(sql) 时就会预编译 SQL 语句,那个时候 SQL 语句已经固定了。因此它也带来了性能的提升。同一 SQL 语句在多次执行下可以复用,不用每次重新编译和解析。(但这个我还不太懂具体是怎样带来的性能提升)

    2. 防止 SQL 注入,采用问号占位符的方式

    • 只要这个位置本来就该写一个具体的数据(数字 / 字符串 / 日期) ,就可以换成?
    • 只要这个位置是 SQL 语法(表、列、关键字、符号),就不能用?
    • 所有传入的参数都会被一对单引号包裹起来。(这里很特殊,他是把传入的值单纯当成一坨来看的,不管里面是什么,再奇怪的组合都不管,就只是把他当成一串字符串,里面的 'or=-- 全部只是普通文字,不会被数据库识别成 SQL 语法符号,然后再去完成和where条件的比较)

使用即使传入xxx' or '1'= '1在mysql里面得到的WHERE emp_name = 'xxx' or '1'= '1'和Statement看上去一模一样但是已经发生根本的改变了。

用PreparedStatement传进去的内容,数据库只当 "一整块纯文本",不解析语法

ini 复制代码
//3. 获取执行SQL语句对象 
PreparedStatement preparedStatement = connection.prepareStatement("SELECT emp_id,emp_name,emp_salary,emp_age FROM t_emp WHERE emp_name = ?");

 System.out.println("请输入员工姓名:");
 Scanner scanner = new Scanner(System.in); 
 String name = scanner.nextLine(); 
 
 // 给占位符赋值
 preparedStatement.setString(1, name); 
 
 //4. 执行SQL语句,接受返回的结果 ResultSet resultSet = preparedStatement.executeQuery();
 

PreparedStatement 靠预编译锁定 SQL 结构,用?占位符隔离数据,再自动转义参数引号(JDBC 驱动调用 setString 时自动把参数里所有单引号替换成两个单引号,避免截断sql语句),双重防护杜绝 SQL 注入。

4.5 ResultSet

  • ResultSet 是 JDBC API 中的一个接口,用于表示从数据库中执行查询语句所返回的结果集。它提供了一种用于遍历和访问查询结果的方式。

  • 遍历结果:ResultSet 可以使用 next() 方法将游标移动到结果集的下一行,逐行遍历数据库查询的结果,返回值为 boolean 类型,true 代表有下一行结果,false 则代表没有。

  • 获取单列结果:可以通过 getXxx 的方法获取单列的数据,该方法为重载方法,支持索引和列名进行获取。

    1. 按列下标(数字,查询 SQL 里字段从左往右数,第 1 个字段填 1,依次递增;)
ini 复制代码
   String name = rs.getString(2); 
   int age = rs.getInt(4);
  1. 按列名字符串(推荐)
ini 复制代码
String name = rs.getString("emp_name");
int age = rs.getInt("emp_age");
相关推荐
用户64278006937881 小时前
elpis-core 第一阶段学习心得与收获
后端
kfaino1 小时前
码农的AI翻身·前传 一个大模型从出生到上岗的全过程
后端·aigc
IT_陈寒1 小时前
Vue的这个响应式陷阱让我熬到凌晨三点
前端·人工智能·后端
葫芦和十三2 小时前
图解 MongoDB 17|大集合与工作集:数据超过内存怎么办
后端·mongodb·面试
kfaino9 小时前
码农的AI翻身(三)你好,我叫 Embedding
后端·ai编程
葫芦和十三10 小时前
图解 MongoDB 18|复制集拓扑:Primary、Secondary 和 Arbiter 的分工
后端·mongodb·面试
爱勇宝10 小时前
大多数人不是在使用 AI 赚钱,而是在帮 AI 公司赚钱
前端·后端·程序员
程序员cxuan13 小时前
虽迟但到!GPT-5.6 终于来了!
人工智能·后端·程序员
IT_陈寒15 小时前
React的这个渲染问题连官方文档都没说清楚
前端·人工智能·后端