【JDBC】笔记(3)

database

1.Statement 编译一次,只执行一次,PreparedStatement 编译一次,可执行n次,所以 PreparedStatement 效率较高......

一.实现功能:

    1.解决“应用Statement的登录系统”存在的SQL注入问题
    2.用户信息表
    +----+-----------+----------+----------+
    | id | loginName | loginPwd | realName |
    +----+-----------+----------+----------+
    |  1 | abc       | 123      | 张三     |
    |  2 | wwe       | 456      | 李四     |
    +----+-----------+----------+----------+

 

二.代码实现:

 

import java.sql.*;

import java.util.*;

public class JDBCTest02 {

public static void main(String[] args) {

//初始化界面(用户输入账号和密码)

Map<String,String> userLoginInfo = initUI();

//验证用户名和密码(JDBC)

boolean loginSuccess = login(userLoginInfo);

//显示结果:

System.out.println(loginSuccess==true?"登录成功":"登录失败");

}

/**

* 验证用户登录信息是否正确

* @param userLoginInfo 用户登录信息

* @return false 表示登录失败,true 表示登录成功

*/

private static boolean login(Map<String, String> userLoginInfo) {

//打标记(登录结果)

boolean loginSuccess = false;

Connection connection = null;

PreparedStatement ps = null;

ResultSet resultSet = null;

try {

//1、注册驱动

Class.forName("com.mysql.cj.jdbc.Driver");

//2、获取连接

connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode",

"root","888");

//3、获取预编译的数据库操作对象

//一个?代表一个占位符,一个?接受一个“值”

String sql = "select * from t_user where loginName = ? and loginPwd = ? ";

//程序执行到此处,会发送sql语句框子给DBMS,然后DBMS进行sql的编译

ps = connection.prepareStatement(sql);

//给占位符传值(第一个?下标是1,第二个?下标是2,JDBC的的下标从1开始)

ps.setString(1,userLoginInfo.get("loginName"));

ps.setString(2,userLoginInfo.get("loginPwd"));

//4、执行sql

resultSet = ps.executeQuery();

//5、处理结果集

//不需要while结果集,因为查询结果不是 无 就是 1条记录

if (resultSet.next()){

loginSuccess = true;

}

} catch (Exception e) {

e.printStackTrace();

}finally {

//从小到大分别关闭三个资源

if (resultSet != null) {

try {

resultSet.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

if (ps != null) {

try {

ps.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

if (connection != null) {

try {

connection.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

}

//最后返回 登录结果(boolean)

return loginSuccess;

}

/**

* 初始化用户界面

* @return 用户的用户名和密码(Map)

*/

private static Map<String, String> initUI() {

Scanner s=new Scanner(System.in);

System.out.println("用户名:");

String loginName = s.nextLine();

System.out.println("密码:");

String loginPwd = s.nextLine();

//用 HashMap(键值对的方式)存储用户输入的 账号和密码

Map<String,String> userLoginInfo = new HashMap<>();

userLoginInfo.put("loginName",loginName);

userLoginInfo.put("loginPwd",loginPwd);

return userLoginInfo;

}

}

 

三.效果展示:

1.使用 PreparedStatement 解决了SQL注入问题:

用户名:

yyds

密码:

yyds" or "1"="1

登录失败

Process finished with exit code 0

2.注意:

1)JDBC代码部分的第三步 --- 获取预编译的数据库操作对象(不同于Statement):

先写好sql语句模型:

String sql = "select * from t_user where loginName = ? and loginPwd = ? ";

发送sql语句框子给DBMS,然后DBMS准备进行sql的编译:

ps = connection.prepareStatement(sql);

给占位符传值:?的值为String就setString,?的值为int就setInt ...

ps.setString(1,userLoginInfo.get("loginName"));

ps.setString(2,userLoginInfo.get("loginPwd"));

 

四.Statement 与 PreparedStatement 对比:

1.Statement 编译一次执行一次,PreparedStatement 编译一次,可执行n次,所以 PreparedStatement 效率较高;

2.PreparedStatement 比 Statement 更加安全;

3.Statement 可以完成根据用户的意愿,通过输入sql语句来实现相应的功能,比如:升序(asc)/降序(desc):

1)假设使用 PreparedStatement:

用户想通过按“账号首字母”升序的方式看到用户的信息,所以向?传入“asc”,但这样运行是会报错的,因为实际执行的sql语句是:
select * from t_user order by loginName "asc" //那这俩单引号是什么鬼嘛,执行肯定报错啊,所以这时只能选择 Statement

String sql = "select * from t_user order by loginName ?";

ps = connection.prepareStatement(sql);

ps.setString(1,"asc");

resultSet = ps.executeQuery();

2)假设使用 Statement:

statement = connection.createStatement();

String sql = "select * from t_user order by loginName asc";

resultSet = statement.executeQuery(sql);

while (resultSet.next()) {

System.out.println(resultSet.getString("loginName"));

}

这样就可以根据 loginName 首字母大小升序的方式来输出 loginName:

abc

wwe

Process finished with exit code 0

 

以上是 【JDBC】笔记(3) 的全部内容, 来源链接: utcz.com/z/536210.html

回到顶部