JDBC教程中篇
创始人
2025-06-01 05:46:52

二、SQL注入

2.1 什么是SQL注入

用户输入的数据中有SQL关键词,导致在执行SQL语句时出现一些不正常的情况.这就是SQL注入!


出现SQL注入是很危险

2.2 避免SQL注入

问题出现在用户输入数据时,里面有关键词,再配合字符串拼接导致出现SQL注入.所以为了避免SQL注入,可以在用户输入数据到SQL之前,先把SQL语句预编译,预处理后,JDBC就会知道此SQL需要几个参数,后续再将用户输入的数据给参数填充.

这就是PreparedStatement

三、PreparedStatement【重点】

PreparedStatement是Statement的子接口,用来预处理SQL语句

PreparedStatement使用

  • 先写SQL语句,SQL语句中的参数不能直接拼接,而是使用?占位
  • 使用ps预处理SQL语句,处理的?号,ps内部就会知道此SQL语句需要几个参数
  • 再动态给?处填充值
package com.qf.jdbc;import java.sql.*;
import java.util.Scanner;
/*** @Author:二手Java程序员* @DateTime 2023/3/21 10:35**/public class Demo2_LoginPlus {public static void main(String[] args) throws Exception {Scanner scanner = new Scanner(System.in);System.out.println("请输入用户名:" );String username = scanner.nextLine( );System.out.println("请输入密码:" );String password = scanner.nextLine( );Class.forName("com.mysql.jdbc.Driver");Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/java2217?useSSL=false", "root", "123456");// 改造SQL,将拼接变量,变成?占位String sql = "select * from tb_user where username = ? and password = ?";System.out.println("处理前:  " + sql);// 由之前的Statement换成PreparedStatement// 将改造好的SQL,传入方法PreparedStatement ps = conn.prepareStatement(sql);System.out.println("处理后: " + ps );// 给处理好的占位参数赋值// ps.setXxx() 给指定Xxx类型赋值// 第一个?,下标是1ps.setString(1,username);ps.setString(2,password);System.out.println("填充后: " + ps );//【特别注意!!!!】 此处executeQuery不需要再传入SQL参数!!!ResultSet rs = ps.executeQuery();if (rs.next()) {System.out.println("登录成功!!" );} else {System.out.println("用户名或密码错误!" );}rs.close();ps.close();conn.close();}
}
请输入用户名:
111
请输入密码:
111' or '1=1
处理前:  select * from tb_user where username = ? and password = ?
处理后: select * from tb_user where username = ** NOT SPECIFIED ** and password = ** NOT SPECIFIED **
填充后: select * from tb_user where username = '111' and password = '111\' or \'1=1'
用户名或密码错误!

四、预处理语句完成CRUD

4.1 插入

package com.hui.homework;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Scanner;/*** @Author:二手Java程序员* @DateTime 2023/3/21 13:44**/
public class insert {public static void main(String[] args) throws Exception {input();}private static void input() throws SQLException, ClassNotFoundException {Scanner scan = new Scanner(System.in);System.out.println("请输入用户名");String username = scan.next();System.out.println("请输入密码");String password = scan.next();in (username,password);}private static void in(String username, String password) throws ClassNotFoundException, SQLException {Class.forName("com.mysql.jdbc.Driver");Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/java2301","root","hui778203081");String sql = "select * from tb_user where username = ? and password = ?";System.out.println(sql);// 防止SQL注入PreparedStatement ps = conn.prepareStatement(sql);ps.setString(1,username);ps.setString(2,password);}
}

4.2 更新

package com.hui.homework;import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.Scanner;/*** @Author:二手Java程序员* @DateTime 2023/3/21 15:05**/
public class Update {public static void main(String[] args) throws Exception {input();}private static void input() throws Exception {Scanner scan = new Scanner(System.in);System.out.println("请输入要修改哪条数据:");int id = scan.nextInt();System.out.println("请输入要修改的用户名");String username = scan.next();System.out.println("请输入要修改的密码");String password = scan.next();User user = new User();user.setUsername(username);user.setPassword(password);user.setId(id);up(user);}private static void up(User user) throws Exception {Class.forName("com.mysql.jdbc.Driver");Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/java2301?useSSL=false","root","hui778203081");String sql = "update tb_user set username = ?,password = ? where id = ?";System.out.println(sql);PreparedStatement ps = conn.prepareStatement(sql);ps.setString(1,user.getUsername());ps.setString(2,user.getPassword());ps.setInt(3,user.getId());int n = ps.executeUpdate();if (n>0){System.out.println("修改成功!");}else {System.out.println("修改失败!");}conn.close();ps.close();}
}

4.3 删除

package com.hui.homework;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Scanner;/*** @Author:二手Java程序员* @DateTime 2023/3/21 14:56**/
public class Delete {public static void main(String[] args) throws Exception {input();}private static void input() throws SQLException, ClassNotFoundException {Scanner scan = new Scanner(System.in);System.out.println("请输入要删除的id");int id = scan.nextInt();// 获取User user = new User();user.setId(id);rm(user.getId());}private static void rm(int id) throws ClassNotFoundException, SQLException {Class.forName("com.mysql.jdbc.Driver");Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/java2301?useSSL=false","root","hui778203081");String sql = "delete from tb_user where id = ?";// 防止SQL注入PreparedStatement ps = conn.prepareStatement(sql);ps.setInt(1,id);int n = ps.executeUpdate();if (n > 0){System.out.println("删除成功!!!");}}
}

五、事务处理

事务是逻辑一组操作,要么全部成功,要么全部失败!


使用mysql客户端操作事务

  • 因为mysql支持事务,且每句话都在事务内,且自动提交
  • 所以关闭自动提交事务,手动开启事务 start transaction
  • 正常写sql/执行sql
  • 一切正常,提交事务 commit
  • 如果不正常,要回滚 rollback

JDBC也可以完成事务操作

  • conn.setAutoCommit(false) 关闭自动提交,就相当于是开启手动管理
  • 正常的处理sql
  • 一切正常,提交事务 conn.commit()
  • 如果不正常,回滚 conn.rollback()

演示: 以转账案例演示

package com.qf.tx;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;/*** @Author:二手Java程序员* @DateTime 2023/3/21 10:35**/
public class Demo6_TX {// 张三转账给李四public static void main(String[] args) {Connection conn = null;PreparedStatement ps1 = null;PreparedStatement ps2 = null;try {Class.forName("com.mysql.jdbc.Driver");conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/java2217?useSSL=false", "root", "123456");// 【1 开启事务】conn.setAutoCommit(false);// 张三的钱减少100String sql1 = "update account set money = money - 100 where id = 1";ps1 = conn.prepareStatement(sql1);int num = ps1.executeUpdate( );if (num > 0) {System.out.println("张三转账(-100)完成!");}System.out.println(1/0 ); // 模拟在转账中,出现异常,后续不执行// 李四的钱要增加100String sql2 = "update account set money = money + 100 where id = 2";ps2 = conn.prepareStatement(sql2);int num2 = ps2.executeUpdate( );if (num2 > 0) {System.out.println("李四转账(+100)完成!");}// 【2 一切顺利,提交事务】conn.commit();} catch (Exception e) {try{// 【3 不顺利,中间有异常,回滚事务】conn.rollback();}catch (Exception e2) {System.out.println("回滚事务异常!!" );e2.printStackTrace();}System.out.println("SQL异常!!!");e.printStackTrace( );} finally {try {ps1.close( );ps2.close( );conn.close( );} catch (Exception e) {System.out.println("关流时有异常!!");e.printStackTrace( );}}}
}

另外发现: 建立与Mysql连接后,关流之前,可以执行很多次SQL语句

六、DBUtil【理解,会用】

DBUtil操作数据库的工具类,因为发现每次操作数据库,JDBC的步骤第1,2,5步完全重复的,即加载驱动,获得连接对象,已经最后的关流是每次都要写但每次都是一样的!!!


现在设计工具类,简化第1,2,5步

  • 设计个方法,调用直接获得连接对象
  • 设计个方法,调用直接关闭全部的流对象
package com.qf.util;import java.io.InputStream;
import java.sql.*;
import java.util.Properties;/*** @Author:二手Java程序员* @DateTime 2023/3/21 10:35**/
public class DBUtil {// 创建Properties类对象,专用于操作properties文件private static final Properties properties = new Properties();/*** 加载驱动的目的是为了在JVM中有sql运行的环境* 该环境有一份就行了,不用重复加载* ------------------------------------* static 静态代码块* 1) 保证内存中只有一份* 2) 保证随着类加载而加载,即该代码块会执行*/static {// 通过反射的技术获得字节码文件// 再通过字节码文件将配置文件读取成输入流InputStream inputStream = DBUtil.class.getResourceAsStream("/jdbc.properties");try {// 再通过流获得其中数据properties.load(inputStream);// 从properties对象取值Class.forName(properties.getProperty("driverClass"));} catch (Exception e) {System.out.println("加载驱动异常!!" );e.printStackTrace( );}}/*** 一般会将关于JDBC配置信息,抽取出来,形成一个配置文件,方便维护* 文件类型是properties文件,该文件类似map,键值对类型* 名字 jdbc.properties* 位置 src/jdbc.properties* 内容*/public static Connection getConnection() {Connection conn = null;try{conn = DriverManager.getConnection(properties.getProperty("url"),properties.getProperty("username") ,properties.getProperty("password") );} catch (Exception e) {System.out.println("获得连接出异常!!!" );e.printStackTrace();}return conn;}/*** 关闭所有流*/public static void closeAll(Connection conn, Statement s) {if (conn != null) {try {conn.close();} catch (SQLException throwables) {throwables.printStackTrace( );}}if (s != null) {try {s.close();} catch (SQLException throwables) {throwables.printStackTrace( );}}}public static void closeAll(Connection conn, Statement s, ResultSet rs){if (conn != null) {try {conn.close();} catch (SQLException throwables) {throwables.printStackTrace( );}}if (s != null) {try {s.close();} catch (SQLException throwables) {throwables.printStackTrace( );}}if (rs != null) {try {rs.close();} catch (SQLException throwables) {throwables.printStackTrace( );}}}
}

在src下创建jdbc.properties文件

driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/java2217?useSSL=false
username=root
password=123456

相关内容

热门资讯

赛诺菲斥资超90亿美元收购罕见... 当地时间6月2日,法国制药巨头赛诺菲与美国生物药企Blueprint Medicines公司宣布达成...
黔源电力:董事长罗涛因工作原因... 新京报贝壳财经讯 黔源电力6月2日晚间公告,公司董事长罗涛因工作原因申请辞去公司董事长、董事、董事会...
京沪高铁:已完成约10亿元股份... 新京报贝壳财经讯 6月2日,京沪高铁(601816.SH)公告称,公司已使用自有资金约10亿元,以集...
恒宝股份:实控人在股票交易异常... 新京报贝壳财经讯 6月2日,恒宝股份发布异动公告,公司控股股东、实际控制人在股票交易异常波动期间存在...
机构论后市丨关注核心资产;对科... 沪指本周累计跌0.03%,深成指累计跌0.91%,创业板指累计跌1.4%。A股后市怎么走?看看机构怎...
宏信证券更名天府证券,中小券商... 因实控人将发生变化,时隔13年,宏信证券再次更名。国家企业信用信息公示系统信息显示,宏信证券有限责任...
最新!全球9大汽车集团总负债:... 谁是车界负债之王?在企业的经营生产中,负债是难以避免的。企业通过合理的负债水平,是有助于其快速发展的...
韩国紧急商讨应对美上调钢铝关税   新华社首尔6月2日电(记者黄昕欣 陆睿)韩国产业通商资源部2日召集钢铝产业代表召开紧急会议,商讨...
二次育肥“禁令”来了?有猪企回... 二次育肥禁令来了? 今天上午,猪肉板块异动拉升。有市场消息称,“昨天,相关部门开会,透露引导生猪行业...
恒指探底回升跌0.57% 黄金...   中新经纬6月2日电 周一,港股三大指数集体低开,此后探底回升。截至收盘,恒生指数跌0.57%报2...
在下沉市场,找不到中国汽车的未... 原本已经渐入缓和的车市价格战,随着年中6月的到来而再度升温。下到5万元接近老头乐的“车市踢脚线”,上...
全维度突破!雅迪冠能S长续航进... 文 | 无锈钵“你可能不认识我们,但你一定见过我造的车。”5月26日,浙江宁波,雅迪全球产品及技术副...
晶科能源:收到政府补助9800... 晶科能源(688223)公告,5月29日收到政府补助人民币9800万元,属于与收益相关的政府补助款项...
国际金价年内上涨超25%,5月... 首先来看美股上周交易的情况。受美欧贸易谈判出现积极信号、美国国际贸易法院一度“叫停”特朗普政府多项关...
全球人造草坪老二青岛青禾“躺平... 5月26日-6月2日,沪深北合计有3家企业终止审核,分别为沪市主板申报企业青岛青禾人造草坪股份有限公...
MiniMax正暗戳戳憋大招 ... 出品|虎嗅科技组作者|宋思杭编辑|苗正卿头图|视觉中国AI六小虎之一的MiniMax正在憋大招,而这...
今日起招股发售价9.75港元,... 6月2日,车来了母公司元光科技启动全球发售,发售价9.75港元,预计将在6月10日在港交所挂牌。元光...
港股午评:恒生指数跌2.20%... 新京报贝壳财经讯 6月2日,港股午间收盘,恒生指数跌2.20%,恒生科技指数跌2.43%。石药集团跌...
夏乐:美债压力与美元走弱 全球... 原创 财联社 蜂网专家2025年05月29日《首席说》是财联社倾力打造的一档高端直播联线栏目。面向泛...
罗志恒:财政政策不应受3%赤字... 罗志恒系粤开证券首席经济学家、中国首席经济学家论坛理事自2008年以来,本轮积极财政政策实行了长达1...
三大利空,突袭! 三大利空,突... 时局依然不稳!今天早上,全球市场全线杀跌。日经指数一度杀跌近1.5%,中国台湾股指大跌近1%,港股三...
美国客户“疯狂”催单 这家川企... 自硬公司的精密零件产品之一:随钻用核心零部件。韩吉尔摄 “5月中旬,美国休斯敦的客户发邮件,要求尽快...
这只港股,突然暴涨超60%!发... 6月2日,亚太股市开盘后持续走弱。不过,港股方面,加密货币数字概念股大涨,连连数字涨62.67%。港...
招商基金三首席同日上任!“去管... 当同行纷纷为投研人才做“去管理化”减法时,招商基金却反其道而行之,提拔朱红裕、王景两位基金经理。这究...
2025浙江国际电子商务博览会... 这个周末,端午的粽叶飘香和六一小朋友的欢笑声撞了个满怀~跨境电商圈也跟着热闹到飞起。 从节令美食到文...
头部餐饮,火拼儿童餐 头部餐饮... 总第4234期作者 |餐饮老板内参内参君儿童餐,卷入next level端午恰逢六一,双节叠加背景下...
舆论战升级!巨子生物深夜回应,... 2025.06.02本文字数:2490,阅读时长大约4分钟作者 |第一财经 刘晓颖重组胶原蛋白成分之...
财经时评|以创新厚度重塑汽车产... 作者 远山中国汽车工业协会与工业和信息化部近期针对行业“内卷式”竞争的联合发声,为持续蔓延的价格战按...
恒生指数午盘下跌2.20%,恒... 6月2日午盘,香港恒生指数下跌2.20%,报22778.45点;恒生科技指数下跌2.43%,报504...
“以旧换新”带货1万亿,中国何... “美国想让制造业回流成为中国的样子,一个踏实劳作的‘生产者社会’;而中国想努力扩大消费成为美国的样子...