关于JDBC入门之后的一些问题解决和优化

博客介绍了JDBC类代码工具类的实现,将注册驱动、创建连接和释放资源等可复用代码整合到工具类,用属性文件管理配置,减少修改麻烦。还阐述了JDBC的SQL注入漏洞,分析其成因并给出用PreparedStatement对象替换Statement对象的解决方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

按照前一篇的内容写完JDBC之后,会发现在JDBC的类中内容实在过多,而且许多代码可以重复使用。那么是否可以将这些代码整合到一个类里面呢?当然是可以的。

一、JDBC类代码工具类的实现

首先我们先想一下,在JDBC 的类中,哪些代码是可以重复使用的。。。

1. 每个JDBC中都需要 注册驱动,创建连接和释放资源,所以将这些内容整合到一个工具类中,可以减少代码的复杂度。

2. 在这个JDBCUtils.java 的工具类中,其中driverClass,url,username,password 这些字符串可能都会随着环境的不同而发生改变,那么如果每次环境一变,我们都选择去改变源代码,这肯定是不可取得,这时候我们就可以使用属性文件(xxxx.properties),

这样就可以减少未来我们要修改配置的麻烦。

    注:这是我在属性文件中编写的一些小问题

                   在.properties的文件中  格式是   key = value 

                   无论在key值上还是在value值上,都是不需要 " "的,不然会出错,还有在每句语句的后面不需要写 ; 不然也会出错。 

package com.zhouxin.jdbc.utils;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class JDBCUtils {
	private static final String driverClass;
	private static final String url;
	private static final String username;
	private static final String password;
	

    //properties文件读取过程.
	static {
		//加载属性文件并解析:
		Properties prop = new Properties();
		//通常情况下使用类的加载器的方式进行获取属性文件的输入流:
		InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
		try {
			prop.load(is);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		driverClass = prop.getProperty("driverClass");
		url = prop.getProperty("url");
		username = prop.getProperty("username");
		password = prop.getProperty("password");
	}
	/**
	 * 注册数据库驱动
	 * @throws ClassNotFoundException
	 */
	public static void loadDriver() throws ClassNotFoundException {
		Class.forName(driverClass);
	}
	/**
	 * 创建连接
	 * @return
	 * @throws Exception
	 */
	public static Connection getConnection() throws Exception {
		loadDriver();
		Connection conn = DriverManager.getConnection(url,username,password);
		return conn;
	}
	
	/**
	 * 
	 */
	public static void release(Statement stmt ,Connection conn) {
		if(stmt!= null) {
			try {
				stmt.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			stmt = null;
		}
		if(conn!= null) {
			try {
				conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			conn = null;
		}
	}
	public static void release(ResultSet rs,Statement stmt,Connection conn) {
		if(rs!= null) {
			try {
				rs.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			rs = null;
		}
		if(stmt!= null) {
			try {
				stmt.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			stmt = null;
		}
		if(conn!= null) {
			try {
				conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			conn = null;
		}
	}
	
}

在写完这些后,直接在JDBC类中调用就可以了,这样能提高代码可读和降低复杂度。

二、JDBC的SQL注入漏洞

1. 引起的原因:

    在SQL语句的动态拼装过程的。传入的字符串(参数)和原SQL语句组合,形成一句完整的SQL语句时,但由于传入的值的不同而发生了不同的语义。

例如: 假设 正确的用户名密码为 username : aaa     password : 123

String  sql = "select * from user where username = ' "+username  + " ' and password =  ' " + password + " ' ";

此时传入username = aaa ' --  password :asdfasdf  因为 -- 在数据库中是注释的意思,当传入这个uername 之后就会到导致 在后面的sql 全部都失效了,所以这个语句照样能从数据库中读取出数据,那么此时我们就可以登录成功了。

这样的漏洞在我们的项目中是万万不能出现的。

2. 解决方法

用PreparedStatement 对象替换 Statement 对象,避免SQL注入的问题出现

Statement会频繁的编译SQL,可能会导致数据库缓冲区的溢出,而PreparedStatement可以对sql进行预编译,提高数据库执行的效率。在PreparedStatement中的SQL参数,可以使用占位符( ? )的形式进行替换,简化sql语句的编写。

String sql = "select * from user where username = ? and password = ? " ;
PreparedStatement pstmt = connection.preparedStatement(sql);
// 第一个参数,代表的是第几个占位符 ,第二个参数,则是这个位置的填入的值
pstmt.setString(1,username);
pstmt.setString(2,password);
ResultSet rs = pstmt.executeQuery();

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值