JdbcUtils的三个版本
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+"'";// 执行sqlstmt = 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注入导致账号密码错误也显示登录成功
使用占位符就能避免这个问题