当前位置: 首页 > news >正文

BCSP-玄子JAVA开发之JAVA数据库编程CH-08_JDBC

BCSP-玄子JAVA开发之JAVA数据库编程CH-08_JDBC

8.1 JDBC 介绍

8.1.1 什么是 JDBC

JDBC(Java Database Conectivity)

Java数据库连接技术的简称,提供连接各种常用数据库的能力

8.1.2 JDBC 的工作原理

JDBC API

内容:供程序员调用的接口与类,集成在java.sql和javax.sql包中,如

  • DriverManager类
  • Connection接口
  • Statement接口
  • ResultSet接口

DriverManager

  • 作用:管理各种不同的JDBC驱动

JDBC 驱动

  • 提供者:数据库厂商
  • 作用:负责连接各种不同的数据库

8.1.3 JDBC API

JDBC API 主要功能

  • 与数据库建立连接、执行SQL 语句、处理结果

  • DriverManager :依据数据库的不同,管理JDBC驱动

  • Connection :负责连接数据库并担任传送数据的任务

  • Statement :由 Connection 产生、负责执行SQL语句

  • esultSet:负责保存Statement执行后的查询结果

8.2 使用 JDBC 连接数据库

8.2.1 导入 JDBC 驱动 JAR 包

数据库版本:MySQL5.7

MySQL官网下载对应的JDBC驱动JAR包

  • mysql-connector-java-8.0.19.jar

驱动类

  • com.mysql.cj.jdbc.Driver

8.2.2 纯 Java 驱动方式

使用纯Java方式连接数据库

  • 由JDBC驱动直接访问数据库

  • 优点:完全Java代码,快速、跨平台

  • 缺点:访问不同的数据库需要下载专用的JDBC驱动

  • JDBC驱动由数据库厂商提供

8.2.3 JDBC编程模板

try {Class.forName(JDBC驱动类);# 1.加载JDBC驱动 
} catch (ClassNotFoundException e) {//异常输出代码
} //… …
try {Connection con=DriverManager.getConnection(数据连接字符串,数据库用户名,密码);// 2.与数据库建立连接 Statement stmt = con.createStatement();ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM table1;");// 3.发送SQL语句,并得到返回结果 while (rs.next()) {int x = rs.getInt("a");String s = rs.getString("b");float f = rs.getFloat("c");}// 4.处理返回结果 rs.close();stmt.close();   con.close();// 5.释放资源
} //… …

8.2.4 数据库连接字符串

jdbc:数据库://ip:端口/数据库名称[连接参数=参数值]
  • 数据库:表示JDBC连接的目标数据库
  • ip: 表示JDBC所连接的目标数据库地址,如果是本地数据库,可为localhost,即本地主机名
  • 端口:连接数据库的端口号
  • 数据库名称:是目标数据库的名称
  • 连接参数:连接数据库时的参数配置

连接本地MySQL中hospital数据库

jdbc:mysql://localhost:3306/hospital?serverTimezone=GMT-8
// 我国处于东八区,时区设置为GMT-8

8.2.5 Connection 接口

Connection是数据库连接对象的类型

方法作用
Statement createStatement()创建一个Statement对象将SQL语句发送到数据库
PreparedStatement prepareStatement(String sql)创建一个PreparedStatement对象,将参数化的SQL语句发送到数据库
boolean isClosed()查询此Connection对象是否已经被关闭。如果已关闭,则返回true;否则返回false
void close()立即释放此Connection对象的数据库和JDBC资源

8.2.6 连接本地 hospital 数据库

