快速学会使用JDBC+原理的全面详解(一)

快速学会使用JDBC+原理的全面详解

目录

一、JDBC是什么、用来干什么

1.1 概述:

JDBC(Java Data Base Connectivity, java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。**总结而言,JDBC就是Java用于执行SQL语句实现数据库操作的API。**它就是JAVA与数据库连接的桥梁或者插件,用JAVA代码就能操作数据库的增删改查、存储过程、事务等。

1.2 JDBC的作用

用JAVA就能连接到数据库;创建SQL或者MYSQL语句;执行SQL或MYSQL的查询数据库;查看和修改数据库中的数据记录。

1.3 工作原理图

jdbc工作原理图(来自百度)

数据库是由不同生产产商决定的,例如Mysql、Oracle、SQL Server,而如果JAVA 如何对不同数据库的实现管理和操作?为了更便捷和灵活地使用高级语言直接对数据库进行管理,JDBC因此而产生,JDBC是一套协议,是JAVA开发人员和数据库厂商达成的协议,也就是由Sun公司定义一组接口,由数据库厂商来具体实现。
如上图所示,我们工作人员编写应用程序(application),通过不同的数据库产商对Sun公司定义的JDBC驱动接口的具体实现类(数据库驱动),来实现对数据库的操作。

二、JDBC程序的编写步骤

2. 1 具体步骤

(1) 注册驱动
JDBC类库向DriverManager注册数据库驱动·
(2)建立连接(url、username、password)
使用DriverManager提供的getConnection()方法连接到数据库
(3)创建SQL语句,获取语句执行对象
编写SQL语句,并建立SQL语句执行对象
(4)执行语句
执行SQL语句,并将结果集合返回到ResultSet中
(5)处理结果
(6)释放资源(注意关闭的顺序)

2.2 代码案例

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

static void test() throws SQLException, ClassNotFoundException {
  //1.注册驱动
  //方式一
//  DriverManager.registerDriver(new com.mysql.jdbc.Driver());
  //方式二:多个驱动的话用冒号:隔开
//  System.setProperty("jdbc.drivers", "com.mysql.jdbc.Driver");
  **//方式三:推荐方式**
   Class.forName("com.mysql.jdbc.Driver");
  
  //2.建立连接
   String url="jdbc:mysql://localhost:3306/jdbc";//url格式:jdbc:子协议:子名称//主机名:端口/数据库名称
   String name="root";
   String password="mysql";
   Connection conn=DriverManager.getConnection(url,name,password);
  //3.创建SQL语句,,并建立SQL语句执行对象
   sql="select * from user";//创建SQL语句
   Statement st=conn.createStatement();//SQL语句执行对象
  //4.执行语句
   ResultSet rs=st.executeQuery(sql);
  //5.处理结果
   while(rs.next()) {//按行遍历
    System.out.println(rs.getObject(1)+"\t"+rs.getObject(2)+"\t"
      +rs.getObject(3)+"\t"+rs.getObject(4)+"\t");//获取每一列
   
  }
  //6.释放资源(后创建的先关闭)
  rs.close();
  st.close();
  conn.close();
  
  
 }

2.3 步骤详解

(1)注册驱动

2.2中的程序注册驱动一步给出了三种方式,Class.forName(),是最常见的注册JDBC驱动程序的方法,注册某数据库就将该数据库驱动的名称以字符串的形式作为参数。不同的数据库具有不同的但是固定的驱动名称。2.2中的案例是以MySQL数据库为例,驱动名称为:com.mysql.jdbc.Driver
其他数据库对应的驱动名称如下:
数据库驱动名称和URL格式
以MySQL数据库为例,注册驱动的代码如下:

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

(2)建立连接(url、username、password)

注册驱动以后就需要和数据库建立连接。可以使用 DriverManager.getConnection()方法建立连接。根据传入参数的不同,有三种重载的DriverManager.getConnection()方法,最常用的方式是传入是三个参数:

getConnection(String url, String user, String password)

第一个参数url是指向数据库的地址,不同的数据库有不同的格式如上图所示。以MySQL为例,
url的格式为:jdbc:子协议:子名称//主机名:端口/数据库名称
子协议为mysql;不存在子名称;主机名和端口号一般默认为localHost:3306;还需要datebaseName数据库名,假设为jdbc;那么,url为:String url="jdbc:mysql://localhost:3306/jdbc"
第二、三个参数分别是数据库的用户名和密码。得到数据库的地址,用户名和密码才能与其建立连接。

建立连接的代码为:

扫描二维码关注公众号,回复: 5138615 查看本文章
String url="jdbc:mysql://localhost:3306/jdbc";
String name="root";
String password="mysql";
Connection conn=DriverManager.getConnection(url,name,password);
  

(3)创建SQL语句,获取语句执行对象

创建SQL语句就是以字符串的形式编写操作数据库的语言。在2.2案例中对应的代码为:sql="select * from user";

(3).1 Statement和PreparedStatement都可以创建执行对象

SQL语句的执行对象说有Statement和PreparedStatement两个,但我们一般都使用PreparedStatement。两者的描述如下:

Statement 是 Java 执行数据库操作的一个重要接口,用于在已经建立数据库连接的基础上,向数据库发送要执行的SQL语句。Statement对象,用于执行不带参数的简单SQL语句,即静态SQL语句。
如何获取执行对象?通过使用Connection对象的createStatement()方法创建指定对象:Statement st=conn.createStatement();

PreparedStatement 继承于Statement。实例包含已编译的 SQL 语句,这就是使语句预编译。包含于 PreparedStatement 对象中的 SQL 语句可具有一个或多个 IN 参数。IN参数的值在 SQL 语句创建时未被指定。相反的,该语句为每个 IN 参数保留一个问号(“?”)作为占位符。每个问号的值必须在该语句执行之前,通过适当的setXXX() 方法来提供。
如何获取执行对象?通过使用Connection对象的PreparedStatement()方法创建指定对象:
PreparedStatement ps=conn.prepareStatement(sql);

(3).2 Statement和PreparedStatement的区别

两者在使用上具有一定的区别,主要集中在第(3)步:创建SQL语句,获取语句执行对象和第(4)步:执行语句
使用Statement的代码为(只展示第(3)步和第(4)步):

  //3.创建SQL语句,,并建立SQL语句执行对象
   sql="select * from user";//创建SQL语句
   Statement st=conn.createStatement();//SQL语句执行对象
  //4.执行语句
   ResultSet rs=st.executeQuery(sql);
  /

使用PreparedStatement的代码为(只展示第(3)步和第(4)步):

//3.创建语句
  //PreparedStatement可以对sql语句进行预处理,过滤一些MySQL中的字符
String sql="select * from user where name=?";/使用PreparedStatement,sql语句中可以存在占位符"?"
PreparedStatement ps=conn.prepareStatement(sql);//区别于使用Statement,需要将sql语句传入进行预编译
ps.setString(1, "zhangsan");//这句代码是对上面sql语句中的第1个问号进行设置,下面(3).2讲解
//4.执行语句
rs=ps.executeQuery();//区别于使用Statement,不需要将sql语句作为参数传入

注意:使用Statement的话,需要在第(4)步将sql语句交给Statement的executeQuery()或executeUpdate()方法来执行;而使用PreparedStatement的话,由于其具有预编译的功能,在第(3)步创建PreparedStatement 对象的时候就需要将sql语句传入进行预编译,到第(4)步调用executeQuery()或executeUpdate()方法来执行sql语句的时候就不需要将sql语句传入,如果传入会报错。

(3).2 PreparedStatement相比于Statement的优势
优势一:

Statement执行不带参数的简单SQL语句,即静态SQL语句。PreparedStatement可执行动态执行SQL语句,使用占位符?去代替未知数据,因而一个句子可以执行多种不同的SQL,而Statement需要重新书写SQL语句,笨重。

案例:
使用Statement查询user表里面名字为"zhangsan"的人所有信息:

 //3.创建SQL语句,,并建立SQL语句执行对象
   sql="select * from user where name = zhangsan";//创建SQL语句
   Statement st=conn.createStatement();//SQL语句执行对象
  //4.执行语句
   ResultSet rs=st.executeQuery(sql);
  /

使用PreparedStatement查询user表里面名字为"zhangsan"的人所有信息:

//3.创建语句
String sql="select * from user where name=?";/使用PreparedStatement,sql语句中可以存在占位符"?"
PreparedStatement ps=conn.prepareStatement(sql);//区别于使用Statement,需要将sql语句传入进行预编译
ps.setString(1, "zhangsan");//这句代码是对上面sql语句中的第1个问号进行设置,下面讲解
//4.执行语句
rs=ps.executeQuery();//区别于使用Statement,不需要将sql语句作为参数传入

注意:
使用PreparedStatement,可以使用占位符"?"表示 SQL 语句创建时未被指定的部分,每个问号的值必须在该语句执行之前,通过适当的setXXX() 方法来指定。XXX表示相应的参数类型,如上例中的 "zhangsan"为String类型,故使用setString()方法。该方法包含两个参数,第一个参数表示第几个问号,第二个表示问号表示的内容。
案例:

ps.setString(1, "zhangsan");//设置第1个问号为String类型的 "zhangsan"
ps.setInt(2,5);//设置第2个问号为Int类型的5
优势二:

PreparedStatement没有SQL注入的问题,可以对sql语句进行预处理,过滤一些MySQL中的字符
静态SQL语句说到底还是字符串,所以存在拼字符串的而带来的注入式SQL攻击风险。比如某个网站的登录验证SQL查询代码为:

String sql = "SELECT * FROM users WHERE name = '" + userName + "' and pw = '"+ passWord +"';"

验证需要用户输入用户名和密码,正确则执行查询语句(登录),但如果这样输入:

userName = "1' OR '1'='1";
passWord = "1' OR '1'='1";

那么执行语句就变成了:

String sql = "SELECT * FROM users WHERE name = '1' OR '1'='1' and pw = '1' OR '1'='1';"

这样,where语句恒为真,就能实现无账号登录。此外便可能被恶意修改甚至删除数据表。然而使用PreparedStatement的参数化的查询可以阻止大部分的SQL注入。在使用参数化查询的情况下,数据库系统(eg:MySQL)不会将参数的内容视为SQL指令的一部分来处理,而是在数据库完成SQL指令的编译后,才套用参数运行,且占位符?不允许多值,只能填入一个值,因此就算参数中含有破坏性的指令,也不会被数据库所运行。

优势三:

当需要执行多次相似的SQL命令时,能够比较高效地执行。(只执行一次的话,PreparedStatement会包含与处理的时间)

(4)执行语句

sql语句有增删查改等几种类型,所以执行方法有以下两种:
executeQuery():执行SQL查询语句,查询结果返回为ResultSet 对象。
executeUpdate() :执行更新语句,包括增删改。该语句必须是一个 SQL 数据操作语言(Data Manipulation Language,DML)语句,比如 INSERT、UPDATE 或 DELETE 语句;或者是无返回内容的 SQL 语句,比如 DDL 语句。返回值是int类型的被修改记录条数。

(5)处理结果

当是增删改数据时,返回的是int类型的被修改记录条数。很好处理。
当是查找数据时,返回的是ResultSet对象。一般使用while循环来处理:ResultSet 对象具有指向其当前数据行的光标。最初,光标被置于第一行之前。next() 方法将光标移动到下一行;因为该方法在 ResultSet 对象没有下一行时返回 false,所以可以在 while 循环中使用它来迭代结果集。另外,可以使用ResultSet对象的getXXX(int columnIndex)获得游标所在行指定列的值。其中XXX是String、Int、Double类的变量类型,取决于所要读取的字段的数据类型。
案例

   while(rs.next()) {//按行遍历
    System.out.println(rs.getObject(1)+"\t"+rs.getObject(2)+"\t"
      +rs.getObject(3)+"\t"+rs.getObject(4)+"\t");//获取每1-4列
  }

在JDBC程序结束之后,显式地需要关闭与数据库的所有连接以结束每个数据库会话,以避免浪费资源。要使用与连接对象关联的close()方法关闭连接。要确保连接已关闭,可以将关闭连接的代码中编写在“finally”块中。 一个finally块总是会被执行,不管是否发生异常。

(6)释放资源(后创建的先关闭)

2.2代码中第(6)步的关闭方法不够严谨,可以采取如下的关闭方法:

try {
    if (rs != null)
        rs.close();
} catch (SQLException e) {
    e.printStackTrace();
} finally {
    try {
         if (ps != null)
         ps.close();
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        try {
             if (conn != null)
                 conn.close();
     } catch (SQLException e) {
         e.printStackTrace();
     }
    }
 }

2.4完整代码

由于篇幅限制,放在下一篇博客:https://mp.csdn.net/postedit/85792701
后续内容也将在这篇博客内写作。

参考:
https://www.cnblogs.com/fzz9/p/8970210.html
黑马程序员_JDBC视频教程

猜你喜欢

转载自blog.csdn.net/qq_42262803/article/details/85762993
今日推荐