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

JDBC组件

JDBC

1.为什么需要学习JDBC

之前存储数据使用序列化方式,缺点不适合做大量数据的存储,所以如果是大量数据,推荐使用数据库,所以需要学习Java如何和数据库进行交互的技术,这个也是JDBC的作用

2.什么是JDBC

JDBC(Java database connection):是Java数据库连接的简称,是Java EE的一个核心组件,是一种用于执行SQL语句的一套完整API,它里面提供了一个完整的类和接口,这些接口和类定义了访问数据库的规则,但是具体要实现哪种数据库,必须要得到数据库厂商的许可(数据库驱动包,jar包

3.JDBC涉及到的类和接口 — 笔试题(选择题)

  • DriverManager:驱动管理类,用于加载驱动包的信息,可以创建数据库连接
  • Connection:数据库连接,负责和数据库进行交互,还负责创建Statement对象
  • Statement:用于执行SQL语句(增、删、改、查)
  • ResultSet:只有查询语句会返回结果集对象,负责保存查询语句查询出来的内容

在这里插入图片描述

4.JDBC使用步骤 — 面试题

  • 加载驱动类(前提:需要先导入好驱动包)
  • 通过DriverManager管理驱动类,创建数据库连接
  • 通过连接对象,创建Statement对象(核心对象)
  • 通过Statement对象去执行SQL语句
    • 如果是查询语句,通常会返回ResultSet对象,需要处理结果集
  • 关闭资源
public static void select() throws SQLException, ClassNotFoundException {//1.加载驱动类(前提要导入驱动包) -- 依赖于反射//mysql 8:com.mysql.cj.jdbc.DriverClass.forName(driver);//2.DriverManager管理驱动类,用于创建连接//url:请求地址,也叫统一资源定位符//完整版如下:协议://IP地址:端口号/项目资源(数据库名)?参数名=参数值 & 参数2=值2//MySQL协议:jdbc:mysql://localhost:3306/sc250601_wy?可选参数//常用可选参数://1.useUnicode:表示是否使用Unicode编码进行存储//2.characterEncoding:修改字符集编码(防止中文乱码)//3.autoReconnect:是否自动连接//4.rewriteBatchedStatement:是否开启批处理(一口气新增多条数据)//5.serverTimezone:设置时区 不是必选的 看数据库和系统的时间是否有差异 			serverTimezone=Asia/Shanghai//6.useSSL: 是否使用SSL协议 不是必选的Connection conn = DriverManager.getConnection(url,username,password);System.out.println("连接成功:"+conn);//3.通过连接对象 创建Statement对象Statement stmt = conn.createStatement();//4.通过Statement对象执行SQL语句//① execute():用于执行增删改查语句,返回值是boolean,无法查看查询的数据 不推荐//② executeUpdate():用于执行增删改语句,返回值是int(受影响的行数) 推荐使用//③ executeQuery():用于执行查询语句,返回ResultSet 推荐使用//④ executeBatch():执行批处理(比如:新增100条数据)//在执行前需要结合addBatch() 添加批处理 看需求使用String sql = "select * from jdbcUser";ResultSet rs = stmt.executeQuery(sql);//5.只用查询语句会有结果集返回 需要处理结果集//处理方式类似于迭代器//rs.next()等价于迭代器的hasNext(),表示每次获取一行数据,初始值是指向第一行之前(默认0)while(rs.next()){ //循环一次获取了一行数据//每次循环还需要把这一行数据的每个字段的值取出来//rs.getXXX(),获取每行数据的每个字段 根据类型决定//rs.getInt() rs.getString() rs.getDate() rs.getDouble()//rs.getXXX(数值):根据你查询的结果的第几个字段获取数据 不推荐 不适合复杂查询//rs.getXXX(字符串): 根据表中的字段名称(别名),来获取每个字段的值 推荐使用Integer id = rs.getInt(1);String name = rs.getString("name");double money = rs.getDouble("money");Date time = rs.getDate("birthday");//看需求,如果要打印直接使用,如果要给其他人用,通过集合把这些数据封装起来System.out.println(id+"\t"+name+"\t"+money+"\t"+time);}//6.释放资源(先创建的最后关,满足栈的规则)rs.close();stmt.close();conn.close();
}

5.SQL注入 — 高频面试题

SQL注入:一般是前端可以传递些非法参数,最后通过字符串拼接的方式来处理SQL语句,最终执行SQL语句的时候,可能执行的效果不会按照程序员的预期执行,达到了欺骗服务器的目的,比如:delete from 表 where name = ‘任意字符串’ or 1=1 这里的or 1=1 就是非法参数,就会造成明明只是删除一条,最后删除全部数据

//合法删除
String name = "eee"; //后期前端提交的数据
//存在SQL注入的非法删除
String name = " ddd' or '1'='1";
delete(name);
5.1 解决方案(预编译)

使用预编译对象PreparedStatement来解决,它会先编译SQL语句,目的是让SQL语句的结构是固定的,并且SQL语句的参数是通过?做占位符进行编写,同时还可以实现一次编译多次运行,执行效率也会稍微高些

public static void main(String[] args) throws ClassNotFoundException, SQLException {//insert();//合法删除//String name = "bbb"; //后期前端提交的数据//存在SQL注入的非法删除String name = " ddd' or '1'='1";delete2(name);
}
public static void delete2(String name) throws SQLException, ClassNotFoundException {Class.forName(driver);Connection conn = DriverManager.getConnection(url,username,password);//预编译对象要先传入SQL语句,对它进行编译String sql = "delete from jdbcUser where name=?";//insert into 表 values(null,?,?,?...);PreparedStatement pstmt = conn.prepareStatement(sql);//?做占位符 执行语句前,还需要给?赋值//pstmt.set类型(整数(给第几个?赋值),数据(给?赋值))pstmt.setString(1, name);int i = pstmt.executeUpdate(); //不能传SQL语句System.out.println("删除了:"+i+"条");pstmt.close();conn.close();
}
5.2 PreparedStatement和Statement区别 — 面试题
5.3 mybatis中 #{} 和 ${} 区别 — 面试题
  • ${}:底层是通过Statement实现的,是通过字符串拼接的方式来处理参数,会存在SQL注入的隐患一般用于编写表名或字段名这种不需要预编译的数据
  • #{}:底层是通过PreparedStatement实现的,是预编译对象,要先编译SQL语句,多次运行执行效率高于Statement,是采用?作为占位符来处理参数,可以防止SQL注入,比较安全,大部分都会使用这种方式来执行SQL语句

6.JDBC工具类封装

package util;import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;//jdbc工具类:把jdbc代码提取出来统一处理
public class Jdbcs {//四个属性经常修改,但是经常修改的部分Java规范是不推荐把这些内容放入Java代码直接编写的//而是把他们单独提出来形成一个文件(配置文件)//配置文件:xml properties yml ...private static String driver;private static String url;private static String username;private static String password;static { //会在类加载执行一次 非常适合读取配置文件...//通过当前类的类加载器获取本地文件生成IO流InputStream is = Jdbcs.class.getClassLoader().getResourceAsStream("config/jdbc.properties");Properties prop = new Properties();try {prop.load(is); //读取properties文件给prop对象赋值//String value = prop.getProperty("key")driver = prop.getProperty("driver");url = prop.getProperty("url");username = prop.getProperty("username");password = prop.getProperty("password");Class.forName(driver);} catch (IOException | ClassNotFoundException e) {throw new RuntimeException(e);}}//获取连接的通用方法public static Connection getConnection() {Connection conn;try {conn = DriverManager.getConnection(url,username,password);} catch (SQLException e) {throw new RuntimeException(e);}return conn;}//关闭资源的通用方法 可变长参数... 类型不同(AutoCloseable)//bug: 传参的顺序就是以后关闭的顺序(先创建后关闭)public static void close(AutoCloseable ... o) {for (AutoCloseable ac : o) {try {if (ac != null) ac.close();} catch (Exception e) {throw new RuntimeException(e);}}}//增删改的通用方法//bug: SQL语句参数的顺序和个数必须和sql语句中的?一一对应public static int update(String sql, Object ... o) {Connection conn = null;PreparedStatement ps = null;int result;try {conn = getConnection();ps = conn.prepareStatement(sql);if (o != null) { //判断是否有参数for (int i = 0; i < o.length; i++) {ps.setObject(i + 1, o[i]);}}result = ps.executeUpdate();} catch (SQLException e) {throw new RuntimeException(e);} finally {close(ps,conn);}return result;}//查询的半通用方法public static Connection conn;public static PreparedStatement ps;public static ResultSet select(String sql, Object ... o) {ResultSet rs;try {conn = getConnection();ps = conn.prepareStatement(sql);if (o != null) {for (int i = 0; i < o.length; i++) {ps.setObject(i+1,o[i]);}}rs = ps.executeQuery();} catch (SQLException e) {throw new RuntimeException(e);}//不能关闭 如果关闭了 外面就无法使用rs处理结果集return rs;}
}

7.JDBC如何做事务管理 — 面试题

JDBC做事务类似于MySQL数据库,都是自动提交事务的,如果想自己实现事务,需要手动提交,JDBC本身是通过Connection对象来完成事务操作的,实现步骤如下:

  • conn.setAutoCommit(false):设置手动提交
  • 如果没有发生异常 conn.commit() 提交事务
  • 如果出现异常 conn.rollback() 回滚事务

8.什么是ThreadLocal — 面试题

ThreadLocal是Java中的一个特殊的类,用于在多线程的环境下维护线程的局部变量,一般情况下如果多个线程共享同一个变量,可能引发线程安全的问题,而ThreadLocal可以为每个线程提供一个独立的变量副本,每个线程都可以独立的修改这个副本,不会影响到其他线程对象的副本,适合在多线程下共享资源时使用,比如:存储数据库连接,Session会话管理…常用方法如下:

  • set():设置当前线程的变量副本
  • get():获取当前线程的变量副本
    readLocal — 面试题

ThreadLocal是Java中的一个特殊的类,用于在多线程的环境下维护线程的局部变量,一般情况下如果多个线程共享同一个变量,可能引发线程安全的问题,而ThreadLocal可以为每个线程提供一个独立的变量副本,每个线程都可以独立的修改这个副本,不会影响到其他线程对象的副本,适合在多线程下共享资源时使用,比如:存储数据库连接,Session会话管理…常用方法如下:

  • set():设置当前线程的变量副本
  • get():获取当前线程的变量副本
  • remove():清除当前线程的变量副本
http://www.dtcms.com/a/394650.html

相关文章:

  • StandardScaler,MinMaxScaler等四个内置归一化函数学习
  • pandawiki 无法获取模型列表
  • openEuler2403安装宝塔面板
  • Altium Designer(AD) PCB铺铜
  • 解决Django长时间操作中的MySQL连接超时问题
  • 样本量估计原理与python代码实现
  • 0v0.pro 深度评测、 AI 助手篇、80+模型 free
  • ego(9)---ego-planner中的动力学仿真
  • 2025年9月第3周AI资讯
  • ETL详解:从核心流程到典型应用场景
  • SQL查询基础常用攻略
  • 数据结构二叉树(C语言)
  • Domain、BO、BIZ 三层的协作关系
  • 【从小白到精通之数据库篇】Mysql--连接与子查询
  • C++ 函数详解:从基础到高级应用
  • HTML打包的EXE程序无法关闭?
  • openEuler2403安装Ollama
  • 苍穹外卖项目实战(day11-1)-记录实战教程、问题的解决方法以及完整代码
  • 【Linux命令从入门到精通系列指南】mv 命令详解:文件与目录移动、重命名及安全操作的终极实战手册
  • 【C语言】深入解析阶乘求和算法:从代码实现到数学原理
  • 图形库的基础--svg
  • 令牌桶算法
  • FPGA开发环境配置
  • 特别分享:怎么用coze搭建智能体?
  • Linux 管道
  • NumPy 系列(四):numpy 数组的变形
  • 【Zod 】数据校验新范式:Zod 在 TypeScript 项目中的实战指南
  • 「React实战面试题」useEffect依赖数组的常见陷阱
  • 系统架构设计师部分计算题解析
  • 3.1 BP神经网络结构(反向传播算法)