第六章JDBC基础详解

news2025/4/27 9:17:11

文章目录

  • 什么是JDBC
    • 数据库编程的必要条件
    • JDBC工作原理
  • JDBC如何建立数据库连接
  • JBDC的基本操作
      • 添加操作
      • 修改操作
      • 删除操作
      • 查询操作
      • JDBC使用的步骤
  • JDBC的批处理操作
  • JDBC数据源连接池
  • 关于执行sql语句的对象

什么是JDBC

数据库编程的必要条件

  • 编程语言,如Java,C、C++、Python等
  • 数据库,如Oracle,MySQL,SQL Server等
  • 数据库驱动包:不同的数据库,对应不同的编程语言提供了不同的数据库驱动包,如:MySQL提 供了Java的驱动包mysql-connector-java,需要基于Java操作MySQL即需要该驱动包。同样的, 要基于Java操作Oracle数据库则需要Oracle的数据库驱动包jdbc。
  • JAVA的驱动包就是JDBC
    • JDBC,即Java Database Connectivity,java数据库连接。是一种用于执行SQL语句的Java API,它是Java中的数据库连接规范。这个API由 java.sql.,javax.sql. 包中的一些类和接口组成,它为Java开发人员操作数据库提供了一个标准的API,可以为多种关系数据库提供统一访问

在这里插入图片描述

JDBC工作原理

img

  • JDBC 为多种关系数据库提供了统一访问方式,作为特定厂商数据库访问API的一种高级抽象,它主要包含一些通用的接口类
    • sun发布的Java程序与数据库通信的规范(也就是一系列接口)
    • Java语言访问数据库操作完全面向抽象接口编程
    • 开发数据库应用不用限定在特定数据库厂商的API
    • 程序的可移植性大大增强
    • JDBC只支持关系型数据库,也就是使用表结构的数据库
  • JDBC的驱动层是各大数据库厂商去实现JDBC的规范,然后将这些实现类打成压缩包,就是所谓的jar包

JDBC如何建立数据库连接

public class Demo1 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //1导入jar包——也就是对应数据块的驱动包
        //2加载驱动——驱动其实是一个类,在JVM中我们学到了关于反射的forname,会引起我们的类加载和初始化
        //也就把我们的相关的类加载到内存
        Class.forName("org.gjt.mm.mysql.Driver");
        //3通过驱动管理获取连接对象
           //3.1 准备url
        String url="jdbc:mysql://localhost:3306/fruitdb";
        //"jdbc:mysql://127.0.0.1:3306/rocket_class?characterEncoding=utf8&useSSL=false?characterEncoding=utf8&useSSL=false")
           //3.2准备用户名
        String user="root";
           //3.3准备密码
        String pwd="******";
        //4获取网络请求,根据上面的属性获得数据库的连接
        //java.sql.Connection 连接对象
        Connection con= DriverManager.getConnection(url,user,pwd);
        System.out.printf("Connection"+con);

    }
}
  • jar包的导入,只要把对应的项目中导入对应要操作数据库的jar包

  • 加载驱动,其实就是将对应的数据库的类加载到我们的内存中

  • 通过我们的驱动对象获取我们的连接对象,配置相关的数据库信息

    • url 类似我们的http协议的请求形式

      • jdbc:mysql://类似http://
      • localhost:3306 对应ip地址和端口
      • fruitdb对应着我们的数据库,我们的http中是一个文件路径来找到对应的资源
      • ?表示连接我们的设置,设置的形式是key:value这种形式,多个参数用&连接

    在这里插入图片描述

    • user 是我们的登录用户的账号

    • pwd 是我们登录用户的密码

JBDC的基本操作

添加操作

package com.lsc.jdbc;

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

/**
 * 实现JDBC的添加操作
 */
