JDBC的工具类 1.0版本 JDBC的工具类 2.0版本(智能一些),编写properties属性文件,程序就可以读取属性文件 JDBC的工具类 3.0版本,加入连接池对象
我们封装jdbc工具类是为了减少代码重复,方便开发,JdbcUtils至少要有三个方法
1.新建驱动
2.新建连接
3.关闭资源
1.0 这里的static是为了直接调用类方法,不用new对象
public class JdbcUtils1 {
/**
* 加载驱动的方法 static
*/
public static void loadDrive(){
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 连接对象conn
*/
public static Connection getConntion(){
loadDrive();
Connection connection = null;
try {
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
/**
* 获取执行sql的对象 Statement
*/
public static Statement creatstmt() throws SQLException {
Connection conntion = getConntion();
Statement statement = conntion.createStatement();
return statement;
}
/**
* 关闭资源的提取
*/
public static void close(ResultSet rs, Statement stmt, Connection conn){
try {
rs.close();
stmt.close();
conn.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
2.0 可以动态修改配置,不是写死的了
1. 驱动类
2. 数据库地址
3. 用户名
4. 密码
package com.qcby.utils;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
/**
* JDBC的工具类 1.0版本
* JDBC的工具类 2.0版本(智能一些),编写properties属性文件,程序就可以读取属性文件
* 1. 驱动类
* 2. 数据库地址
* 3. 用户名
* 4. 密码
*/
public class JdbcUtils2 {
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 = JdbcUtils2.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 加入连接池对象
package com.qcby.utils;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
/**
* JDBC的工具类 1.0版本
* JDBC的工具类 2.0版本(智能一些),编写properties属性文件,程序就可以读取属性文件
* JDBC的工具类 3.0版本,加入连接池对象
*/
public class JdbcUtils3 {
// 连接池对象
private static DataSource DATA_SOURCE;
static{
// 加载属性文件
Properties pro = new Properties();
InputStream inputStream = JdbcUtils3.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();
}
}
}
}
连接池xml配置
<!--配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/spring_db?characterEncoding=utf8mb4" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
druid.properties配置
driverclass = com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/spring_db?useUnicode=true&characterEncoding=utf8
username=root
password=root
sql注入问题
/**
* 演示SQL注入的问题,漏洞
* 在已知用户名的情况下,通过sql语言关键字,登录系统。密码随意输入的。
* SQL注入产生原因是SQL语句的拼接,利用SQL关键字产生效果。
* 需要解决SQL注入的问题
*
* 解决SQL注入问题,采用SQL语句预编译的方式,把SQL语句中的参数使用 ? 占位符来表示,先把SQL语句编译,格式固定的。
* 再给 ? 传入值,传入任何内容都表示值。数据库会判断SQL执行的结果。
*
*
* 解决sql注入问题:
* 1.使用预编译sql的PreparedStatement对象
* 2.在通过PreparedStatement对象的set方法为每一个占位符赋值(避免了字符串拼接带来的关键字问题)
* 3.执行sql方法 stmt.executeQuery(); 拿到结果集
*/
public class JdbcTest4 {
public static void main(String[] args) {
// 模拟登录的功能,有SQL注入的问题
String result = new JdbcTest4().login2("aaa'or'1=1", "12309809");
System.out.println(result);
// String result = new JdbcTest4().login2("aaa", "123");
// System.out.println(result);
}
/**
* 采用预编译的方式,解决SQL注入的问题
* @param username
* @param password
* @return
*/
public String login2(String username,String password){
Connection conn = null;
// 预编译执行SQL语句对象
PreparedStatement stmt = null;
ResultSet rs = null;
try {
// 获取到连接
conn = JdbcUtils3.getConnection();
// 使用?占位符
String sql = "select * from t_user where username = ? and password = ?";
// 预编译SQL语句,把SQL语句固定
stmt = conn.prepareStatement(sql);
// 需要给 ? 设置值
stmt.setString(1,username);
stmt.setString(2,password);
// 执行SQL语句
rs = stmt.executeQuery();
// 遍历数据
if(rs.next()){
// 表示存在数据,如果存在,说明用户名和密码编写正确
return "登录成功...";
}else{
return "登录失败了...";
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils3.close(conn,stmt,rs);
}
return null;
}
/**
* 模拟登录的功能,通过用户名和密码从数据库中查询
* @param username
* @param password
* @return
*/
public String login(String username,String password){
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
// 获取到连接
conn = JdbcUtils3.getConnection();
// 编写SQL语句的拼接 '1=1' true password = '1234sdfsce' false true and false 整体上false
// String sql = "select * from t_user where username = 'aaa' or '1=1' and password = '1234sdfsce'";
// String sql = "select * from t_user where username = 'aaa' or false";
String sql = "select * from t_user where username = '"+username+"' and password = '"+password+"'";
// 执行sql
stmt = conn.createStatement();
// 执行
rs = stmt.executeQuery(sql);
// 遍历数据
if(rs.next()){
// 表示存在数据,如果存在,说明用户名和密码编写正确
return "登录成功...";
}else{
return "登录失败了...";
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils3.close(conn,stmt,rs);
}
return null;
}
}
数据库
sql注入导致账号密码错误也显示登录成功
使用占位符就能避免这个问题