Java - JDBC

Java - JDBC

文章目录

  • Java - JDBC
    • 引言
    • JDBC
      • 1 什么是JDBC
      • 2 MySQL数据库驱动
      • 3 JDBC开发步骤
      • 4 具体介绍

引言

思考:

当下我们如何操作数据库?

  • 使用客户端工具访问数据库,手工建立连接,输入用户名和密码登录。
  • 编写SQL语句,点击执行,查看操作结果(结果集或受影响行数)。

实际开发中,会采用上述方式吗?

  • 不会,因为操作量过大,无法保证效率和正确性。
  • 普通用户不能直接操作客户端工具。

JDBC

1 什么是JDBC

概念:

  • JDBC(Java DataBase Connectivity)Java数据库连接,SUN公司定义的一套连接数据库的规范(标准)。
  • 使用JDBC连接数据库完成CRUD操作。

核心思想:

  • JDBC中定义了访问数据库的接口,可以为多种关系型数据库提供统一的访问方式。
  • 由数据库厂商提供驱动实现类(Driver数据库驱动)。

如图:

在这里插入图片描述

2 MySQL数据库驱动

MySQL数据库驱动包:

  • mysql-connector-java-5.1.X 适用于5.X版本。
  • mysql-connector-java-8.0.X 适用于8.X版本。

JDBC API:

类型全限定名简介
classjava.sql.DriverManager管理多个数据库驱动类,提供了获取数据库连接的方法。
interfacejava.sql.Connection代表一个数据库连接。当connection不是null时,表示已连接数据库。
interfacejava.sql.Statement发送SQL语句到数据库工具。
interfacejava.sql.ResultSet保存SQL查询语句的结果数据(结果集)。
classjava.sql.SQLException处理数据库应用程序时所发生的异常。

3 JDBC开发步骤

开发六步骤:

  • 注册驱动:

  • Class.forName("com.mysql.jdbc.Driver");
    
  • 获取连接:

  • Connection conn = DriverManager.getConnection(url,name,pwd);
    
  • 创建命令对象:

  • Statement statement = conn.createStatement();
    
  • 执行SQL语句:

  • int result = statement.executeUpdate(sql);
    
  • 处理结果:

  • System.out.println(result);
    
  • 释放资源:

  • statement.close();
    conn.close();
    

4 具体介绍

1 DriverManager类

概念:

  • java.sql.DriverManager管理所有数据库的驱动,如果想要建立数据库连接需要先在java.sql.DriverManager中注册对应的驱动类,然后调用getConnection方法才能连接上数据库。

注册驱动:

  • 方法1:(推荐使用)

  • Class.forName("com.mysql.jdbc.Driver");
    
  • 方法2:(不推荐使用)

  • DriverManager.registerDriver(new Driver());
    
  • 原因: 会导致注册两次, 耦合性高;

获取连接:

String url= "jdbc:mysql://localhost:3306/mysql";//连接字符串
String user= "root";//用户名
String password = "root";//密码

//jdbc:mysql	协议
//localhost 	主机名
//3306  	    端口号
//mysql		    数据库名

Connection connection = DriverManager.getConnection(url, user, password);

这样连接后会出现一个警告:

Fri Jan 26 09:35:24 CST 2024 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.

这段警告信息是关于MySQL数据库SSL连接的,其翻译如下:

警告:在未验证服务器身份的情况下建立SSL连接是不推荐的。根据MySQL 5.5.45+、5.6.26+ 和 5.7.6+ 的要求,如果未设置明确选项,则必须默认建立SSL连接。为了兼容不使用SSL的现有应用程序,已将verifyServerCertificate属性设置为’false’。您需要明确通过设置useSSL=false来禁用SSL,或者设置useSSL=true并为服务器证书验证提供truststore。

简单来说,这个警告告诉你,你的MySQL连接没有使用SSL或者没有正确地验证服务器的SSL证书。为了安全起见,你应该考虑启用SSL并提供正确的证书验证,或者如果你确定不需要SSL,你可以明确禁用它。