public class Demo2 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        Class.forName("com.mysql.jdbc.Driver");

        String url="jdbc:mysql://localhost:3306/fruitdb?characterEncoding=utf8&useSSL=false";
        String user="root";
        String pwd="*****";
        Connection connection= DriverManager.getConnection(url,user,pwd);
        //1编写sql语句
        String sql="insert into t_fruit values(0,?,?,?,?)";
        //2创建预处理命令对象
        PreparedStatement pst=connection.prepareStatement(sql);
        //3填充参数
        pst.setString(1,"菠萝蜜");
        pst.setInt(2,15);
        pst.setInt(3,100);
        pst.setString(4,"这是菠萝蜜");
        //4执行操作
        int count=  pst.executeUpdate();//对于增删改 我们使用executeUpdate 返回的是行数
        System.out.println(count>0?"添加成功":"添加失败");
        //5释放资源
        pst.close();
        connection.close();
    }
}

  • 添加操作使用的执行方法的executeUpdate(),返回值是对数据库影响的行数

修改操作

package com.lsc.jdbc;

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

/**
 * 添加操作
 */
public class Demo3 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        Class.forName("org.gjt.mm.mysql.Driver");
        String url="jdbc:mysql://localhost:3306/fruitdb?characterEncoding=utf8&useSSL=false";
        String user="root";
        String pwd="******";
        Connection connection= DriverManager.getConnection(url,user,pwd);
        //编写sql语句
        String sql = "update t_fruit set fname = ? , remark = ? where fid = ? " ;
        PreparedStatement ps=connection.prepareStatement(sql);
        Fruit fruit=new Fruit(33,"猕猴桃","这是一个猕猴桃");
        ps.setString(1,fruit.getFname());
        ps.setString(2,fruit.getRemark());
        ps.setInt(3,fruit.getFid());
        int count=ps.executeUpdate();
        System.out.println(count>0?"修改成功":"修改失败");
        //5释放资源
        ps.close();
        connection.close();
    }
}

  • 修改操作使用的执行方法的executeUpdate(),返回值是对数据库影响的行数

删除操作

/**
 * 删除操作
 */
public class Demo4 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        Class.forName("org.gjt.mm.mysql.Driver");
        String url="jdbc:mysql://localhost:3306/fruitdb?characterEncoding=utf8&useSSL=false";
        String user="root";
        String pwd="*****";
        Connection connection= DriverManager.getConnection(url,user,pwd);
        //编写sql语句
        String sql = "delete  from t_fruit where fid= ?" ;
        PreparedStatement ps=connection.prepareStatement(sql);
        Fruit fruit=new Fruit(33,"猕猴桃","这是一个猕猴桃");
        ps.setInt(1,fruit.getFid());
        int count=ps.executeUpdate();
        System.out.println(count>0?"修改成功":"修改失败");
        //5释放资源
        ps.close();
        connection.close();
    }
}

  • 删除操作使用的执行方法的executeUpdate(),返回值是对数据库影响的行数

查询操作

/**
 * 查询操作
 */
public class Demo5 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        Class.forName("org.gjt.mm.mysql.Driver");
        String url="jdbc:mysql://localhost:3306/fruitdb?characterEncoding=utf8&useSSL=false";
        String user="root";
        String pwd="*****";
        //获得连接
        Connection connection= DriverManager.getConnection(url,user,pwd);
        //编写sql语句
        String sql="select * from t_fruit";
        //获取预处理对象
        PreparedStatement ps=connection.prepareStatement(sql);
        //获得结果集
        ResultSet rs= ps.executeQuery();
        //解析结果集
        while (rs.next()){
            int fid=rs.getInt("fid");
            String fname=rs.getString("fname");
            int price=rs.getInt("price");
            int fcount=rs.getInt("fcount");
            String remark=rs.getString("remark");
            Fruit fruit=new Fruit(fid,fname,price,fcount,remark);
            System.out.println(fruit);
        }
        //7.释放资源
        rs.close();
        ps.close();
        connection.close();
    }
}

  • 查询操作使用的执行方法的executeQuery(),返回值是我们的ResultSet,里面存储着我们的数据

image-20221208211146786

  • 我们返回的ResultSet相当于这个橙色的箭头,next一下,箭头就会往下滑动,如果到头了,就会返回false

