加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

JDBC—03—SQL注入问题;PreparedStatement介绍;

发布时间:2020-12-15 07:33:50 所属栏目:Java 来源:网络整理
导读:一、 JDBC的使用 ? 9.SQL 注入问题 9.1 什么是 SQL 注入 所谓 SQL 注入,就是通过把 `含有 SQL 语句片段的参数` 插入到需要执行的 SQL 语句中,然后statement把SQL语句发送到数据库中,数据库进行编译,?最终达到欺骗数据库服务器执行恶意操作的 SQL 命令。 9.

一、 JDBC的使用

?

9.SQL 注入问题

9.1什么是 SQL 注入

所谓 SQL 注入,就是通过把 `含有 SQL 语句片段的参数` 插入到需要执行的 SQL 语句中,然后statement把SQL语句发送到数据库中,数据库进行编译,?最终达到欺骗数据库服务器执行恶意操作的 SQL 命令。

9.2如何解决?

因为statement没有SQL语句预编译的能力,所以会是数据库执行到恶意SQL命令;

我们换一个有预编译能力的statement对象就行了---PreparedStatement;

?

?

?

10.PreparedStatement 对象的使用(重点)

(1)PreparedStatement 特点:

  • PreparedStatement 接口继承 Statement 接口
  • PreparedStatement 效率高于 Statement
  • PreparedStatement 支持动态绑定参数
  • PreparedStatement 具备 SQL 语句预编译能力,所以使用 PreparedStatement 可防止出现 SQL 注入问题

(2)?通过 PreparedStatement 对象向表中插入数据:

//向 Departments 表中插入一条数据

try{

conn = JdbcUtil.getConnection();

//再也不用拼接字符串或者参数了,参数用占位符`?`表示,然后在单独对占位符赋值就好了; 

ps = conn.prepareStatement("insert into departmentsvalues(default,?,?)");

ps.setString(1,departmentName);

ps.setInt(2,locationId);

ps.execute();

}catch(Exception e){

e.printStackTrace();

}finally{

JdbcUtil.closeResource(ps,conn,null);

}
}

?

?

?

?

11. PreparedStatement 的预编译能力

11.1什么是预编译

(1)SQL 语句的执行步骤

  • 语法和语义解析
  • 优化 sql 语句,制定执行计划
  • 执行并返回结果

但是很多情况,我们的一条 sql 语句可能会反复执行,或者每次执行的时候只有个别的值不同(比如 select 的 where 子句值不同,update 的 set 子句值不同,insert 的 values 值不同)。如果每次都需要经过硬解析----上面的词法语义解析、语句优化、制定执行计划等,那效率就明显不行了。

所谓预编译语句就是将这类语句中的值用占位符替代,可以视为将 sql 语句模板化或者说参数化;

预编译语句的优势在于:一次编译、多次运行,省去了解析优化等过程(将完全硬解析变成了硬软都有);此外预编译语句能防止 sql 注入;

(2)解析过程

  • 硬解析:在不开启缓存执行计划的情况下,每次 SQL 的处理都要经过:语法和语义的解析,优化器处理 SQL,生成执行计划。整个过程我们称之为硬解析。
  • 软解析如果开启了缓存执行计划,数据库在处理 sql 时会先查询缓存中是否含有与当前SQL语句相同的执行计划,如果有则直接执行该计划。(我们所谓的预编译也就是软解析;)

11.2预编译方式

  • 开始数据库的日志
  • show VARIABLES like ‘%general_log%‘
  • set GLOBAL general_log = on
  • set GLOBAL log_output=‘table‘

(1)依赖数据库驱动完成预编译

如果我们没有开启数据库服务端编译,那么默认的是使用数据库驱动完成 SQL 的预编

译处理。

(2)依赖数据库服务器完成预编译

我们可以通过修改连接数据库的 URL 信息,添加 useServerPrepStmts=true 信息开启服

务端预编译。

?

?

?

12.?通过 PreparedStatement 对象完成数据的更新

代码

//更新数据