怎么解决这个问题:

我们采用明确禁止SSL的方式:

更新 url (添加参数):

参数: ?useSSL=false&characterEncoding=utf-8
useSSL=false	明确禁止SSL
characterEncoding=utf-8		设置数据库编码为 UTF-8

url="jdbc:mysql://localhost:3306/mysql?useSSL=false&characterEncoding=utf-8";

2 Connection

概念:

  • Connection接口代表与特定的数据库的连接,要对数据表中的数据进行操作,首先要获取数据库连接,Connection实现就像在应用程序中与数据库之间开通了一条渠道。
方法名说明
createStatement()创建Statement命令对象
prepareStatement(String sql)创建预编译命令对象

3 Statement

概念:

  • 获取连接对象后,可以创建Statement对象,用来执行命令。

语法: Statement stat=连接对象.createStatement();

方法名说明
execute()执行任何SQL语句,一般不用
executeUpdate()执行增删改、创建库、表等
executeQuery()执行查询,返回ResultSet结果集

4 ResultSet

概念:

  • 在执行查询SQL后,存放查询到的结果集数据。

接收结果集:

  • ResultSet rs = statement.executeQuery(sql);

注意:

  • 作用是完成了查询结果的存储功能,默认只能向前读取,不能修改.

遍历ResultSet结果集

  • ResultSet以表结构进行临时结果的存储,通过JDBC API将其中数据进行依次获取
方法名返回值类型描述
next();boolean数据行指针,每调用一次,指针向下移动一行。结果为 true,表示当前行有数据。结果为false,没有数据。
getXxx(编号);xxx代表根据列的编号顺序获得,从 1 开始。
getXxx(“列名”);xxx代表根据列名获得。推荐

**经验:**getXxx方法可以获取的类型有:基本数据类型、引用数据类型

5 常见错误

在这里插入图片描述

6 代码演示

代码演示-1

JDBCDemo1:

public class JDBCDemo1 {
    public static void main(String[] args) throws Exception{
        //1 注册驱动
        Class.forName("com.mysql.jdbc.Driver");
        //2 获取连接
        //url: 连接字符串 jdbc:mysql://localhost:3306/companydb
        //useSSL=false 明确禁用SSL
        //characterEncoding=utf-8 设置字符编码为utf-8
        //user: 用户名
        //password: 密码

        // 定义数据库连接参数
        String url = "jdbc:mysql://localhost:3306/companydb?useSSL=false&characterEncoding=utf-8";
        String username = "root";
        String password = "root";
        Connection connection = null;
        connection = DriverManager.getConnection(url, username, password);

        if (connection != null) {
            System.out.println("连接成功...");
        }
        //3 关闭
        // 关闭数据库连接
        if (connection != null) {
            connection.close();
        }
    }
}

代码演示-2

JDBCDemo2:

public class JDBCDemo2 {
    public static void main(String[] args) throws Exception{
        // 1 注册驱动
        Class.forName("com.mysql.jdbc.Driver");
        // 2 获取连接对象
        // 定义数据库连接参数
        String url = "jdbc:mysql://localhost:3306/companydb?useSSL=false&characterEncoding=utf-8";
        String username = "root";
        String password = "root";
        Connection connection;
        connection = DriverManager.getConnection(url, username, password);
        // 3 创建命令对象
        Statement statement = connection.createStatement();
        // 4 执行命令
        // 4.1 创建数据库
        int count1 = statement.executeUpdate("create database if not exists myschool;");
        // 4.2 切换数据库
        int count2 = statement.executeUpdate("use myschool;");
        // 4.3 创建数据表
        int count3 = statement.executeUpdate("create table if not exists student(stu_id int primary key auto_increment, stu_name varchar(20), stu_age int);");
        // 4.4 添加数据
        int count4 = statement.executeUpdate("insert into student values (null,'张三',18),(null,'李四',19),(null,'王五',20);");
        // 4.5 修改数据
        int count5 = statement.executeUpdate("update student set stu_age = stu_age+5,stu_name='张利' where stu_id=1;");
        // 4.6 删除数据
        int count6 = statement.executeUpdate("delete from student where stu_id=1;");
        // 4.7 删除数据表/数据库
//        statement.executeUpdate("drop table student;");
//        statement.executeUpdate("drop database myschool;");
        // 5 处理
        System.out.println("count1: "+ count1);
        System.out.println("count2: "+ count2);
        System.out.println("count3: "+ count3);
        System.out.println("count4: "+ count4);
        System.out.println("count5: "+ count5);
        System.out.println("count6: "+ count6);
        // 6 关闭资源
        statement.close();
        connection.close();
    }
}