JDBC使用的步骤

  1. 导入相关数据库的jar包到我们的项目中

  2. 加载JDBC驱动程序

     Class.forName("org.gjt.mm.mysql.Driver");
    
  3. 获取数据库的连接

    String url="jdbc:mysql://localhost:3306/fruitdb?characterEncoding=utf8&useSSL=false";
    String user="root";
    String pwd="******";
    Connection connection= DriverManager.getConnection(url,user,pwd);
    
  4. 编写我们的SQL语句

  5. 获取预处理对象

    // 查询操作
    preparedStatement.executeQuery(sql);
    // 新增、修改、删除操作
    preparedStatement.executeUpdate(sql);
    
  6. 获得结果并处理

    // 新增、修改、删除操作 返回的是一个整数
    // 查询操作 返回的是ResultSet对象
    while (resultSet.next()) {
    	int xxx = resultSet.getInt("xxx");
    	String yyy= resultSet.getString("yyy");
    	...
    }
    
  7. 关闭资源

    try {
    	if(resultSet != null){
    		resultSet.close();
    	}
    	if(preparedStatement != null){
    		preparedStatement.close();
    	}
    	if(connection != null){
    		connection.close();
    	}
    } catch (SQLException e) {
    	e.printStackTrace();
    	throw new RuntimeException("数据库错误");
    }
    

JDBC的批处理操作

/**
 * 实现JDBC的批处理添加操作
 */
public class Demo1Batch {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        Class.forName("com.mysql.jdbc.Driver");
        //批处理操作1 如果要进行批处理任务,URL需要添加一个参数rewriteBatchedStatements=true
        String url="jdbc:mysql://localhost:3306/fruitdb?characterEncoding=utf8&useSSL=false&rewriteBatchedStatements=true";
        String user="root";
        String pwd="*****";
        Connection connection= DriverManager.getConnection(url,user,pwd);
        //1编写sql语句
        String sql="insert into t_fruit values(0,?,?,?,?)";
        //2创建预处理命令对象
        PreparedStatement pst=connection.prepareStatement(sql);
        //3批处理填充参数
        for(int i=0;i<10;i++){
            pst.setString(1,"批处理水果"+i);
            pst.setInt(2,15);
            pst.setInt(3,100);
            pst.setString(4,"这是批处理水果");
            //批处理操作2 addBatch()
            pst.addBatch();
            //如果批处理的次数太多,进行清空一次队列再进行
            if(i%1000==0){
                pst.executeBatch();
                pst.clearBatch();
            }
        }

        //批处理执行操作3
        int [] count=pst.executeBatch();
        for (int i: count) {
            System.out.println(i);
        }
        //5释放资源
        pst.close();
        connection.close();
    }
}

  • 对于我们的批处理操作,我们的url必须要配置这个参数rewriteBatchedStatements=true
  • 利用循环给我们的批处理去填充参数 addBatch()
  • 进行执行批处理操作 executeBatch()

JDBC数据源连接池

先导入对应连接池的jar包

在这里插入图片描述

package com.lsc.jdbc;

import com.alibaba.druid.pool.DruidDataSource;

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

//验证连接池中的connection可以重复使用
public class Demo02Druid {
    public static void main(String[] args) throws SQLException, SQLException {

        DruidDataSource dataSource = new DruidDataSource();

        dataSource.setDriverClassName("org.gjt.mm.mysql.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/fruitdb?useSSL=false&useUnicode=true&characterEncoding=utf-8");
        dataSource.setUsername("root");
        dataSource.setPassword("123456");

        //证明两点:
        //1. 被close的连接对象并没有真正关闭,而是将状态重新设置为空闲状态,然后放回池子,这样下次获取连接对象,这个对象会被重复使用
        //2. 没有close的连接对象会被一直占用,那么下次继续获取连接对象,是不会获取到这个对象的(hashcode没有重复,只出现一次)
        for(int i = 0 ; i<5 ; i++){
            Connection conn1 = dataSource.getConnection();
            Connection conn2 = dataSource.getConnection();

            System.out.println(conn1);
            System.out.println(conn2);

            if(i%3==0){
                conn1.close();
                conn2.close();
            }
        }
    }
}
//输出结果
1com.mysql.jdbc.JDBC4Connection@2957fcb0
2com.mysql.jdbc.JDBC4Connection@1376c05c
    