public void updateDepartment(int departmentId,String

departmentName,int localhostId){

Connection conn= null;

PreparedStatement ps = null;

try{

conn = JdbcUtil.getConnection();

ps = conn.prepareStatement("update departments set

department_name = ?,location_id = ? where department_id = ?");

ps.setString(1,localhostId);

ps.setInt(3,departmentId);

ps.execute();

}catch(Exception e){

e.printStackTrace();

}finally{

JdbcUtil.closeResource(ps,null);

}

}

?

?

?

13.?通过 PreparedStatement 对象完成数据的查询

(1)查询返回单条结果集

public Departments selectDepartmentsById(intdepartmentId){

Connection conn = null;

PreparedStatement ps = null;

ResultSet rs = null;

Departments dept = null;

try{

conn = JdbcUtil.getConnection();

ps = conn.prepareStatement("select * from

departments where department_id = ?");

ps.setInt(1,departmentId);

rs = ps.executeQuery();

while(rs.next()){

dept=new Departments();

dept.setDepartmentId(rs.getInt("department_id"));

dept.setDepartmentName(rs.getString("department_name"));

dept.setLocationId(rs.getInt("location_id"));

}

}catch(Exception e){

e.printStackTrace();

}finally{

JdbcUtil.closeResource(ps,rs);

}

return dept;

}

?

(2)查询返回多条结果集

建立了一个集合而已,然后不断地输出这个集合的信息就可以了;?

//查询部门表中的部门名称,找到那些包含“人力”的部门信息

public List selectDepartmentByLikeName(String departmentName){

Connection conn = null;

PreparedStatement ps = null;

ResultSet rs = null;

List list = new ArrayList<>();

try{

  conn = JdbcUtil.getConnection();

  ps = conn.prepareStatement("select * from

  departments where department_name like ?");

  ps.setString(1,"%"+departmentName+"%");//注意like子句,的like关键字要和占位符拼在一起;

  rs = ps.executeQuery();

  while(rs.next()){Departments dept = new Departments();

  dept.setDepartmentId(rs.getInt("department_id"));

  dept.setDepartmentName(rs.getString("department_name"));

  dept.setLocationId(rs.getInt("location_id"));

  list.add(dept);

}

}catch(Exception e){

e.printStackTrace();

}finally{

JdbcUtil.closeResource(ps,rs);

}
return list;
}

?

?

14. PreparedStatement 批处理操作

批处理:在与数据库的一次连接中,批量的执行条 SQL 语句。

14.1代码

//批量添加

public void addBatch(List list){

Connection conn = null;

PreparedStatement ps = null;

try{

conn = JdbcUtil.getConnection();

ps = conn.prepareStatement("insert into departments

values(default,?)");

for(int i=0;i<list.size();i++){

ps.setString(1,

list.get(i).getDepartmentName());

ps.setInt(2,list.get(i).getLocationId());

//添加批处理

ps.addBatch();

}

int[] arr =ps.executeBatch();

for(int i=0;i<arr.length;i++){

System.out.println(i);

}

}catch(Exception e){

e.printStackTrace();

}finally{JdbcUtil.closeResource(ps,null);

}

}

?

?

15. JDBC 中的事务处理

在 JDBC 操作中数据库事务默认为自动提交。如果事务需要修改为手动提交,那么我们

需要使用 Connection 对象中的 setAutoCommit 方法来关闭事务自动提交。然后通过

Connection 对象中的 commit 方法与 rollback 方法进行事务的提交与回滚。

15.1代码

//事务处理

public void deleteDempartments(String depratmentName){

Connection conn = null;

PreparedStatement ps = null;

try{

conn = JdbcUtil.getConnection();

//关闭事务的自动提交

conn.setAutoCommit(false);

ps = conn.prepareStatement("delete from departments

where department_name like ?");

ps.setString(1,"%"+depratmentName+"%");

ps.executeUpdate();

ps = conn.prepareStatement("insert into departments

values(default,‘开发部‘,2)");

ps.executeUpdate();

String str = null;

str.length();

conn.commit();

}catch(Exception e){

e.printStackTrace();

JdbcUtil.rollback(conn);

}finally{

JdbcUtil.closeResource(ps,null);

}

}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读