代码演示-3

JDBCDemo3:

public class JDBCDemo3 {
    public static void main(String[] args) throws Exception{
        // 1 注册驱动
        Class.forName("com.mysql.jdbc.Driver");

        // 定义数据库连接参数
        String url = "jdbc:mysql://localhost:3306/companydb?useSSL=false&characterEncoding=utf-8";
        String username = "root";
        String password = "root";

        // 2 获取连接对象
        Connection connection;
        connection = DriverManager.getConnection(url, username, password);

        // 3 创建命令对象
        Statement statement = connection.createStatement();

        // 4 执行命令
        ResultSet resultSet = statement.executeQuery("select * from student;");

        // 5 处理
        while (resultSet.next()) {
            int stuId = resultSet.getInt("stu_id");
            String stuName = resultSet.getString("stu_name");
            int stuAge = resultSet.getInt("stu_age");
            String stuGender = resultSet.getString("stu_gender");
            String stuAddress = resultSet.getString("stu_address");
            Date stuBorn = resultSet.getDate("stu_born");
            System.out.println(stuId+"\t"+stuName+"\t"+stuAge+"\t"+stuGender+"\t"+stuAddress+"\t"+stuBorn);
        }

        // 6 关闭
        resultSet.close();
        statement.close();
        connection.close();
    }
}

代码演示-4

JDBCDemo4:

需求:
创建用户表(user): 字段:user_id,user_name,password,age,phone,email
实现用户登录功能
public class JDBCDemo4 {
    public static void main(String[] args) throws Exception{
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入用户名");
        //回车返回
        String user_name = scanner.nextLine();
        System.out.println("请输入密码");
        //空格返回
        String user_pwd = scanner.next();

        // 1 注册驱动
        Class.forName("com.mysql.jdbc.Driver");

        // 定义数据库连接参数
        String url = "jdbc:mysql://localhost:3306/companydb?useSSL=false&characterEncoding=utf-8";
        String username = "root";
        String password = "root";

        // 2 获取连接对象
        Connection connection;
        connection = DriverManager.getConnection(url, username, password);

        // 3 创建命令对象
        //当在 SQL 中使用字符串时,必须非常小心,确保采取适当的安全措施,以防止 SQL 注入和其他安全威胁。
        String sql = "select * from user where user_name = '" + user_name + "' and password = '" + user_pwd + "'";
        Statement statement = connection.createStatement();

        // 4 执行命令
        //容易受到 SQL 注入攻击
        ResultSet resultSet = statement.executeQuery(sql);

        // 5 处理
        if (resultSet.next()) {
            System.out.println("登录成功...");
        } else {
            System.out.println("登录失败...");
        }

        // 6 关闭
        resultSet.close();
        statement.close();
        connection.close();
    }
}

SQL注入攻击:

请输入用户名
xxxx' or 1=1;#
请输入密码
root
登录成功...

什么是SQL注入攻击?

SQL注入:用户输入的数据中有SQL关键字或语句并且参与了SQL语句的编译,导致SQL语句编译后的条件含义为true,实现欺骗服务器,一直得到正确的结果。这种现象称为SQL注入。

如何避免:

不要使用SQL拼接方式,SQL 语句要在用户输入数据前就已编译成完整的 SQL 语句,再进行填充数据。

PreparedStatement

