一、JDBC连接数据库的7个步骤

1、加载驱动

2、获取连接

3、编写sql

4、获取执行sql的stmt对象

有两种 stmt(存在sql注入问题 字符串拼接) pstmt(预编译可以防止sql注入)

5、执行sql 拿到结果集

6、遍历结果集

7、关闭资源(按倒序关闭,资源先开的后关,后开的先关)

 主方法程序实例

package com.qcby.dao;import com.qcby.model.Account;
import com.qcby.utils.JdbcUtils;import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JdbcSelect {public static void main(String[] args) {Connection connection =null;Statement statement=null;ResultSet resultSet=null;try {//建立连接connection= JdbcUtils.getConnection();//编写sqlString sql="select * from account";//获取执行sql的statement对象statement=connection.createStatement();//执行sql拿到结果集resultSet=statement.executeQuery(sql);//遍历结果集while (resultSet.next()){Account account=new Account();account.setId(resultSet.getInt("id"));account.setName(resultSet.getString("name"));account.setMoney(resultSet.getDouble("money"));System.out.println(account);}} catch (SQLException e) {e.printStackTrace();}finally {//关闭资源JdbcUtils.close(connection,resultSet,statement);}}}

 二、JDBC工具类的三个版本

上述的7个步骤中可以将加载驱动、获取连接和关闭资源抽取出来从而简化代码。

1.0版本

  • 所有数据库连接信息直接写在代码里(地址、账号密码都固定)
  • 每次要连接数据库时都新建一个连接
  • 用完就直接扔掉,下次再用再新建
package com.qcby.utils;import org.gjt.mm.mysql.Driver;import java.io.InputStream;
import java.sql.*;
import java.util.Properties;//JDBC工具类,减少代码
public class JdbcUtils {//1、加载驱动public static void  createSDriver(){try {//2种 直接调用方法//  DriverManager.registerDriver(new Driver());DriverManager.registerDriver(new Driver());//反射加载//Class.forName(driverclass); // MySQL 8.0+驱动}catch (SQLException e){e.printStackTrace();}}//2、获取连接public  static Connection getConnection(){Connection connection=null;try {//1、加载驱动createSDriver();//2、获取连接connection= DriverManager.getConnection("jdbc:mysql:///spring_db","root","12345");}catch (SQLException e){e.printStackTrace();}return connection;}//3、关闭连接,方法重载public  static  void close(Connection connection, ResultSet resultSet,Statement statement){try {resultSet.close();statement.close();connection.close();} catch (SQLException e) {e.printStackTrace();}}//3、关闭连接public  static  void close(Connection connection,Statement statement){try {statement.close();connection.close();} catch (SQLException e) {e.printStackTrace();}}}

2.0版本

  • 把数据库信息移到单独的配置文件里(db.properties)
  • 想改数据库地址或密码时,不用改代码,改配置文件就行
  • 但还是每次新建连接,用完就扔

 编写properties属性文件,程序就可以读取属性文件

driverclass=com.mysql.jdbc.Driver
url=jdbc:mysql:///spring_db
username=root
password=12345
package com.qcby.utils;import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;public class JdbcUtil3 {private static final String driverclass;private static final String url;private static final String username;private static final String password;static{// 加载属性文件Properties pro = new Properties();InputStream inputStream = JdbcUtil3.class.getResourceAsStream("/db.properties");try {// 加载属性文件pro.load(inputStream);} catch (IOException e) {e.printStackTrace();}// 给常量赋值driverclass = pro.getProperty("driverclass");url = pro.getProperty("url");username = pro.getProperty("username");password = pro.getProperty("password");}/*** 加载驱动*/public static void loadDriver(){try {// 加载驱动类Class.forName(driverclass);} catch (ClassNotFoundException e) {e.printStackTrace();}}/*** 加载完驱动,获取到连接,返回连接对象* @return*/public static Connection getConnection(){// 加载驱动loadDriver();// 获取到连接对象,返回Connection conn = null;try {// 获取到连接conn = DriverManager.getConnection(url,username,password);} catch (SQLException e) {e.printStackTrace();}return conn;}/*** 关闭资源* @param conn* @param stmt* @param rs*/public static void close(Connection conn, Statement stmt, ResultSet rs){if(rs != null){try {rs.close();} catch (SQLException e) {e.printStackTrace();}}if(stmt != null){try {stmt.close();} catch (SQLException e) {e.printStackTrace();}}if(conn != null){try {conn.close();} catch (SQLException e) {e.printStackTrace();}}}/*** 关闭资源* @param conn* @param stmt*/public static void close(Connection conn, Statement stmt){if(stmt != null){try {stmt.close();} catch (SQLException e) {e.printStackTrace();}}if(conn != null){try {conn.close();} catch (SQLException e) {e.printStackTrace();}}}
}

 3.0版本

什么是连接池

连接池技术通过复用数据库连接,显著提升了系统性能。以电商库存系统为例,当100个用户同时购买商品时:

传统方式需要100次连接创建和销毁,消耗大量资源。而使用连接池(如配置10个连接)后:

  1. 系统启动时预先建立10个连接

  2. 前10个请求直接获取现有连接

  3. 使用后连接归还而非销毁

  4. 后续请求复用这些连接

这就像物业管理:

  • 传统方式:每次有访客都现场配钥匙,离开就销毁

  • 连接池方式:预先准备10把钥匙,访客使用后归还

代码 

使用druid.properties配置文件管理连接池参数

连接从连接池获取而非每次新建

  • 使用Druid连接池,预先创建一批连接放着
  • 需要用时直接从池子里拿,用完放回去
  • 可以控制最多准备多少连接、最少留多少
  • 优势:速度快(不用每次都新建)、省资源(连接可以重复用)、还能防漏水(连接泄漏检测)
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///spring_db
username=root
password=12345
initialSize=5
maxActive=10
maxWait=3000
maxIdle=6
minIdle=3
package com.qcby.utils;import com.alibaba.druid.pool.DruidDataSourceFactory;import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;public class JdbcUtils2 {// 连接池对象private static DataSource DATA_SOURCE;static{// 加载属性文件Properties pro = new Properties();InputStream inputStream = JdbcUtils2.class.getResourceAsStream("/druid.properties");try {// 加载属性文件pro.load(inputStream);// 创建连接池对象DATA_SOURCE = DruidDataSourceFactory.createDataSource(pro);} catch (Exception e) {e.printStackTrace();}}/*** 从连接池中获取连接,返回。* @return*/public static Connection getConnection(){Connection conn = null;try {conn = DATA_SOURCE.getConnection();} catch (SQLException e) {e.printStackTrace();}return conn;}/*** 关闭资源* @param conn* @param stmt* @param rs*/public static void close(Connection conn, Statement stmt, ResultSet rs){if(rs != null){try {rs.close();} catch (SQLException e) {e.printStackTrace();}}if(stmt != null){try {stmt.close();} catch (SQLException e) {e.printStackTrace();}}if(conn != null){try {conn.close();} catch (SQLException e) {e.printStackTrace();}}}/*** 关闭资源* @param conn* @param stmt*/public static void close(Connection conn, Statement stmt){if(stmt != null){try {stmt.close();} catch (SQLException e) {e.printStackTrace();}}if(conn != null){try {conn.close();} catch (SQLException e) {e.printStackTrace();}}}
}

 测试

package com.qcby.dao;import com.qcby.model.Account;
import com.qcby.utils.JdbcUtils;import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JdbcSelect {public static void main(String[] args) {Connection connection =null;Statement statement=null;ResultSet resultSet=null;try {//建立连接connection= JdbcUtils.getConnection();//编写sqlString sql="select * from account";//获取执行sql的statement对象statement=connection.createStatement();//执行sql拿到结果集resultSet=statement.executeQuery(sql);//遍历结果集while (resultSet.next()){Account account=new Account();account.setId(resultSet.getInt("id"));account.setName(resultSet.getString("name"));account.setMoney(resultSet.getDouble("money"));System.out.println(account);}} catch (SQLException e) {e.printStackTrace();}finally {JdbcUtils.close(connection,resultSet,statement);}}}

 补充:Sql注入问题

想象你开了一家会员制餐厅:

  • 正常流程:客人报会员名"张三",你查名单确认后放行
  • 注入攻击:客人报会员名"张三' OR '1'='1",你的名单系统会把所有人都放进来!

漏洞是如何产生的 (字符串拼接问题)

String username = "aaa'or'1=1"; // 用户输入
String password = "随便输";
String sql = "SELECT * FROM users WHERE username='"+username+"' AND password='"+password+"'";

实际执行的SQL变成:
 SELECT * FROM users WHERE username='aaa'or'1=1' AND password='随便输'
'1'='1'永远成立,相当于不需要密码

攻击者常用的花招 

1、万能密码

用户名:admin' --

密码:随便

相当于SQL:SELECT * FROM users WHERE username='admin' --' AND password='随便'

--是SQL注释符,后面条件被忽略

2、永远为真:

用户名:aaa'or'1=1

密码:随便

相当于:SELECT * FROM users WHERE username='aaa'or'1=1' AND password='随便'

 如何解决sql注入问题

 使用PreparedStatement

就像改进后的餐厅检查流程:

  1. 提前预定格式:会员名必须是一个完整字符串(预编译)
  2. 严格检查输入:即使用户输入特殊符号,也只当作普通字符

基本格式:

            // 获取到连接对象conn = dataSource.getConnection();// 编写SQL语句String sql = "insert into account values (null,?,?)";// 预编译SQL语句stmt = conn.prepareStatement(sql);// 设置值stmt.setString(1,"eee");stmt.setString(2,"1233");// 执行sqlstmt.executeUpdate();

为什么使用PreparedStatement安全?

注意:

  1. 永远不要拼接SQL:就像不要直接吃陌生人给的糖果
  2. 始终使用PreparedStatement:这是防止SQL注入的最简单有效方法
  3. 即使参数固定也要用:养成良好的编码习惯

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

3.1/Q1,Charls最新文章解读

文章题目:Predictive model for sarcopenia in chronic kidney disease: a nomogram and machine learning approach using CHARLS data DOI:10.3389/fmed.2025.1546988 中文标题:慢性肾病肌肉减少症的预测模型:使用 CHARLS 数据的…

DEEPPOLAR:通过深度学习发明非线性大核极坐标码(2)

目录 2.问题的提出和背景 2.1 信道编码 2.2.极化码 极坐标编码 极坐标解码 原文:《DEEPPOLAR: Inventing Nonlinear Large-Kernel Polar Codes via Deep Learning》 2.问题的提出和背景 2.1 信道编码 信道编码是一种为传输添加冗余的技术,使其对…

手机当电脑播放器 soundwire

soundwire server免费下载_soundwire serverPC下载_3DM软件 win11可用延迟1秒 安卓端音频缓冲区大小改成8k延迟就没那么夸张了 我用audiorelay连上了没声音

LVGL中的事件

文章目录 🧱 一、什么是 LVGL 事件?🎯 二、事件回调的注册参数解释:示例: 📚 三、常见事件类型(lv_event_code_t)✅ 1. 输入类事件(用户交互)✅ 2. 组件状态类…

警惕C#版本差异多线程中的foreach陷阱

警惕C#版本差异多线程中的foreach陷阱​ 同样的代码,不同的结果闭包捕获的“时间差”问题绕过闭包陷阱的三种方法Lambda立即捕获(代码简洁)显式传递参数(兼容性最佳)使用Parallel.ForEach(官方推荐)注意事项:版本兼容性指南警惕多线程中的foreach陷阱:C#版本差异引发的…

mac u盘重装mac10.15Catalina系统

我的电脑提mac2017的air 重装过程 (文件夹中间有空格时为 Install\ macOS\ Catalina 才行) (有需要的,最好做一下备份,有些东西可以及时找到配置和文件之类的, u盘制作是在mac电脑上操作的) 一、先下载系统镜像文件或自行到官方…

说说es配置项的动态静态之分和集群配置更新API

这天因为某件工作来到了es官网某个参数配置相关的页面,注意到了下图圆圈里的“Dynamic”: 链接:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/modules-cluster.html#misc-cluster-settings 显然这是对配置项的一个描述&am…

2025软考【系统架构设计师】:两周极限冲刺攻略(附知识点解析+答题技巧)

距离2025上半年“系统架构设计师”考试已经只剩最后两周了,还没有准备好的小伙伴赶紧行动起来。为了帮助大家更好的冲刺学习,特此提供一份考前冲刺攻略。本指南包括考情分析、答题技巧、注意事项三个部分,可以参考此指南进行最后的复习要领&a…

web animation API 锋利的css动画控制器 (更新中)

什么是web animation api 以及为什么要使用web animation api? web animation API 是web页面中控制DOM元素动画效果的javascript原生API。 它能够逐个关键帧控制动画效果,具有Timeline 机制‌能通过javascript来实现动画的暂停,播放&#x…

Linux基础io知识

理解 "文件" 狭义理解 文件在磁盘里 磁盘是永久性存储介质,因此文件在磁盘上的存储是永久性的 磁盘是外设(即是输出设备也是输入设备) 磁盘上的文件 本质是对文件的所有操作,都是对外设的输入和输出 简称 IO 广义理解…

视频编解码学习三之显示器续

一、现在主流的显示器是LCD显示器吗? 是的,现在主流的显示器仍然是 LCD(液晶显示器,Liquid Crystal Display),但它已经细分为多种技术类型,并和其他显示技术(如OLED)形成…

[测试]并发模拟工具Apache Bench 进行AB压力测试

下载(windows) https://www.apachelounge.com/download/ 下载后解压,解压后进入bin目录,打开CMD,即可使用 命令 ab.exe -n 请求总数 -c 并发数 http://网站/ 比如ab.exe -n 1000 -c 100 http://127.0.0.1:5555/ 看不懂的话直接把结果让AI分析…

LeetCode 热题 100 138. 随机链表的复制

LeetCode 热题 100 | 138. 随机链表的复制 大家好,今天我们来解决一道经典的链表问题——随机链表的复制。这道题在 LeetCode 上被标记为中等难度,要求深拷贝一个带有随机指针的链表。 问题描述 给你一个长度为 n 的链表,每个节点包含一个额…

开源分享:TTS-Web-Vue系列:Vue3实现固定顶部与吸顶模式组件

🎯 本文是TTS-Web-Vue系列的第十三篇文章,重点介绍项目中固定顶部导航和内容区域吸顶模式的实现方案。通过这些优化,我们大幅提升了用户在滚动页面时的交互体验,使关键操作区域始终可见,同时实现了更现代化的界面视觉效…

Docker、Docker-compose、K8s、Docker swarm之间的区别

1.Docker docker是一个运行于主流linux/windows系统上的应用容器引擎,通过docker中的镜像(image)可以在docker中构建一个独立的容器(container)来运行镜像对应的服务; 例如可以通过mysql镜像构建一个运行mysql的容器,既可以直接进入该容器命…

用浏览器打开pdf,如何使用划词翻译?

1. 浏览器 | 扩展 | 获取 Microsoft Edge 扩展 2. 搜索 “沙拉查词” 点击“获取” 3. 扩展这里选择 管理扩展 勾选 “允许访问文件url” 注:这里一定要勾选,否则沙拉查词无法访问.pdf 文件!!!会出现下图错误 4. 右击…

深入解析STM32中断机制:从原理到外部中断实战

知识点1【中断的介绍】 单片机的中断——硬件中断 Linux操作系统的中断——软件中断 中断是指计算机运行过程中,出现某种意外情况需要主机干预,机器能自动停止正在运行的程序并转入处理新情况的程序,处理完毕后有返回原本暂停的程序继续运…

【入门】打印字母塔

描述 输入行数N,打印图形. 输入描述 输入只有一行&#xff0c;包括1个整数。(N<15) 输出描述 输出有N行. #include <bits/stdc.h> using namespace std; int main() { char t;int n,f;cin>>n;for(int i1;i<n;i){tchar(65i);for(int j1;j<n-i;j){cout…

CentOS 7.9 安装详解:手动分区完全指南

CentOS 7.9 安装详解&#xff1a;手动分区完全指南 为什么需要手动分区&#xff1f;CentOS 7.9 基本分区说明1. /boot/efi 分区2. /boot 分区3. swap 交换分区4. / (根) 分区 可选分区&#xff08;进阶设置&#xff09;5. /home 分区6. /var 分区7. /tmp 分区 分区方案建议标准…

油冷式电动滚筒设计:关键技术解析与应用前景

引言 电动滚筒作为一种集动力传输、减速和驱动功能于一体的机电一体化设备&#xff0c;在输送机械、矿山设备、食品加工等领域广泛应用。随着工业设备向高效化、紧凑化和智能化发展&#xff0c;传统风冷式电动滚筒的散热效率与负载能力已逐渐难以满足需求。油冷式电动滚筒凭借…