3com.mysql.jdbc.JDBC4Connection@1376c05c
4com.mysql.jdbc.JDBC4Connection@2957fcb0
    
com.mysql.jdbc.JDBC4Connection@51521cc1
com.mysql.jdbc.JDBC4Connection@1b4fb997
    
com.mysql.jdbc.JDBC4Connection@deb6432
com.mysql.jdbc.JDBC4Connection@28ba21f3
    
com.mysql.jdbc.JDBC4Connection@28ba21f3
com.mysql.jdbc.JDBC4Connection@deb6432


  • 我们通过结果可以发现1和4的数据源是一样的
    • 被close的连接对象并没有真正关闭,而是将状态重新设置为空闲状态,然后放回池子,这样下次获取连接对象,这个对象会被重复使用
    • 没有close的连接对象会被一直占用,那么下次继续获取连接对象,是不会获取到这个对象的(hashcode没有重复,只出现一次)

两种方式

DateSource方式(实际都是使用这种)

  • 在内部创建Connection对象的连接池,池就是为了资源重复利用,当一个Connection对象调用close方法关闭不是真正关闭,这个对象会被DateSource回收,进入连接池,若此时有别的用户需要建立连接,不是创建一个新的连接,若此时连接池中有空闲连接,直接使用此链接,也就是不需要关闭物理连接,只重置,重置初始化后放入线程池
  • 市面上有不同的连接池实现方式

DriverMannger方式

  • DriverManager 类来获取的 Connection 连接,是无法重复利用的,每次使用完以后释放资源时,通过 connection.close() 都是关闭物理连接。

关于执行sql语句的对象

Statement

  • 用于执行不带参数的简单SQL语句 比如select * from p

PreparedStatement——预处理对象

  1. 用于执行带或者不带参数的SQL语句
    • 可以使用占位符 ? 下标从1开始
  2. SQL语句会预编译在数据库系统
  3. 执行速度快于Statement对象
    • 这个sql语句就会保存到mysql系统中,这个SQL语句的语法和词法分析都已经执行过了,下一次使用时候,只是简单的替换内容即可
//编写sql语句
String sql="select * from t_fruit";
//获取预处理对象
PreparedStatement ps=connection.prepareStatement(sql);
//获得结果集
ResultSet rs= ps.executeQuery();
  • 比statement更加安全,可以阻止常见的sql注入攻击
public class Demo06 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        Class.forName("com.mysql.jdbc.Driver");
 
  Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/fruitdb?				    useSSL=false&useUnicode=true&characterEncoding=utf-8","root","123456");
        //String fname = "西瓜";
        String fname = "西瓜' or 1=1 or fname='";
        String sql = "select * from t_fruit where fname = '" + fname +"'";

        System.out.println(sql);

        Statement stmt = conn.createStatement() ;
        ResultSet rs = stmt.executeQuery(sql);

        while(rs.next()){
            System.out.println(rs.getInt(1));
            System.out.println(rs.getString("fname"));
            System.out.println(rs.getInt(3));
            System.out.println(rs.getInt("fcount"));
            System.out.println(rs.getString("remark"));
        }
    }
}
//我们这个sql语句就把所有的信息都查出来,因为1=1是恒成立的

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/93415.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

靶向药物丨艾美捷西妥昔单抗Cetuximab方案

西妥昔单抗Cetuximab基本信息&#xff1a; 中文名 西妥昔单抗 英文名 Cetuximab 别名 西妥昔单抗 EGFR抑制剂 西妥昔单抗对照品 6-二氨基庚二酸 英文别名 IMC 225 Hsdb 7454 CETUXIMAB EGFR antibody CetuxiMab(C225) Cetuximab - Buffer solution CAS 205923-56-…

