JDBC基础内容2

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: JDBC基础内容2

执行DML语句:

包括增删改,这里我们以修改作为例子进行讲解

举例:

package MyJDBC;
import org.junit.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class myjdbc_test {
   //单元测试:必须导入junit,快速导入的方法:Alt+回车,点击junit4,注意必须在联网环境下
   @Test
   public void test_demo() throws ClassNotFoundException, SQLException {
      //注册驱动
      Class.forName("com.mysql.cj.jdbc.Driver");
      //获取连接
      String url="jdbc:mysql://localhost:3306/myjdbc";
      String username="root";
      String password="xxx";
      Connection connection= DriverManager.getConnection(url,username,password);
      //定义SQL
      String sql="update person set age=18 where id=2";
      //获取执行SQL的对象Statement
      Statement statement=connection.createStatement();
      //执行sql
      int count_row=statement.executeUpdate(sql);
      System.out.println(count_row);
      //释放资源
      statement.close();
      connection.close();
   }
}

输出:

在mysql中查询数据:

当所修改的数据不存在时:

虽然这样能够正确的修改结果,但并不是最优方案,因为输出的影响行数对于用户来说,没有任何意义,因此,我们需要将输出影响行数的内容修改为提示信息。

修改如下:

将输出影响行数的代码修改为如下代码:

if(count_row>0){
         System.out.println("修改成功");
      }else{
         System.out.println("修改失败");
      }

当要修改的数据不存在时,就会提示修改失败的信息:

执行DDL语句:

将myjdbc_test做如下修改:

在mysql中进行查询:

删除刚创建的数据库:

package MyJDBC;
import org.junit.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class myjdbc_test {
   //Alt+回车,注意必须在联网环境下
   @Test
   public void test_demo() throws ClassNotFoundException, SQLException {
      //注册驱动
      Class.forName("com.mysql.cj.jdbc.Driver");
      //获取连接
      String url="jdbc:mysql://localhost:3306/?";
      String username="root";
      String password="xxx";
      Connection connection= DriverManager.getConnection(url,username,password);
      //定义SQL
      String sql="drop database myjdbc1";
      //获取执行SQL的对象Statement
      Statement statement=connection.createStatement();
      //执行sql
      int count_row=statement.executeUpdate(sql);
      System.out.println(count_row);
      //释放资源
      statement.close();
      connection.close();
   }
}

idea输出:

虽然返回值为0,但是在mysql中进行查询,我们会发现该数据库已经成功被删除,因为DDL语句执行后,执行成功也可能返回0,正是由于这个原因,所以我们不能像上面执行DML语句一样,通过返回值来判断是否成功。

判断DDL语句是否执行成功的方法很简单,只要未报错即认为执行成功;

举例:

ResultSet:

ResultSet[结果集对象]作用:

ResultSet  executeQuery(sql):执行DQL语句[数据查询语句]
//返回值:ResultSet结果集对象

获取查询结果:

boolean next():
1:将光标从当前位置向前移动一行
2:判断当前行是否为有效行
//返回值:
true:有效行,当前行有数据
false:无效行,当前行没有数据

如下所示:

光标需要从上到下依次判断当前行是否有效,因此,判断数据是否有效的过程是一个循环的过程:

while(rs.next()){
//获取数据
rs.getXXX(参数);
}
xxx getXXX(参数):获取数据
xxx:数据类型,如int getInt(参数):String getString(参数)
参数:int:列的编号,从1开始  String:列的名称

举例:

package MyJDBC;
import org.junit.Test;
import java.sql.*;
public class myjdbc_test {
   //Alt+回车,注意必须在联网环境下
   @Test
   public void test_demo() throws ClassNotFoundException, SQLException {
      //注册驱动
      Class.forName("com.mysql.cj.jdbc.Driver");
      //获取连接
      String url="jdbc:mysql://localhost:3306/myjdbc";
      String username="root";
      String password="xxx";
      Connection connection= DriverManager.getConnection(url,username,password);
      //定义SQL语句
      String sql="select * from person";
      //获取statement对象
      Statement statement=connection.createStatement();
      //执行SQL
      ResultSet resultSet=statement.executeQuery(sql);
      //处理结果,遍历resultSet中的所有数据
      //光标移动到下一行,并且判断当前行是否有数据
      while(resultSet.next()){
      //第一种写法:
         int id=resultSet.getInt(1);
         int age=resultSet.getInt(2);
         String name=resultSet.getString(3);
      //第二种写法:
          //int id=resultSet.getInt("id");
         //int age=resultSet.getInt("age");
         //String name=resultSet.getString("name");
         System.out.println(id);
         System.out.println(age);
         System.out.println(name);
         System.out.println("--------------------------");
      }
      //关闭资源
      resultSet.close();
      statement.close();
      connection.close();
   }
}

输出:

1
24
张三
--------------------------
2
18
李军
--------------------------
3
24
张伟
--------------------------

ResultSet简单应用:

要求:查询person账户表数据,封装为Person对象中,并且存储到ArrayList集合当中

步骤:

a:定义实体类person

package pdjo;
public class Person {
//注意:这里的字段要和数据库中的表的字段对应
    private int id;
    private int age;
    private  String name;
    public void setId(int id) {
        this.id = id;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getId() {
        return id;
    }
    public int getAge() {
        return age;
    }
    public String getName() {
        return name;
    }
    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

b:查询数据,封装到person对象中,将person对象存入ArrayList集合中

package pdjo;
import org.junit.Test;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
    public class myjdbc_test {
        @Test
        public void test_demo() throws ClassNotFoundException, SQLException {
            //注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            //获取连接
            String url="jdbc:mysql://localhost:3306/myjdbc";
            String username="root";
            String password="xxx";
            Connection connection= DriverManager.getConnection(url,username,password);
            //定义SQL语句
            String sql="select * from person";
            //获取statement对象
            Statement statement=connection.createStatement();
            //执行SQL
            ResultSet resultSet=statement.executeQuery(sql);
            //创建集合
            List<Person> personList=new ArrayList<>();
            //处理结果,遍历resultSet中的所有数据
            //光标移动到下一行,并且判断当前行是否有数据
            while(resultSet.next()){
                //创建对象操作
                Person person=new Person();
                int id=resultSet.getInt("id");
                int age=resultSet.getInt("age");
                String name=resultSet.getString("name");
                //赋值操作
                person.setId(id);
                person.setAge(age);
                person.setName(name);
                //将对象放入集合
                personList.add(person);
            }
            //输出集合中的数据
            System.out.println(personList);
            //关闭资源
            resultSet.close();
            statement.close();
            connection.close();
        }
    }

输出:

[Person{id=1, age=17, name='张三'}, Person{id=2, age=21, name='李军'}, Person{id=3, age=24, nam

PreparedStatement:

PreparedStatement作用:

预编译SQL语句并执行:预防SQL注入问题

SQL注入:SQL注入是通过操作输入来修改事先定义好的SQL语句,用以到达执行代码对服务器进行攻击的方法

恶意的SQL语句会入侵数据库,甚至对数据库产生破坏:

String sql="select * from tb_name where name='"+varname+"' and password='"+varpassword+"'";

对于上述SQL语句,如果我们将' or 1=1 or ' 或者'or'1'='1作为varpassword传进来,那么无论用户名是什么,都会登录成功

举例:

package MyJDBC;
import pdjo.Person;
import java.sql.*;
public class myjdbc {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //获取连接
        String url="jdbc:mysql://localhost:3306/MyJDBC";
        String username="root";
        String password="xxxx";
        Connection connection= DriverManager.getConnection(url,username,password);
        //接收用户输入:用户名和密码
        String name="张三";
        String pwd="'or'1'='1";
        //定义SQL
        String SQL="select * from user_info where name='"+name+"' and password='"+pwd+"'";
        //获取Statement对象
        Statement Statement= connection.createStatement();
        ResultSet resultSet=Statement.executeQuery(SQL);
        //判断是否登录成功
        if(resultSet.next()){
            System.out.println("登录成功");
        }else{
            System.out.println("登录失败");
        }
        //关闭资源
        resultSet.close();
        Statement.close();
        connection.close();
    }
}

输出:

原因是:

  String SQL="select * from user_info where name='任意' and password=''or'1'='1'";

上述这条SQL语句'1'='1'一定成立,因此可以通过任何的验证,但是有些数据库是不会让这种恶意的SQL语句执行成功的,但也有很多数据库可以让这些语句得到执行,而如果使用预编译语句,传入的任何内容就不会和原来的语句发生任何匹配关系,只要安全使用预编译语句,就不需要对传入的数据做任何过滤。


通过PreparedStatement对象解决注入问题:

package MyJDBC;
import pdjo.Person;
import java.sql.*;
public class myjdbc {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //获取连接
        String url="jdbc:mysql://localhost:3306/MyJDBC";
        String username="root";
        String password="xxx";
        Connection connection= DriverManager.getConnection(url,username,password);
        //接收用户输入:用户名和密码
        String name="lisa";
        String pwd="'or'1'='1";
        //定义SQL
        String SQL="select * from user_info where name='?' and password='?'";
        //获取Statement对象
        PreparedStatement preparedStatement= connection.prepareStatement(SQL);
        ResultSet resultSet=preparedStatement.executeQuery();
        //判断是否登录成功
        if(resultSet.next()){
            System.out.println("登录成功");
        }else{
            System.out.println("登录失败");
        }
        //关闭资源
        resultSet.close();
        preparedStatement.close();
        connection.close();
    }
}

此时的密码依然是上述发生SQL注入问题的时的密码,但当对象为PreparedStatement,登录失败:

那么PreparedStatement对象是如何解决这个注入问题呢?

将特殊字符进行转义操作

转义前:

转义后:

1:获取PreparedStatement对象:

//sql语句中的参数值,使用?占位符替代
String SQL="select * from user where username=? and password=?";
//通过Connection对象获取,并传入对应的SQL语句
PreparedStatement pstmt=conn.preparedStatement(sql); 

2:设置参数值

PreparedStatement对象:setXXX(参数1,参数2,参数3…):给?赋值

XXX:

数据类型:如setInt(参数1,参数2)

参数:

参数1:?的位置编号,从1开始
参数2:?的值

执行SQL:

executeQuery();不需要再传递SQL
package MyJDBC;
import pdjo.Person;
import java.sql.*;
public class myjdbc {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //获取连接
        String url="jdbc:mysql://localhost:3306/MyJDBC";
        String username="root";
        String password="xxx";
        Connection connection= DriverManager.getConnection(url,username,password);
        //定义SQL
        String SQL="insert into person(id,age,name) values(?,?,?)";
        //获取Statement对象
        PreparedStatement preparedStatement= connection.prepareStatement(SQL);
        //设置?的值:在设置时,数据类型一定要和数据库中表的字段类型一致
        preparedStatement.setInt(1,3);
        preparedStatement.setInt(2,19);
        preparedStatement.setString(3,"lucy");
        preparedStatement.executeUpdate();
        preparedStatement.close();
        connection.close();
    }
}

在数据库查询数据:

PreparedStatement原理:

PreparedStatement好处

预编译SQL,性能高,并且可以防止SQL注入,将敏感字符进行转义

PreparedStatement预编译功能开启:userServerPreStmts=true

配置mysql执行日志(重启MySQL服务器后生效):

mysql中的ini文件中编写如下代码:

log-output=FILE
general-log=1
general_log_file="D:\mysql.log"
slow-query-log=1
slow_query_log_file="D:\mysql_slow.log"
long_query_time=2

执行SQL语句,查看 D:\mysql.log 日志,即可发现SQL语句中的单引号都被加上了转义字符

PreparedStatement原理:

1:在获取PreparedStatement对象时,将SQL语句发送给mysql服务器进行检查,编译[耗时]
2:执行时就不用再进行这些步骤了,速度较快
3:如果SQL模板一样,则只需要进行一次检查,编译

举例:

未使用预编译

select * from tb_user where username='zhangsan';
select * from tb_user where username-'lisa';

使用编译

select * from tb_user where username=?;
setString(1,'zhangsan');
setString(1,'lisa');

第一种未使用预编译,那么程序每次运行都会经历检查SQL语法,编译SQL,执行SQL这三个步骤,但是使用预编译,前两个步骤只执行一次,此后只需要执行第三个步骤即可。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
11月前
|
SQL Java 关系型数据库
JDBC基础内容
JDBC基础内容
|
11月前
|
Java 关系型数据库 MySQL
JDBC知识【JDBC概述】第一章
JDBC知识【JDBC概述】第一章
|
11月前
|
SQL Java 关系型数据库
JDBC知识【JDBC API详解】第三章下篇
JDBC知识【JDBC API详解】第三章下篇
|
4月前
|
SQL Java 关系型数据库
JDBC技术【JDBC概述、获取数据库连接、 下载数据库驱动】(一)-全面详解(学习总结---从入门到深化)
JDBC技术【JDBC概述、获取数据库连接、 下载数据库驱动】(一)-全面详解(学习总结---从入门到深化)
107 0
JDBC技术【JDBC概述、获取数据库连接、 下载数据库驱动】(一)-全面详解(学习总结---从入门到深化)
|
4月前
|
SQL Java 关系型数据库
JDBC技术【SQL注入、JDBC批量添加数据、JDBC事务处理、其他查询方式】(三)-全面详解(学习总结---从入门到深化)
JDBC技术【SQL注入、JDBC批量添加数据、JDBC事务处理、其他查询方式】(三)-全面详解(学习总结---从入门到深化)
55 0
|
存储 SQL Java
jdbc概述
jdbc概述
79 0
|
SQL Oracle 安全
如何使用JDBC操作数据库?一文带你吃透JDBC规范(一)
如何使用JDBC操作数据库?一文带你吃透JDBC规范(一)
378 1
|
存储 SQL Java
JDBC概述
JDBC概述
79 0
|
SQL druid Java
如何使用JDBC操作数据库?一文带你吃透JDBC规范(二)
如何使用JDBC操作数据库?一文带你吃透JDBC规范(二)
105 0
|
Java 数据库连接
JDBC学习(十二):使用BeanHandler实现查询
JDBC学习(十二):使用BeanHandler实现查询
190 0