package XaunZiShare;import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;import java.sql.*;public class HospitalConn {private static Logger logger = LogManager.getLogger(HospitalConn.class.getName());public static void main(String[] args) {Connection conn = null;// 1、加载驱动try {Class.forName("com.mysql.cj.jdbc.Driver");} catch (ClassNotFoundException e) {logger.error(e);}try {// 2、建立连接conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/hospital?serverTimezone=UTC","root", "root");System.out.println("数据库连接成功");} catch (SQLException e) {logger.error(e);} finally {// 3、关闭数据库连接try {if (null != conn) {conn.close();System.out.println("数据库连接断开");}} catch (SQLException e) {logger.error(e);}}}
}

8.2.7 常见异常

使用JDBC连接数据库时,经常出现的错误

  • JDBC驱动类的名称书写错误,导致ClassNotFoundException异常
  • 数据连接字符串、数据库用户名、密码错误,导致SQLException异常
  • 数据库操作结束后,没有关闭数据库连接,导致仍旧占有系统资源
  • 关闭数据库连接语句没有放到finally语句块中,导致语句可能没有被执行

8.3 Statement 操作数据库

Java执行数据库操作的一个重要接口,在已经建立数据库连接的基础上,向数据库发送要执行的SQL语句

  • Statement对象:执行不带参数的简单SQL语句
  • PreparedStatement对象:执行带或不带In参数的预编译SQL语句
方法作用
ResultSet executeQuery(String sql)可以执行SQL查询并获取ResultSet对象
int executeUpdate(String sql)可以执行插入、删除、更新的操作,返回值是执行该操作所影响的行数
boolean execute(String sql)可以执行任意SQL语句。如果结果为 ResultSet 对象,则返回 true;如果其为更新计数或者不存在任何结果,则返回false

使用 executeQuery() 和 executeUpdate() 方法都需要啊传入 SQL 语句,因此,需要在 Java 中通过字符串拼接获得 SQL 字符串

8.3.1 Java 的字符串操作

String类

  • 字符串常量一旦声明则不可改变
  • String类对象可以改变,但改变的是其内存地址的指向
  • 使用“+”作为数据的连接操作
  • 不适用频繁修改的字符串操作

StringBuffer类

  • StringBuffer类对象能够被多次修改,且不产生新的未使用对象
  • 使用append()方法进行数据连接
  • 适用于字符串修改操作
  • 是线程安全的,支持并发操作,适合多线程

如果使用StringBuffer 生成了 String 类型字符串,可以通过 toString( ) 方法将其转换为一个 String 对象

  • 需要拼接的字符串
String patientName="李明";
String gender="男";
String birthDate="2010-09-03";
  • 使用+拼接字符串
//使用+拼接字符串
String sql = "insert into patient (patientName,gender,birthDate) values('"+patientName+"','"+gender+"','"+birthDate+"');";
System.out.println(sql);
  • 使用StringBuffer拼接字符串
//使用StringBuffer拼接字符串
StringBuffer sbSql = new StringBuffer("insert into patient (patientName,gender,birthDate)" +"  values('");sbSql.append(patientName+"','");
sbSql.append(gender+"','");
sbSql.append(birthDate+"');");
sql = sbSql.toString();
System.out.println(sql);
  • SQL语句中,字符"'是等效的
  • 但在Java代码中拼接字符串时使用字符'会使代码更加清晰
  • 也不容易出错引号、逗号或括号等符号必须成对出现
  • 可在控制台输出拼接后的字符串,检查SQL语句是否正确

8.3.1 Statement 插入数据

使用Statement接口执行插入数据的操作的方法

  • executeUpdate()方法
  • execute()方法

如果希望得到插入成功的数据行数,可以使用executeUpdate()方法;否则,使用execute()方法

实现步骤

  • 声明Statement变量
  • 创建Statement对象
  • 构造SQL语句
  • 执行数据插入操作
  • 关闭Statement对象
  • 关闭顺序是后创建的对象要先关闭释放资源

演示案例

使用JDBC,向hospital数据库病人表中添加一个新的病人记录关键代码

package XaunZiShare;import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;public class HospitalInsert {private static Logger logger = LogManager.getLogger(HospitalInsert.class.getName());public static void main(String[] args) {Connection conn = null;Statement stmt = null;String name = "张菲";// 姓名String gender = "女";// 性别String birthDate = "1995-02-12";// 出生日期String phoneNum = "13887676500";// 联系电话String email = "fei.zhang@qq.com";//邮箱String password = "909000";//密码String identityNum = "610000199502126100";//身份证号String address = "北京市";//地址// 1、加载驱动try {Class.forName("com.mysql.cj.jdbc.Driver");} catch (ClassNotFoundException e) {logger.error(e);}try {// 2、建立连接conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/hospital?serverTimezone=UTC", "root", "root");// 创建Statement对象stmt = conn.createStatement();//构造SQLStringBuffer sbSql = new StringBuffer("insert into patient (patientName,gender,birthDate,phoneNum,email,password,identityNum,address) values ( '");sbSql.append(name + "','");sbSql.append(gender + "','");sbSql.append(birthDate + "','");sbSql.append(phoneNum + "','");sbSql.append(email + "','");sbSql.append(password + "','");sbSql.append(identityNum + "','");sbSql.append(address + "');");System.out.println(sbSql.toString());//3、执行插入操作stmt.execute(sbSql.toString());} catch (SQLException e) {logger.error(e);} finally {// 4、关闭数据库连接try {if (null != stmt) {stmt.close();}if (null != conn) {conn.close();System.out.println("数据库连接断开");}} catch (SQLException e) {logger.error(e);}}}
}

为了避免可能出现的乱码问题,可将指定数据库连接的编码集为UTF8,多个参数间使用字符&进行分隔

jdbc:mysql://localhost:3306/hospital?serverTimezone=GMT-8&useUnicode=true&characterEncoding=utf-8

8.3.2 Statement 更新数据

  • 使用executeUpdate()方法或execute()方法实现更新数据的操作
  • 使用Statement接口更新数据库中的数据的步骤与插入数据类似

实现步骤

  • 声明Statement变量
  • 创建Statement对象
  • 构造SQL语句
  • 执行数据更新操作
  • 关闭Statement对象

需关注拼接的SQL字符串,以避免出错

演示案例

使用JDBC,将hospital数据库中patientID为13的病人电话更新为13627395833

package XaunZiShare;import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;public class HospitalUpdate {private static Logger logger = LogManager.getLogger(HospitalUpdate.class.getName());public static void main(String[] args) {Connection conn = null;Statement stmt = null;int patientID = 13;// 病人编号String phoneNum = "13627395833";// 联系电话// 1、加载驱动try {Class.forName("com.mysql.cj.jdbc.Driver");} catch (ClassNotFoundException e) {logger.error(e);}try {// 2、建立连接conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/hospital?serverTimezone=UTC", "root", "root");// 创建Statement对象stmt = conn.createStatement();//构造SQLStringBuffer sbSql = new StringBuffer("update patient ");sbSql.append("set phoneNum='" + phoneNum + "' ");sbSql.append("where patientID=" + patientID + ";");System.out.println(sbSql.toString());//3、执行插入更新操作int effectRowNum = stmt.executeUpdate(sbSql.toString());System.out.println("更新数据的行数:" + effectRowNum);} catch (SQLException e) {logger.error(e);} finally {// 4、关闭数据库连接try {if (null != stmt) {stmt.close();}if (null != conn) {conn.close();System.out.println("数据库连接断开");}} catch (SQLException e) {logger.error(e);}}}
}

8.3.3 ResultSet 接口

保存和处理Statement执行后所产生的查询结果

  • 由查询结果组成的一个二维表
  • 每行代表一条记录
  • 每列代表一个字段
方法说明
boolean next()将游标从当前位置向下移动一行
void close()关闭ResultSet 对象
int getInt(int colIndex)以int形式获取结果集当前行指定列号值
int getInt(String colLabel)以int形式获取结果集当前行指定列名值
float getFloat(int colIndex)以float形式获取结果集当前行指定列号值
float getFloat(String colLabel)以float形式获取结果集当前行指定列名值
String getString(int colIndex)以String形式获取结果集当前行指定列号值
String getString(String colLabel)以String形式获取结果集当前行指定列名值
  • 要从中获取数据的列号或列名可作为方法的参数
  • 根据值的类型选择对应的方法

ResultSet 接口 getXxx() 方法

  • 获取当前行中某列的值
  • 要从中获取数据的列号或列名可作为方法的参数
  • 根据值的类型选择对应的方法
int类型       ->   getInt()
float类型    ->   getFloat()
String类型  ->   getString()

假设结果集的第一列为patientID,存储类型为int类型,能够获得该列值的两种方法

//使用列号提取数据
int id = rs.getInt(1);
//使用列名提取数据
int id = rs.getInt("patientID");
  • 列号从1开始计数,与数组下标从0开始计数不同
  • 采用列名来标识列可读性强,且不容易出错

8.3.4 Statement 和 ResultSet 查询数据

使用 JDBC 从 hospital 数据库中查询前3个病人的编号、姓名、性别、住址信息并输出到控制台上

package XaunZiShare;import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;import java.sql.*;public class HospitalQuery {private static Logger logger = LogManager.getLogger(HospitalQuery.class.getName());public static void main(String[] args) {Connection conn = null;Statement stmt = null;ResultSet rs = null;int patientID = 13;// 病人编号String phoneNum = "13627395833";// 联系电话// 1、加载驱动try {Class.forName("com.mysql.cj.jdbc.Driver");} catch (ClassNotFoundException e) {logger.error(e);}try {// 2、建立连接conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/hospital?serverTimezone=UTC", "root", "root");System.out.println("建立连接成功 !");// 创建Statement对象stmt = conn.createStatement();//构造SQLString sql = "select patientID,patientName,gender,address from patient limit 3;";//3、执行查询更新操作rs = stmt.executeQuery(sql);//4、移动指针遍历结果集并输出查询结果while (rs.next()) {System.out.println(rs.getInt("patientID") + "\t" +rs.getString("patientName") + "\t" +rs.getString("gender") + "\t" +rs.getString("address"));}} catch (SQLException e) {logger.error(e);} finally {// 5、关闭数据库连接try {if (null != rs) {rs.close();}if (null != stmt) {stmt.close();}if (null != conn) {conn.close();System.out.println("数据库连接断开");}} catch (SQLException e) {logger.error(e);}}}
}

8.4 PreparedStatement 操作数据库

8.4.1 SQL 注入攻击

通过提交一段SQL代码,执行超出用户访问权限的数据操作称为SQL注入(SQL Injection),SQL注入攻击是应用安全领域的一种常见攻击方式,会造成的数据库安全风险包括:刷库、拖库和撞库等,主要是没有对用户输入数据的合法性进行判断,导致应用程序存在安全隐患

使用JDBC实现医院管理系统用户登录验证功能

package XaunZiShare;import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;import java.sql.*;
import java.util.Scanner;public class HospitalLogin {private static Logger logger = LogManager.getLogger(HospitalLogin.class.getName());public static void main(String[] args) {Connection conn = null;Statement stmt = null;ResultSet rs = null;//根据控制台提示输入用户身份证号和密码Scanner input = new Scanner(System.in);System.out.println("用户登录");System.out.print("请输入身份证号:");String identityNum = input.next();System.out.print("请输入密码:");String password = input.next();// 1、加载驱动try {Class.forName("com.mysql.cj.jdbc.Driver");} catch (ClassNotFoundException e) {logger.error(e);}try {// 2、建立连接conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/hospital?serverTimezone=UTC", "root", "123456");// 创建Statement对象stmt = conn.createStatement();//构造SQLStringBuffer sbSql = new StringBuffer("SELECT patientName FROM patient WHERE ");sbSql.append("password='" + password + "'");sbSql.append(" and identityNum='" + identityNum + "';");//3、执行查询更新操作rs = stmt.executeQuery(sbSql.toString());System.out.println(sbSql.toString());//4、验证用户名和密码if (rs.next()) {System.out.println("欢迎" + rs.getString("patientName") + "登录系统!");} else {System.out.println("密码错误!");}} catch (SQLException e) {logger.error(e);} finally {// 5、关闭数据库连接try {if (null != rs) {rs.close();}if (null != stmt) {stmt.close();}if (null != conn) {conn.close();}} catch (SQLException e) {logger.error(e);}}}
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q7QwIOIY-1680668171434)(./assets/%E6%90%9C%E7%8B%97%E6%88%AA%E5%9B%BE20230404172438.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XJPm8kaF-1680668171437)(./assets/%E6%90%9C%E7%8B%97%E6%88%AA%E5%9B%BE20230404172502.png)]

修改查询结构

8.4.2 PreparedStatement 接口

使用PreparedStatement 接口

  • 继承自 Statement接口
  • 与Statement对象相比,使用更加灵活,更有效率

PreparedStatement接口 (预编译的 SQL 语句)

  • 提高代码可读性和可维护性

  • 提高安全性

  • 提高SQL语句执行的性能

方 法作 用
boolean execute()执行SQL语句,可以是任何SQL语句。如果结果是Result对象,则返回true。如果结果是更新计数或没有结果,则返回false
ResultSet executeQuery()执行SQL查询,返回该查询生成的ResultSet对象
int executeUpdate()执行SQL语句,该语句必须是一个DML语句,比如:INSERT、UPDATE或DELETE语句;或者是无返回内容的SQL语句,比如DDL语句。返回值是执行该操作所影响的行数
void setXxx(int index,xxx x)方法名Xxx和第二个参数的xxx均表示(如int,float,double等)基本数据类型,且两个类型需一致,参数列表中的x表示方法的形式参数。把指定数据类型(xxx)的值x设置给index位置的参数。根据参数类型的不同,常见方法有:setInt(int index,int x) 、setFloat(int index,float x)、setDouble(int index,double x)等
void setObject(int index,Object x)除基本数据类型外,参数类型也可以是Object,可以将Object对象x设置给index位置的参数

8.4.3 PreparedStatement 操作数据

创建PreparedStatement对象

  • 使用Connection接口prepareStatement(String sql)方法创建PreparedStatement对象
  • 需要提前设置该对象将要执行的SQL语句
  • SQL语句可具有一个或多个输入参数

设置输入参数的值

  • 调用setXxx()方法完成参数赋值

执行SQL语句

  • 调用PreparedStatement接口
  • executeQuery()
  • executeUpdate()
  • execute()
  • 方法执行SQL语句

验证用户输入的身份证号和密码

  • 如果通过验证,则输出“欢迎[姓名]登录系统!”的信息;
  • 否则输出“密码错误!”
package XaunZiShare;import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;import java.sql.*;
import java.util.Scanner;public class HospitalLogin {private static Logger logger = LogManager.getLogger(HospitalLogin.class.getName());public static void main(String[] args) {Connection conn = null;PreparedStatement pstmt = null;ResultSet rs = null;//根据控制台提示输入用户身份证号和密码Scanner input = new Scanner(System.in);System.out.println("用户登录");System.out.print("请输入身份证号:");String identityNum = input.next();System.out.print("请输入密码:");String password = input.next();// 1、加载驱动try {Class.forName("com.mysql.cj.jdbc.Driver");} catch (ClassNotFoundException e) {logger.error(e);}try {// 2、建立连接conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/hospital?serverTimezone=UTC", "root", "123456");//3、构造PreparedStatement对象pstmt = conn.prepareStatement("SELECT patientName FROM patient WHERE identityNum=? and password=?");pstmt.setString(1, identityNum);pstmt.setString(2, password);rs = pstmt.executeQuery();//4、验证用户名和密码if (rs.next()) {System.out.println("欢迎" + rs.getString("patientName") + "登录系统!");} else {System.out.println("密码错误!");}} catch (SQLException e) {logger.error(e);} finally {// 5、关闭数据库连接try {if (null != rs) {rs.close();}if (null != pstmt) {pstmt.close();}if (null != conn) {conn.close();}} catch (SQLException e) {logger.error(e);}}}
}

8.4.4 PreparedStatement 的优势

实际开发中,推荐使用PreparedStatement接口执行数据库操作

  • PreparedStatement与Statement接口相比,具有的优势
  • 可读性和可维护性高
  • SQL语句执行性能高
  • 安全性更高
http://www.lryc.cn/news/45708.html

相关文章:

  • 一位程序员将一款开源工具变成了价值75亿美元的帝国
  • tmux | 终端操作软件,解决深度学习中终端相关问题
  • 信号 捕捉
  • sqlserver中判断是否存在的方法
  • 基于Kettle跑批的案例说明
  • 2023 最新版网络安全保姆级自学指南
  • Chapter9.3:线性系统稳定性分析及综合实例
  • EXCEL 在复杂查询时摒弃vlookup() sumif() 等公式,而使用数据透视表的初步学习
  • C 文件读写
  • Linux中实现程序开机自启——将程序配置为系统服务
  • 【洛谷刷题】蓝桥杯专题突破-广度优先搜索-bfs(13)
  • 【新2023Q2模拟题JAVA】华为OD机试 - 总最快检测效率 or 核酸检测效率
  • 基于主成分分析的混音方法
  • Code Two Exchange Crack
  • jQuery.form.js 详细用法_维护老项目使用
  • 【Java】关于你不知道的Java大整数运算之BigInteger类超级好用!!!
  • 运维是不是没有出路了?
  • 【C++笔试强训】第七天
  • mysql binlog 一直追加写,磁盘满了怎么办?
  • 缓存穿透、缓存雪崩、缓存击穿解决方案
  • web + servlet + jdbc mysql 实现简单的表单管理界面
  • Maven 国内镜像仓库
  • day21 ● 530.二叉搜索树的最小绝对差 ● 501.二叉搜索树中的众数 ● 236. 二叉树的最近公共祖先
  • 大学计算机(软件类)专业推荐竞赛 / 证书 官网及赛事相关信息整理
  • Metasploit入门到高级【第九章】
  • JDK之8后: 协程? 虚拟线程!!!
  • 体验 jeecg
  • 投稿指南【NO.13】计算机学会CCF推荐期刊和会议分享(人工智能)
  • 一份sql笔试
  • 交换瓶子