概念:

  • PreparedStatement继承了Statement接口,执行SQL语句的方法无异。

作用:

  • 预编译SQL语句,效率高。
  • 安全,避免SQL注入。
  • 可以动态的填充数据,执行多次同构的SQL语句。

应用:

  • 预编译SQL语句,数据参数使用?占位:

  • PreparedStatement pstmt = null;
    pstmt = conn.prepareStatement("select * from user where uname=? and pwd=?");
    
  • 为参数下标赋值:

  • pstmt.setString(1,Gavin);
    pstmt.setString(2,123456);
    

注意:

  • JDBC中的所有参数都由 ?符号占位,这被称为参数占位符。
  • 在执行SQL语句之前,必须为每个参数提供值。
  • 当你不知道数据参数的类型是什么时, 可以使用setObject();方法

预编译命令, 预防SQL注入攻击

请输入用户名
xxxx' or 1=1;#
请输入密码
root
登录失败...

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

每日OJ题_算法_前缀和②_牛客DP35 【模板】二维前缀和

目录 二维前缀和原理 ②牛客DP35 【模板】二维前缀和 解析代码 二维前缀和原理 在一维数组前缀和算法的基础上,想到:计算二维数组前缀和,不就和计算一维数组前缀和一样,即计算每一个位置的前缀和就相当于: 此位置的…

微信小程序开发学习笔记《13》WXS脚本

微信小程序开发学习笔记《13》WXS脚本 博主正在学习微信小程序开发,希望记录自己学习过程同时与广大网友共同学习讨论。建议仔细阅读对应官方文档 一、WXS介绍 WXS ( WeiXin Script)是小程序独有的一套脚本语言,结合WXML,可以构建出页面的…

【Java与网络2】:HTTP核心知识与Curl工具

HTTP是当前应用最为广泛的通信协议,我们上网、玩游戏、刷视频、查美食都离不开HTTP协议。当我们做开发的时候, 需要经常和H5、Android、IOS、PC前端等不同团队的同学打交道,大家讨论的核心问题之一就是交互的时候协议怎么定,而这个…

###C语言程序设计-----C语言学习(6)#

前言:感谢老铁的浏览,希望老铁可以一键三连加个关注,您的支持和鼓励是我前进的动力,后续会分享更多学习编程的内容。 一. 主干知识的学习 1. while语句 除了for语句以外,while语句也用于实现循环,而且它…

Android 系统启动流程

依旧是带着问题再去学习 首先,Android是怎么启动的? Android服务是怎么启动的? Android线程是怎么切换的? Android ApplicationThread是怎么创建的? 那么接下来开始分析Android的启动流程 还是一步一图 先画一张流…

day27 回溯算法part3

39. 组合总和 中等 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。 candidates 中的 同一个 数字可以 无限…

外汇天眼:Alpha Group International为股票回购计划拨款高达2,000万英镑

Alpha Group International plc,一家为企业和机构提供金融解决方案的公司,宣布计划启动股票回购程序,以购买每股面值为0.2便士的普通股。 该公司已经从其现金储备中拨款高达2,000万英镑用于回购计划。购买的普通股将被保留在公司的资本中。 …

合并有序链表---链表OJ---归并思想

https://leetcode.cn/problems/merge-two-sorted-lists/?envTypestudy-plan-v2&envIdtop-100-liked 将两个有序的链表合并为一个新的有序链表,那不就是和归并排序中最后合并的思想一样吗?只不过那里合并的是数组,这里合并的是链表。 首先…

数据分析入门指南:用 Python 开启数据之旅

文章目录 前言发现宝藏为什么选择 Python 进行数据分析?准备工作数据分析基础1. 数据加载2. 数据探索3. 数据清洗4. 数据可视化 探索更多可能性好书推荐总结 前言 为了巩固所学的知识,作者尝试着开始发布一些学习笔记类的博客,方便日后回顾。…

小程序直播項目开发流程

