一、使用PreparedStatement预编译语句防止SQL注入

什么是SQL注入?

所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。

举个例子:假如我们登录时执行的SQL语句为:select *from user where username='USERNAME' and password='PASSWORD';

但是我们可以把USERNAME填写为"tom';-- ",(注意--后有空格),PASSWORD随便写(假设这里写123),这样SQL语句就成了select *from user where username='tom';-- ' and password='123';

"-- "后的内容就被注释掉,现在就算密码不正确也能查询到相应的结果。利用SQL注入可以实现数据的盗取

在Java中使用PreparedStatement类防止SQL注入

防SQL注入的方法有很多,使用预编译语句是一种简单有效的方式

下面介绍如何使用这种方式来操作数据库

我已经在本地数据库mydb中创建了一个user表,并在表中插入数据

现在我们使用字符串拼接的方式来构造一个SQL语句,并在mysql客户端执行此SQL语句,结果如下:

通过图中我们发现这种方式SQL注入成功

下面使用预编译SQL语句的方式来执行此SQL语句

	 String url = "jdbc:mysql://localhost:3306/mydb";
String user = "root";
String password = "root";
String username = "杜若' or 1=1; -- "; //'-- ' 是sql中的注释符号(注意后面的空格)
String pwd = "000";
Class.forName("com.mysql.jdbc.Driver"); Connection connection = DriverManager.getConnection(url,user,password); //构造sql语句
String sql = "select *from user where username=? and pwd =?"; PreparedStatement pstmt = connection.prepareStatement(sql); pstmt.setString(1, username);
pstmt.setString(2, pwd); ResultSet rs = pstmt.executeQuery();
if(rs.next()){
do{
String username = rs.getString(2);
String pwd = rs.getString(3); System.out.println(username+":"+pwd);
}while(rs.next());
}else{
System.out.println("未查到相应的结果");
} if(rs!=null){
rs.close();
}
if(pstmt!=null){
pstmt.close();
}
if(connection!=null){
connection.close();
}

测试运行之后的结果

这样已经达到了防SQL注入的目的

那为什么它这样处理就能预防SQL注入提高安全性呢?其实是因为SQL语句在程序运行前已经进行了预编译,在程序运行时第一次操作数据库之前,SQL语句已经被数据库分析,编译和优化,对应的执行计划也会缓存下来并允许数据库已参数化的形式进行查询,当运行时动态地把参数传给PreprareStatement时,即使参数里有敏感字符如 or '1=1'也数据库会作为一个参数一个字段的属性值来处理而不会作为一个SQL指令

二,获取插入自增长值

有时候在插入一条记录的时候,我们需要获取插入这条数据的自增长值,以便在其他地方使用

直接上代码

//获取插入自增长
public class Demo1 {
private String user="root";
private String password="root";
private String url="jdbc:mysql://localhost:3306/mydb"; @Test
public void test1() throws Exception{
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection(url, user, password);
String sql = "insert into user(username,pwd) values(?,?)";
//第二个参数是Statement类中的一个常量,指示是否应该返回自动生成的键的标志
PreparedStatement pstmt = connection.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS); pstmt.setString(1, "mary");
pstmt.setString(2, "123456"); pstmt.executeUpdate(); ResultSet rs = pstmt.getGeneratedKeys();
if(rs.next()){
int key = rs.getInt(1);
System.out.println(key);
} if(rs!=null){
rs.close();
}
if(pstmt!=null){
pstmt.close();
}
if(connection!=null){
connection.close();
} }
}

三,批处理执行

有时候需要向数据库发送一批SQL语句执行,这时应避免向数据库一条条的发送执行,而应采用JDBC的批处理机制,以提升执行效率。

无论使用Statement对象还是使用PreparedStatement对象都可以实现

这里介绍使用PreparedStatement来实现的方式

  1. 获取PreparedStatement对象
  2. 设置每条批处理的参数
  3. 将一组参数添加到批处理命令中

下面上实例代码

public class Demo1 {
private String user="root";
private String password="root";
private String url="jdbc:mysql://localhost:3306/mydb"; @Test
public void test1() throws Exception{
List<User> list = new ArrayList<User>();
for(int i = 0;i < 10;i++){
User user = new User();
user.setUsername("albee"+i);
user.setPwd("123456");
list.add(user);
} sava(list); } public void sava(List<User> l) throws Exception{
Class.forName("com.mysql.jdbc.Driver"); Connection connection = DriverManager.getConnection(url, user, password);
String sql = "insert into user(username,pwd) values(?,?)";
PreparedStatement pstmt = connection.prepareStatement(sql); for(int i = 0;i<l.size();i++){
pstmt.setString(1, l.get(i).getUsername());
pstmt.setString(2, l.get(i).getPwd()); pstmt.addBatch(); // 每到五条就执行一次对象集合中的批处理命令,
if(i%5==0){
pstmt.executeBatch();
pstmt.clearBatch();
}
}
// 不足五条也要执行一次
pstmt.executeBatch();
pstmt.clearBatch(); if(pstmt!=null){
pstmt.close();
}
if(connection!=null){
connection.close();
}
}
}

四,事务的操作

有时候我们需要完成一组数据库操作,这其中的操作有一个失败则整个操作就回滚,即组成事务的每一个操作都执行成功整个事务才算成功执行

常见的例子就是银行转帐业务

update account set money=money-1000 where accountName='张三';

update account set money=money+1000 where accountName='李四';

已经在mydb中创建了account表,包含accountName和money字段,并插入了两条记录

实例代码:

