JDBC 工具类
目的:简化代码书写,抽取代码中的重复部分(释放资源的操作以及获取连接对象的操作)。当我们获取不同的数据库连接时,都要更改 url 、user、password、driver,代码不易维护与管理。
解决办法:配置文件 在 src 目录下新建一个文件 命名为 jdbc.properties
我们只需在配置文件里更改我们需要连接的数据库信息以及账户、密码和所用到的驱动即可。
package com.ztq.util;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.sql.*;
import java.util.Properties;
/**
* @author: ZTQ
* @Title: JDBCUtils
* @ProjectName: JDBC
* @Description: JDBC 工具类
* @date: 2021/4/18 14:23
*/
public class JDBCUtils {
private static String url;
private static String user;
private static String password;
private static String driver;
/*静态代码块*/
// 文件的读取,只需要读取一次即可拿到这些值
// 静态代码块在类加载的时候就会加载,且只加载一次
static {
try {
// 1. 创建Properties集合类。
Properties pro = new Properties();
// 获取src路径下的文件的方式--->ClassLoader 类加载器
ClassLoader classLoader = JDBCUtils.class.getClassLoader();
URL resource = classLoader.getResource("jdbc.properties");
String path = resource.getPath();
// 打印发现这样获取的 path 就是绝对路径,这样操作代码可以在不同电脑上的运行,不需要更改为该电脑上的绝对路径
// System.out.println(path);
// 2. 加载文件
pro.load(new FileReader(path));
// 3. 获取数据 赋值
url = pro.getProperty("url");
user = pro.getProperty("user");
password = pro.getProperty("password");
driver = pro.getProperty("driver");
// 4. 注册驱动
Class.forName(driver);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/*
* @Description: 获取连接对象
* @param:
* @return java.sql.Connection
* @author ZTQ
* @date 2021/4/18 14:54
*/
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, user, password);
}
/*
* @Description: 释放资源
* @param: statement
* @param: connection
* @return void
* @author ZTQ
* @date 2021/4/18 14:56
*/
public static void close(Statement statement, Connection connection) {
if (statement != null) {
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
public static void close(ResultSet resultSet, Statement statement, Connection connection) {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
练习:
需求:
1. 通过键盘录入 用户名 和 密码
2. 判断用户是否登录成功(判断数据库中是否有此用户的 user 和 password 信息)
数据库中账户和密码信息:
package com.ztq.JDBC;
import com.ztq.util.JDBCUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;
/**
* @author: ZTQ
* @Title: login
* @ProjectName: JDBC
* @Description: 登录练习
* @date: 2021/4/18 15:32
*/
public class login {
/* SQL 注入问题
请输入用户名:
mkads
请输入密码:
a' or 'a' = 'a
登陆成功!!!
* */
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入用户名:");
String username = scanner.nextLine();
System.out.println("请输入密码:");
String password = scanner.nextLine();
boolean flag = new login().login(username, password);
if (flag) {
System.out.println("登陆成功!!!");
} else {
System.out.println("用户名或密码错误!!!");
}
}
public boolean login(String username, String password) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
if (username == null || password == null) {
return false;
}
try {
// 1. 获取连接
connection = JDBCUtils.getConnection();
// 2. 定义 sql
// select * from user where username = '"+username+"' and password = '"+password+"' ";
String sql = "select * from user where username = '" + username + "' and password = '" + password + "'";
// 3. 获取执行 sql 的对象
statement = connection.createStatement();
// 4. 执行查询
resultSet = statement.executeQuery(sql);
return resultSet.next();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
JDBCUtils.close(resultSet, statement, connection);
}
return false;
}
}
打印本次操作的 sql 语句:
select * from user where username = 'jasjldlas' and password = ' a' or 'a' = 'a'
sql 注入问题:
sql 语句的拼接可能会导致 sql 注入问题,如上述语句 or 后面 ‘a’ = ‘a’ 为 true,这样整条查询语句就为true。
解决办法:
使用 PreparedStatement 对 sql 语句进行预处理可以防止 sql 注入。
package com.ztq.JDBC;
import com.ztq.util.JDBCUtils;
import java.sql.*;
import java.util.Scanner;
/**
* @author: ZTQ
* @Title: login_02
* @ProjectName: JDBC
* @Description:
* @date: 2021/4/18 16:02
*/
public class login_02 {
// 解决 sql 注入问题
/*
* 请输入用户名:
dnaks
请输入密码:
a' or 'a' = 'a
用户名或密码错误!!!
* */
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入用户名:");
String username = scanner.nextLine();
System.out.println("请输入密码:");
String password = scanner.nextLine();
boolean flag = new login_02().login(username, password);
if (flag) {
System.out.println("登陆成功!!!");
} else {
System.out.println("用户名或密码错误!!!");
}
}
public boolean login(String username, String password) {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
if (username == null || password == null) {
return false;
}
try {
// 1. 获取连接
connection = JDBCUtils.getConnection();
// 2. 定义 sql
// select * from user where username = '"+username+"' and password = '"+password+"' ";
String sql = "select * from user where username = ? and password = ?";
// 3. 获取执行 sql 的对象
preparedStatement = connection.prepareStatement(sql);
// 给 ? 赋值
preparedStatement.setString(1, username);
preparedStatement.setString(2, password);
// 4. 执行查询
resultSet = preparedStatement.executeQuery();
return resultSet.next();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
JDBCUtils.close(resultSet, preparedStatement, connection);
}
return false;
}
}