一、 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 表中插入一条数据: conn = JdbcUtil.getConnection(); //再也不用拼接字符串或者参数了, 参数用占位符`?`表示, 然后在单独对占位符赋值就好了; ps = conn.prepareStatement("insert into departmentsvalues(default,?,?)"); ps.setString(1, departmentName); ps.setInt(2, locationId); ps.execute();
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 对象完成数据的更新
代码
更新数据 conn = JdbcUtil.getConnection(); ps = conn.prepareStatement("update departments set department_name = ?,location_id = ? where department_id = ?"); ps.setString(1, departmentName); ps.setInt(2, localhostId); ps.setInt(3, departmentId); ps.execute();
13. 通过 PreparedStatement 对象完成数据的查询
(1)查询返回单条结果集
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")); }
(2)查询返回多条结果集
建立了一个集合而已, 然后不断地输出这个集合的信息就可以了;
上图有个bug, 大家可以试着找找看;
既然是模糊查询, 怎么能用`=`, 应该用 `like`;
14. PreparedStatement 批处理操作
批处理:在与数据库的一次连接中,批量的执行条 SQL 语句。
代码:
注意:addBatch()和executeBatch();
15. JDBC 中的事务处理
在 JDBC 操作中数据库事务默认为自动提交。
如果事务需要修改为手动提交,那么我们需要使用 Connection 对象中的 setAutoCommit 方法来关闭事务自动提交, 然后通过Connection 对象中的 commit 方法与 rollback 方法进行事务的提交与回滚。