【图像增强】暗通道图像去雾【含GUI Matlab源码 740期】

⛄一、简介 1 暗通道先验图像去雾方法 1.1 光线透射率模型 光在传播中由于散射使得从光源发出的辐射只有部分能到达接收传感器&#xff0c;其他则被散射到传播介质中。假设距离较小时散射光强与距离是线性关系&#xff0c;当光源距离传感器无限接近时&#xff0c;光的衰减值可…

定期执行命令、脚本之Linux

在linux下&#xff0c;如果想要在未来的某个时刻执行某个任务&#xff0c;并且在未来的每一个这样的时刻里都要执行这个任务&#xff0c;举个简单的例子&#xff0c;比如说想要在将来&#xff0c;每天的十二点都重启路由器&#xff0c;大多数发行版都自带一个守护进程&#xff…

【敏捷转型,效能提升】万字长文敏捷转型实践系列分享

作者&#xff1a;王先科、田野、王锁、刘双、马越、刘思琪 摘要&#xff1a;本文总结了近4年以来部门实施敏捷转型的实践及经验教训&#xff0c;从5个方面进行了阐述&#xff1a; 1. 文化建设下好先手棋 2. 持续敏捷实践祭出连环招 3. 沉淀实践指引把牢定盘星 4. 效能度量…

英飞凌-AURIX-TC3XX-内核架构:AURIX TriCore 1.6P

目录英飞凌-AURIX-TC3XX-内核架构&#xff1a;AURIX TriCore 1.6P1、AURIX TC1.6P内核简介及特点2、AURIX TC1.6P系统组成及框架2.1、AURIX TC1.6P CPU 具体实现图如下&#xff1a;2.2、AURIX TC1.6P CPU 系统框架2.2.1、指令获取单元- Instruction Fetch Unit2.2.2、执行单元-…

SpringSession+Redis实现【分布式Session】

1. 什么是Spring Session SpringBoot整合Spring-Session的自动配置可谓是开箱即用&#xff0c;极其简洁和方便。这篇文章即介绍SpringBoot整合Spring-Session&#xff0c;这里只介绍基于RedisSession的实战。 Spring Session 是Spring家族中的一个子项目&#xff0c;Spring S…

公务员考试要求及流程梳理

背景 虽然我不考, 但考公这么热门, 在信息层面不能落伍. 本文以 浙江2023省考 (考试时间在2022年12月) 为例, 主要梳理 怎么报名, 选职位, 考试科目与题型, 录用流程等. 为什么考公/考编这么热 因为当下的社会环境对员工太不友好了: 工作强度大, 精神压力大, 还有硬性比例淘…

频率调优(调频)

文章目录 前言 1 频率调优步骤 1.1 准备工作 1.2 串行模式微调 1.3 PPM模式微调 2 高级用户 前言 某些协议需要调优以获得最佳性能。在某些情况下&#xff0c;需要调优才能绑定协议。频率调优是每个 MULTI 模块所特有的&#xff0c;是由于射频组件的微小变化引起的。 &#xf…

物联网通信技术 第6章 电信网络

6.5 多网融合 从通信网络来讲&#xff0c;多网融合主要是指固定网络、移动网络、互联网、广电网融合于一体&#xff0c;满足通信业务融合、网络融合、终端融合、产业融合的需求。 “多网融合”技术有两个层面的含义&#xff0c;一是基于IP协议的控制网与信息网的“接入融合”…

电巢:千亿美金砸向半导体,印度能否实现“赶中超美”的野心?

前言 印度&#xff0c;又一次开始向半导体产业进军。 近日&#xff0c;印度最大集团公司塔塔集团&#xff08;Tata Group&#xff09;旗下子公司塔塔之子董事长纳塔拉詹钱德拉塞卡兰(Natarajan Chandrasekaran)&#xff0c;在接受媒体采访时表示&#xff0c;塔塔集团将开始在印…