// 使用事务
@Test
public void test2(){
String url = "jdbc:mysql://localhost:3306/mydb";
String user = "root";
String password = "root";
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection(url,user,password);
connection.setAutoCommit(false); //设置事务为手动提交
String sql_zs = "update account set money=money-1000 where accountName='张三'";
String sql_ls = "update account set money=money+1000 where accountName='李四'"; pstmt = connection.prepareStatement(sql_ls);
int count_ls = pstmt.executeUpdate(); pstmt = connection.prepareStatement(sql_zs);
int count_zs = pstmt.executeUpdate(); }catch (Exception e) {
e.printStackTrace();
try {
connection.rollback();
} catch (Exception e2) {
e2.printStackTrace();
}
} finally {
try {
connection.commit();
} catch (SQLException e1) {
e1.printStackTrace();
}
if(pstmt!=null){
try {
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(connection!=null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}

如果事务执行成功

执行前和执行后表的变动

JDBC加强的更多相关文章

  1. Java数据库连接技术——JDBC

    大家好,今天我们学习了Java如何连接数据库.之前学过.net语言的数据库操作,感觉就是一通百通,大同小异. JDBC是Java数据库连接技术的简称,提供连接各种常用数据库的能力. JDBC API ...

  2. 玩转spring boot——结合AngularJs和JDBC

    参考官方例子:http://spring.io/guides/gs/relational-data-access/ 一.项目准备 在建立mysql数据库后新建表“t_order” ; -- ----- ...

  3. [原创]java使用JDBC向MySQL数据库批次插入10W条数据测试效率

    使用JDBC连接MySQL数据库进行数据插入的时候,特别是大批量数据连续插入(100000),如何提高效率呢?在JDBC编程接口中Statement 有两个方法特别值得注意:通过使用addBatch( ...

  4. JDBC MySQL 多表关联查询查询

    public static void main(String[] args) throws Exception{ Class.forName("com.mysql.jdbc.Driver&q ...

  5. JDBC增加删除修改

    一.配置程序--让我们程序能找到数据库的驱动jar包 1.把.jar文件复制到项目中去,整合的时候方便. 2.在eclipse项目右击"构建路径"--"配置构建路径&qu ...

  6. JDBC简介

    jdbc连接数据库的四个对象 DriverManager  驱动类   DriverManager.registerDriver(new com.mysql.jdbc.Driver());不建议使用 ...

  7. JDBC Tutorials: Commit or Rollback transaction in finally block

    http://skeletoncoder.blogspot.com/2006/10/jdbc-tutorials-commit-or-rollback.html JDBC Tutorials: Com ...

  8. FineReport如何用JDBC连接阿里云ADS数据库

    在使用FineReport连接阿里云的ADS(AnalyticDB)数据库,很多时候在测试连接时就失败了.此时,该如何连接ADS数据库呢? 我们只需要手动将连接ads数据库需要使用到的jar放置到%F ...

  9. JDBC基础

    今天看了看JDBC(Java DataBase Connectivity)总结一下 关于JDBC 加载JDBC驱动 建立数据库连接 创建一个Statement或者PreparedStatement 获 ...

  10. Spring学习记录(十四)---JDBC基本操作

    先看一些定义: 在Spring JDBC模块中,所有的类可以被分到四个单独的包:1.core即核心包,它包含了JDBC的核心功能.此包内有很多重要的类,包括:JdbcTemplate类.SimpleJ ...

随机推荐

  1. django中的时区问题

    在django中设置时区,通过setting文件中的: TIME_ZONE = 'Asia/Shanghai' 开起多时区支持功能:USE_TZ=True 这时在数据库中插入的时间为UTC时间,当调用 ...

  2. Shell 中的 expect 命令

    目录 expect 介绍 expect 安装 expect 语法 自动拷贝文件到远程主机 示例一 示例二 示例三 示例四 expect 介绍 借助 expect 处理交互的命令,可以将交互过程如 ss ...

  3. Centos 7.6关闭selinux

    查看selinux状态 [root@localhost ~]# sestatus SELinux status: enabled SELinuxfs mount: /sys/fs/selinux SE ...

  4. Springboot集成邮箱服务发送邮件

    一.前言 Spring Email 抽象的核心是 MailSender 接口,MailSender 的实现能够把 Email 发送给邮件服务器,由邮件服务器实现邮件发送的功能. Spring 自带了一 ...

  5. JVM调优2-远程监控

    监控远程JVM VisualJVM不仅是可以监控本地jvm进程,还可以监控远程的jvm进程,需要借助于JMX技术实现. 什么是JMX JMX(Java Management Extensions,即J ...

  6. 快速删除IDEA/WebStrom/Rider中的代码空行

    使用替换 ^\s*\n 并打开正则匹配模式   Visual Studio中未测试,大家可以去试一试

  7. golang中的反射reflect详解

    先重复一遍反射三定律: 1.反射可以将"接口类型变量"转换为"反射类型对象". 2.反射可以将"反射类型对象"转换为"接口类型变量 ...

  8. vue常用组件

    滚动组件:better-scroll   官网地址:https://ustbhuangyi.github.io/better-scroll/doc/zh-hans/installation.html ...

  9. Python数据结构之“栈”与“队列”

    栈(Stacks): ·定义:是一种只能通过访问其一端来实现的数据存储于检索的线性数据结构,具有后进先出(last in first out,LIFO)的特征 ·主要操作: 1. Stack():建立 ...

  10. HOW2J 全套教程整理:Java、前端、数据库、中间件、第三方、项目、面试题

    考虑到部分同学寝室会断网,原站的所有的免费内容都提供了一个离线版本以供使用.但是它直接提供了静态页面,并不方便在手机上阅读,因为我将其转换为 EPUB. 目录 HOW2J J2EE 教程.epub H ...