通过反射机制完成注册
观察源码,可以看出已经写了注册的方法,所以通过反射拿到class文件
package JDBCTEST;
import java.sql.*;
public class JDBCTest04 {
public static void main(String[] args) {
Connection connection = null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
System.out.println("register is ok");
String url = "jdbc:mysql://localhost:3306/mysql";
String user = "root";
String password = "333";
connection = DriverManager.getConnection(url, user, password);
System.out.println("database connection object is " + connection);
} catch (SQLException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
报错记录
想通过ResourceBundle来配置
package JDBCTEST;
import java.sql.*;
import java.util.ResourceBundle;
public class JDBCTEST05 {
public static void main(String[] args) throws Exception {
ResourceBundle resourceBundle = ResourceBundle.getBundle("JDBC_Test");
String MyDriver = resourceBundle.getString("MyDriver");
String url = resourceBundle.getString("url");
String user = resourceBundle.getString("user");
String password = resourceBundle.getString("password");
Connection connection = null;
try {
Class.forName(MyDriver);
System.out.println("register is ok");
connection = DriverManager.getConnection(url, user, password);
System.out.println("database connection object is " + connection);
} catch (Exception e) {
e.printStackTrace();
}
}
}
然后配置文件也放在同一个目录下的
MyDriver="com.mysql.cj.jdbc.Driver"
url="jdbc:mysql://localhost:3306/mysql";
user="root";
password="333";
但是始终报错
Exception in thread “main” java.util.MissingResourceException: Can’t find bundle for base name JDBC_Test
这个问题百度了还是找不到,所以先搁置一下吧
更新一下:又重新配置了一个空的Project,可以使用,之前这个添加jar包报了以下错误
处理查询结果集
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class JDBC20210330 {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
ResultSet rs = null;
try {
//注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//获取连接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mysql", "root", "333");
//获取数据库操作对象
statement = connection.createStatement();
//执行sql语句
String sql = "select empno,ename,sal from emp";
rs = statement.executeQuery(sql);
//处理查询的结果集
//rs一次取一行,判断下一行是否有数据
boolean flag1;
while (flag1 = rs.next()) {
String empno = rs.getString(1);
String ename = rs.getString(2);
//或者直接写成字段名,查询结果后的字段名,如果as重命名后,用重命名的
//除了String类型,还有其他类型
double sal = rs.getDouble("sal");
System.out.println(empno + "," + ename + "," + (100 + sal));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
}
处理的时候rs.next(),仿佛回到了迭代器的日子
配置intellij
在module上,配置module
open module settings
library里面添加jar包
用户登录业务介绍
配置数据库
PowerDesign工具
在百度上随便搜一个下载一下
选择对应数据库的版本,新建一个model
从右侧拖一个table过来
双击表,给表设置各种属性
可以直接保存为一个sql文件
稍微修改一下刚刚的sql 文件
准备数据集
drop table if exists t_User;
/*==============================================================*/
/* Table: t_User */
/*==============================================================*/
create table t_User
(
id bigint auto_increment,
loginName varchar(255),
loginPassword varchar(255),
realName varchar(255),
primary key (id)
);
insert into t_user(loginName,loginPassword,realName)values("ZS","123","Zhangsan");
insert into t_user(loginName,loginPassword,realName)values("LS","123","Lisi");
insert into t_user(loginName,loginPassword,realName)values("Wangwu","123","王五");
commit;
select * from t_user;
写JDBC语句
分布来拆解
写出主程序,各个子模块定义方法即可
初始化界面+输出情况写在主方法里面
//模拟用户登录
public class JDBCTest02 {
public static void main(String[] args) {
//初始化UI界面,尽量把所有的子功能写成单独的方法
//用Map来存
Map<String, String> userLoginInfo = Initiate_UI();
//验证用户名和密码
System.out.println(userLoginInfo);
//登录成功或者失败,就两种情况,所以用boolean
boolean loginSuccess = login(userLoginInfo);
System.out.println(loginSuccess ? "登录成功" : "登录失败");
}
定义Initiate_UI()方法
利用Map存放密码和用户
放进一个HashMap里面
//上面给了返回值,那么生成的方法也一定要有返回值
private static Map<String, String> Initiate_UI() {
Scanner scanner = new Scanner(System.in);
System.out.println("用户名:");
//一次接受一行
String userName = scanner.nextLine();
System.out.println("密码:");
String passWord = scanner.nextLine();
Map<String, String> user_info = new HashMap<>();
user_info.put("userName", userName);
user_info.put("passWord", passWord);
return user_info;
}
定义login方法
private static boolean login(Map<String, String> userLoginInfo) {
//定义变量
boolean loginSuccess = false;
//来自之前的Map集合,用来读取里面的数据
String loginName = userLoginInfo.get("userName");
String loginPassword = userLoginInfo.get("passWord");
//JDBC代码,按照JDBC六步走
Statement statement = null;
Connection connection = null;
ResultSet resultSet = null;
try {
//注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//建立数据库连接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mysql", "root", "333");
//获取数据库操作对象
statement = connection.createStatement();
//执行Sql语句
//注意在sql语句中写变量,是两个双引号和两个加号拼起来
String sql = "select * from t_user where loginName='" + loginName + "' and loginPassword='" + loginPassword + "'";
resultSet = statement.executeQuery(sql);
//处理结果集
//因为对错与否都只有一个结果,所以不需要whiletrue,只需要简单的if
if (resultSet.next()) {
loginSuccess = true;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//释放资源
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null)
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
if (resultSet != null)
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return loginSuccess;
}
数据库里有三条记录
+----+-----------+---------------+----------+
| id | loginName | loginPassword | realName |
+----+-----------+---------------+----------+
| 1 | ZS | 123 | Zhangsan |
| 2 | LS | 123 | Lisi |
| 3 | Wangwu | 123 | 鐜嬩簲 |
+----+-----------+---------------+----------+
执行以上代码
用户名:
ZS
密码:
123
{passWord=123, userName=ZS}
登录成功
用户名:
Zhangsan
密码:
234
{passWord=234, userName=Zhangsan}
登录失败
上述完整代码
package BUPT20210330;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
//模拟用户登录
public class JDBCTest02 {
public static void main(String[] args) {
//初始化UI界面,尽量把所有的子功能写成单独的方法
//用Map来存
Map<String, String> userLoginInfo = Initiate_UI();
//验证用户名和密码
System.out.println(userLoginInfo);
//登录成功或者失败,就两种情况,所以用boolean
boolean loginSuccess = login(userLoginInfo);
System.out.println(loginSuccess ? "登录成功" : "登录失败");
}
private static boolean login(Map<String, String> userLoginInfo) {
//定义变量
boolean loginSuccess = false;
String loginName = userLoginInfo.get("userName");
String loginPassword = userLoginInfo.get("passWord");
//JDBC代码,按照JDBC六步走
Statement statement = null;
Connection connection = null;
ResultSet resultSet = null;
try {
//注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//建立数据库连接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mysql", "root", "333");
//获取数据库操作对象
statement = connection.createStatement();
//执行Sql语句
//注意在sql语句中写变量,是两个双引号和两个加号拼起来
String sql = "select * from t_user where loginName='" + loginName + "' and loginPassword='" + loginPassword + "'";
resultSet = statement.executeQuery(sql);
//处理结果集
//因为对错与否都只有一个结果,所以不需要whiletrue,只需要简单的if
if (resultSet.next()) {
loginSuccess = true;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//释放资源
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null)
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
if (resultSet != null)
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return loginSuccess;
}
//上面给了返回值,那么生成的方法也一定要有返回值
private static Map<String, String> Initiate_UI() {
Scanner scanner = new Scanner(System.in);
System.out.println("用户名:");
//一次接受一行
String userName = scanner.nextLine();
System.out.println("密码:");
String passWord = scanner.nextLine();
Map<String, String> user_info = new HashMap<>();
user_info.put("userName", userName);
user_info.put("passWord", passWord);
return user_info;
}
}
SQL注入现象
用户名:
jdh
密码:
jdh' or '1'='1
{passWord=jdh' or '1'='1, userName=fdsa}
登录成功
即使这个用户名和密码不在库中,还是进了系统
- 导致SQL注入的根本原因是什么?
用户输入的信息中含有sql语句的关键字,并且这些关键字参与sql语句的编译过程,导致sql语句的原意被扭曲,进而达到sql注入。
解决注入现象:使用预编译
主要调整的部分
先写sql再获取预编译的操作对象
给占位符传值而不再需要用单引号自己写到参与编译的statement对象中
//获取预编译的数据库操作对象
//先写sql语句,再传递到对象中,用问号作为占位符,都用预编译的写法prepareXX
String sql = "select * from t_user where loginName=? and loginPassword=?";
preparedStatement = connection.prepareStatement(sql);
//给占位符?传值,第一个问号下标是1,从1开始,
//不要给问号加引号,set的类型自己就会判断加不加
preparedStatement.setString(1, loginName);
preparedStatement.setString(2, loginPassword);
//执行Sql语句就不用传参了
resultSet = preparedStatement.executeQuery();
能够解决该问题
用户名:
jdh
密码:
jdh' or '1'='1
{passWord=jdh' or '1'='1, userName=jdh}
登录失败
Process finished with exit code 0
完整代码
package BUPT20210330;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
//解决sql注入的问题
public class JDBCTest03 {
public static void main(String[] args) {
//初始化UI界面,尽量把所有的子功能写成单独的方法
//用Map来存
Map<String, String> userLoginInfo = Initiate_UI();
//验证用户名和密码
System.out.println(userLoginInfo);
//登录成功或者失败,就两种情况,所以用boolean
boolean loginSuccess = login(userLoginInfo);
System.out.println(loginSuccess ? "登录成功" : "登录失败");
}
private static boolean login(Map<String, String> userLoginInfo) {
//定义变量
boolean loginSuccess = false;
String loginName = userLoginInfo.get("userName");
String loginPassword = userLoginInfo.get("passWord");
//JDBC代码,按照JDBC六步走
PreparedStatement preparedStatement = null;
Connection connection = null;
ResultSet resultSet = null;
try {
//注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//建立数据库连接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mysql", "root", "333");
//获取预编译的数据库操作对象
//先写sql语句,再传递到对象中,用问号作为占位符,都用预编译的写法prepareXX
String sql = "select * from t_user where loginName=? and loginPassword=?";
preparedStatement = connection.prepareStatement(sql);
//给占位符?传值,第一个问号下标是1,从1开始,不要给问号加引号,set的类型自己就会判断加不加
preparedStatement.setString(1, loginName);
preparedStatement.setString(2, loginPassword);
//执行Sql语句就不用传参了
resultSet = preparedStatement.executeQuery();
//处理结果集
//因为对错与否都只有一个结果,所以不需要whiletrue,只需要简单的if
if (resultSet.next()) {
loginSuccess = true;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//释放资源
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null)
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
if (resultSet != null)
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return loginSuccess;
}
//上面给了返回值,那么生成的方法也一定要有返回值
private static Map<String, String> Initiate_UI() {
Scanner scanner = new Scanner(System.in);
System.out.println("用户名:");
//一次接受一行
String userName = scanner.nextLine();
System.out.println("密码:");
String passWord = scanner.nextLine();
Map<String, String> user_info = new HashMap<>();
user_info.put("userName", userName);
user_info.put("passWord", passWord);
return user_info;
}
}
比较Statement和PreparedStatement
对比一下statement和Preparedstatement
- Statement存在sql注入问题,Preparedstatement解决了sql注入问题。
- Statement是编译一次执行一次。Preparedstatement是编译一次,可执行n次。Preparedstatement效率较高一些。
- Preparedstatement会在编译阶段做类型的安全检查。
若是业务要求必须支持Sql注入的时候,就只能用Statement
比如写sql语句中包含一个 asc/desc排序,那么不能用占位符,占位符给进去就是一个字符串,而我们不能传用引号括起来的字符串
必须拼接用statement,传值用preparedstatement
如果还写成preparedstatement形式,就要报错
asc升序,desc降序
desc
java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax;
所以得改回statement形式
package BUPT20210330;
import java.sql.*;
import java.util.Scanner;
public class JDBCTest04 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("asc升序,desc降序");
String keyword = scanner.nextLine();
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mysql", "root", "333");
String sql = "select * from emp order by sal " + keyword;
statement = connection.createStatement();
resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
System.out.println(resultSet.getString("sal"));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}