JDBC工具类 以及使用JDBC工具类
文章目录
思维导图
Github 地址获取原始思维导图文件
https://github.com/YIMEng-0/JavaPlus/tree/main/javaSE%E5%A4%8D%E4%B9%A0%E5%87%86%E5%A4%87/java%E5%9F%BA%E7%A1%80
如有帮助 欢迎 star
目前整理的 xmind
JDBC工具类
1 工具类的代码实现
相关变量
定义四个变量
- driver
数据库的驱动,让程序可以使用数据库
com.mysql.jdbc.Driver
- url
具体的数据库的位置
jdbc:mysql://localhost:3306/data
- username
可以访问数据库的用户名 - password
使用ResourceBundle 进行资源的绑定,主要是绑定到 jdbc.properties 文件,方便将这个配置文件里面的相关配置读取出来
static { // 在类加载的时候,只需要执行一次即可
ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
driver = bundle.getString("driver");
url = bundle.getString("url");
username = bundle.getString("username");
password = bundle.getString("password");
}
(1)(2)加载驱动
- 建立链接,建立链接的时候,把数据库的 url 用户名字以及密码传递进去
public static Connection getConnection() throws SQLException {
Connection conn = null;
try {
Class.forName(driver);
conn = DriverManager.getConnection(url, username, password);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return conn;
}
关闭资源
public static void close(Connection conn, Statement ps, ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (ps != null) {
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
- 关闭资源方法需要传递的三个参数,conn,Statement,ResultSet
2 工具类代码实现所有代码
package com.luobin.utils;
/**
* @author Doraemon
* @date 2021/12/12 12:08 下午
* @version 1.0
*/
import java.sql.*;
import java.util.ResourceBundle;
/**
* JDBC 工具类,用来简化 JDBC 编程
*/
public class DBUtil {
/**
* 工具类中的属性、方法都是私有的,
* 因为工具类中的方法都是静态的,不需要直接的new 对象,直接使用类名字进行调用即可;
*/
//私有变量
private static String driver;
private static String url;
private static String username;
private static String password;
static { // 在类加载的时候,只需要执行一次即可
ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
driver = bundle.getString("driver");
url = bundle.getString("url");
username = bundle.getString("username");
password = bundle.getString("password");
}
public static Connection getConnection() throws SQLException {
Connection conn = null;
try {
Class.forName(driver);
conn = DriverManager.getConnection(url, username, password);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return conn;
}
/**
* 关闭资源
* @param conn 连接对象
* @param ps 数据库操作对象
* @param rs 结果集
*/
public static void close(Connection conn, Statement ps, ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (ps != null) {
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
3 调用工具类的代码实现
创建进行数据库交互的相关变量
- Connection
- PrepareStatement
- ResultSet
调用静态方法进行连接的建立
- conn = DBUtil.getConnection();
(3)建立sql 语句,将建立的sql 语句进行预编译,得到预编译环境
- String sql = “select deptno,dname,loc from dept”;
ps = conn.prepareStatement(sql);
(4)执行预编译得到处理结果
-
PrepareStatement是SQL语句预编译对象,当我们执行:preparedStatement = connection.prepareStatement(sql);这一行代码获取PrepareStatement对象的时候就会把传进去的sql语句进行编译并且加载进如内存中,在接下来的操作中我们只需要对sql语句中的占位符:?进行赋值,这样sql语句就不需要再次重新编译,这是与statement对象的最主要的差别
- rs = ps.executeQuery();
(5)对处理结果进行处理
while (rs.next()) {
String deptno = rs.getString("deptno");
String dname = rs.getString("dname");
String loc = rs.getString("loc");
}
(6)释放资源
- DBUtil.close(conn, ps, rs);
4 调用工具类的代码实现
package com.luobin.oa.web.action;
/**
* @author Doraemon
* @date 2021/12/12 2:19 下午
* @version 1.0
*/
import com.luobin.utils.DBUtil;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class DeptListServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
// 获取连接
conn = DBUtil.getConnection(); // 加载驱动,获取连接,完成 1 2 步 getConnection方法里面有两步
String sql = "select deptno,dname,loc from dept";
ps = conn.prepareStatement(sql); // 获取预编译数据库操作对象,完成第 3 步
rs = ps.executeQuery(); // 执行 sql 完成 4 步
int i = 0;
// 处理查询结果集合 完成第 5 步
while (rs.next()) { // rs 里面的东西就是查询到的表格里面的东西,没有表头的一个表的部分数据
String deptno = rs.getString("deptno");
String dname = rs.getString("dname");
String loc = rs.getString("loc");
// 下面的界面进行动态的展示
}
} catch (SQLException e) {
e.printStackTrace();
} finally { // 资源释放完成第 6 步
DBUtil.close(conn, ps, rs);
}
}
}
5 sql 注入以及解决的方式
怎么注入进去的
- 客户端在自己电脑操作时候,有一定的输入操作,这个输入操作中可能会有一些特殊符号的输入,把特殊的符号输入进去之后,会编译到SQL语句中,进而破坏正常的SQL语句的结构,导致安全漏洞问题,攻击者就可以执行计划外的命令或访问未被授权的数据
String sql = "select * from user_table where username=
' "+userName+" ' and password=' "+password+" '";
–当输入了上面的用户名和密码,上面的SQL语句变成:
SELECT * FROM user_table WHERE username='’or 1 = 1 -- and password='’
--分析SQL语句:
--条件后面username=”or 1=1 用户名等于 ” 或1=1 那么这个条件一定会成功;
--然后后面加两个-,这意味着注释,它将后面的语句注释,让他们不起作用,这样语句永远都--能正确执行,用户轻易骗过系统,获取合法身份。
--这还是比较温柔的,如果是执行
SELECT * FROM user_table WHERE
username='' ;DROP DATABASE (DB Name) --' and password=''
--其后果可想而知…
怎么解决注入问题?
- 参数化查询,使用了预编译的数据库操作对象,提前将SQL语句编译好,里面设置变量集,用户输入的部分作为变量的赋值,不参与到SQL语句的编译,没有破坏SQL语句结构,抵御了SQL注入
小结
1、通过了工具类在进行连接的时候,进行资源释放的时候,会简化代码
2、在工具类里面是没有写 sql 语句和解析的,因为在工具类里面不执行语句
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!