戴尔电脑录屏怎么录?这3个方法,教你轻松录屏

随着互联网的发展&#xff0c;电脑已经成为我们学习、工作和娱乐中不可或缺的工具。很多人在使用戴尔电脑的时候&#xff0c;经常会遇到需要进行录屏的情况。戴尔电脑录屏怎么录&#xff1f;小伙伴还在担心自己不会使用戴尔电脑录屏而烦恼吗&#xff1f;今天小编给大家带来了3个…

DVWA靶场安装

DVWA靶场安装1.环境准备2.安装步骤2.1.phpstudy安装2.2.DVWA安装2.2.1.下载DVWA2.2.2.解压DVWA2.2.3.放入服务器2.2.4.删除配置文件后缀2.2.5.修改配置文件2.2.6.访问DVWA2.2.7.报错修改2.2.8.修改php.ini2.2.9.重新访问DVWA2.2.10.登录DVWA3.修改过关等级1.环境准备 服务器环境…

redux与vuex异同以及使用

一. 概述 React与Vue是我们熟悉的两大前端主流框架&#xff0c;来自官方的解释,Vue是一套用于构建用户界面的渐进式框架,React是一个用于构建用户界面的JavaScript库,两个框架都使用各自的语法&#xff0c;专注于用户UI界面的构建.那我们会有疑问&#xff0c;这两个框架都专注于…

PAG动画研究

阅读文章大约需要6分钟 一、什么是PAG 官方定义&#xff1a;PAG&#xff08;Portable Animated Graphics&#xff09; 是一套完整的动画工作流。提供从AE导出插件&#xff0c;到桌面预览工具PAGViewer&#xff0c;再到各端的跨平台渲染 SDK。 二、PAG的优势 1、动画文件小&a…

[附源码]Python计算机毕业设计工程车辆动力电池管理系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

【DevOps实战系列】第四章:详解Jenkins搭建及使用

个人亲自录制全套DevOps系列实战教程 &#xff1a;手把手教你玩转DevOps全栈技术 Jenkins概述 根据jenkins官网对自己的描述&#xff0c;它是一个可集成有1800插件的自动化服务&#xff0c; 提供构建、部署和自动化的工程&#xff0c;可以说是opsdev的大总管&#xff0c;将开发…

zabbix部署+报警模块+图形模块+管理模块+添加监控模板

目录 安装zabbix 部署zabbix 配置zabbix 1. 修改语言 2. 监控linux端 3. 修改中文乱码 报警功能 报警音报警 邮件报警 脚本报警 邮件通知内容 图形模块 创建图形 创建聚合图形 percona mysql模板 nginx模板 克隆主机 网络发现 自动注册 主被动模式 &#x1f341;如果对你有帮助…

Vue + Element-ui实现后台管理系统---项目搭建 + ⾸⻚布局实现

目录&#xff1a;导读 项目搭建 ⾸⻚布局实现 一、项目搭建 1、环境搭建 2、项目初期搭建 二、Main.vue 三、左侧栏部分(CommonAside.vue) 四、header部分(CommonHeader.vue) 五、Home.vue 写在最后 项目搭建 ⾸⻚布局实现 这篇主要讲解 项目搭建 后台⾸⻚布局实现…

Oracle项目管理之设施与资产管理Facilities and Asset(中文)

目录 维护管理 独立或集成 设施状况评估 空间管理 租赁管理 交易管理 资产组合管理 投资组合管理能力 可持续性和能源管理 单一综合设施和资产生命周期管理 Oracle Primavera Unifier 设施与资产管理是一个功能强大且易于使用的解决方案&#xff0c;用于管理您的财产…

第九章服务器内部转发和客户端重定向

文章目录为什么需要转发和重定向服务器内部转发客户端重定向重定向的相关的状态码对比转发和重定向的应用场景为什么需要转发和重定向 发一个请求给Servlet&#xff0c;接力棒就传递到了Servlet手中。而绝大部分情况下&#xff0c;Servlet不能独自完成一切&#xff0c;需要把接…