点击登录功能,创建IM个人账户 以及 创建直播间群组 第一步:需要获取用户唯一的标识openid。 获取流程如下-点击登录按钮-通过wx.getUserProfile这个Api返回的res.userinfo信息获取用户头像昵称等-再通过wx.login的api获取用户的code-使用code再到服务器换…

【开源】基于JAVA的房屋出售出租系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 房屋销售模块2.2 房屋出租模块2.3 预定意向模块2.4 交易订单模块 三、系统展示四、核心代码4.1 查询房屋求租单4.2 查询卖家的房屋求购单4.3 出租意向预定4.4 出租单支付4.5 查询买家房屋销售交易单 五、免责说明 一、摘…

单片机学习笔记---定时器计数器(含寄存器)工作原理介绍(详解篇1)

目录 51内部定时计数器概述 定时器和计数器概念的区分 定时计数器的结构框图 定时计数器的控制字 M1和M0工作方式选择位的四种工作方式 总结 51内部定时计数器概述 先概述一下,51内部是有两个16位的定时计数器,这个16位指的是它定时计数的常数是1…

4秒读取50w行Excel数据

4秒读取50w行Excel数据 文章比较了几种常用的读取Excel的方法,最终发现rust库Calamine的速度最快,可以在4秒内读取50w行excel数据。 原文:Fastest Way to Read Excel in Python:https://hakibenita.com/fast-excel-python 我们在…

React16源码: React中处理LegacyContext相关的源码实现

LegacyContext 老的 contextAPI 也就是我们使用 childContextTypes 这种声明方式来从父节点为它的子树提供 context 内容的这么一种方式遗留的contextAPI 在 react 17 被彻底移除了,就无法使用了那么为什么要彻底移除这个contextAPI的使用方式呢?因为它…

openGauss学习笔记-209 openGauss 数据库运维-常见故障定位案例-共享内存泄露问题

文章目录 openGauss学习笔记-209 openGauss 数据库运维-常见故障定位案例-共享内存泄露问题209.1 共享内存泄露问题209.1.1 问题现象209.1.2 原因分析209.1.3 处理方法 openGauss学习笔记-209 openGauss 数据库运维-常见故障定位案例-共享内存泄露问题 209.1 共享内存泄露问题…

【Web前端实操18】粘性定位——即固定顶层内容,可以继续滚动,但是顶层内容固定,不随着一起滚动

粘性定位 1、了解 可以被认为是相对定位和固定定位的混合。元素在跨越特定阈值前为相对定位,之后为固定定位。粘性定位是指网页或移动应用程序中的一种特性,即当用户滚动页面时,某个元素能够保持在屏幕上特定位置不动,直到用户滚动到达一定位置或进行特定操作。这个特性可…

Qt无边框窗口拖拽和阴影

先看下效果: 说明 自定义窗口控件的无边框,窗口事件由于没有系统自带边框,无法实现拖拽拉伸等事件的处理,一种方法就是重新重写主窗口的鼠标事件,一种时通过nativeEvent事件处理。重写事件相对繁琐,我们这里推荐nativeEvent处理。注意后续我们在做win平…

2.3_8 多生产者-多消费者问题

2.3_8 多生产者-多消费者问题 实现思路 semaphore mutex1; //实现互斥访问盘子(缓冲区) semaphore apple0; //盘子中有几个苹果 semaphore orange0; //盘子中有几个橘子 semaphore plate 1; //盘子中还可以放多少个水果dad(){while(1){准备一个苹果;P(plate);P(mutex);把苹果放…

网络相关知识

关于作者:CSDN内容合伙人、技术专家, 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 ,擅长java后端、移动开发、商业变现、人工智能等,希望大家多多支持。 目录 一、导读二、概览三、相关工具3.1 network profiler/ In…

休息日的思考与额外题——链表

文章目录 前言链表知识点 一、 92. 反转链表 II二、21. 合并两个有序链表总结 前言 一个本硕双非的小菜鸡,备战24年秋招,计划二刷完卡子哥的刷题计划,加油! 二刷决定精刷了,于是参加了卡子哥的刷题班,训练…