JDBC、JDBC的常用API、 实现第一个JDBC程序、PreparedStatement对象、ResultSet对象、 动手实践:使用JDBC完成数据的增删改查

JDBC

​ 在Web开发中,不可避免的要使用数据库存储和管理数据。为了在Java语言中提供对数据库访问的支持,SUN公司于1996年提供了一套访问数据库的标准Java类库,即JDBC。

01. 什么是JDBC

​ JDBC的全称是Java Database Connectivity即Java数据库连接。它是一套用于执行SQL语句的Java API。应用程序可通过这套API连接到关系型数据库,并使用SQL语句完成对数据库中数据的查询、更新、新增和删除操作。

​ 不同种类的数据库(如MySQL、Oracle等)在内部处理数据的方式是不同的,如果直接使用数据库厂商提供的访问接口操作数据库,应用程序的可移植性就会变得很差。例如,用户当前在程序中使用的是MySQL提供的接口操作数据库,如果换成Oracle数据库,则需要重新使用Oracle数据库提供的接口,这样代码的改动量会非常大。有了JDBC后,这问题就不复存在了,因为它要求各个数据库厂商按照统一的规范提供数据库驱动,而在程序中由JDBC和具体的数据库驱动联系,所以用户就不必直接与底层的数据库交互,这使得代码的通用性更强。

在这里插入图片描述

​ JDBC在应用程序与数据库之间起到了一个桥梁作用,当应用程序使用JDBC访问特定的数据库时,需要通过不同数据库驱动与不同的数据库进行连接,连接后即可对数据库进行相应的操作。

02. JDBC的常用API

01. Driver接口

​ Driver接口是所有JDBC驱动程序必须实现的接口,该接口专门提供给数据库厂商使用。需要注意的是,在编写JDBC程序时,必须要把所使用的数据库驱动程序或类库加载到项目的classpath中(这里指MySQL驱动JAR包)。

02. DriverManager接口

​ DriverManager类用于加载JDBC驱动并且创建与数据库的连接。在DriverManager类中,定义了两个比较重要的静态方法,如下表所示。

方法名称功能描述
registerDriver(Driver driver)该方法用于向DriverManager中注册给定的JDBC驱动程序
getConnection(String url,String user,String pwd)该方法用于建立和数据库的连接,并返回表示连接的Connection对象
03. Connection接口

​ Connection接口表示Java程序和数据库的连接,只有获得该连接对象后才能访问数据库,并操作数据表。在Connection接口中定义了一系列方法,常用方法如下表所示。

方法名称功能描述
getMetaData()用于返回表示数据库元数据的DatabaseMetaData对象
createStatement()用于创建一个Statement对象并将SQL语句发送到数据库
prepareStatement(String sql)用于创建一个PreparedStatement对象并将参数化的SQL语句发送到数据库
prepareCall(String sql)用于创建一个CallableStatement对象来调用数据库存储过程
04. Statement接口

​ Statement接口用于执行静态的SQL语句,并返回一个结果对象。Statement接口的对象通过Connection实例的createStatement( )方法获得。利用Statement接口把静态的SQL语句发送到数据库编译执行,然后返回数据库的处理结果。Statement接口提供了执行SQL语句的3个常用方法。如下表所示。

方法名称功能描述
execute(String sql)用于执行各种SQL语句,该方法返回一个boolean类型的值,如果为true,表示所执行的SQL语句有查询结果,可通过Statement的getResultSet()方法获得查询结果
executeUpdate(String sql)用于执行SQL中的insert、update和delete语句。该方法返回一个int类型的值,表示数据库中受该SQL语句影响的记录条数
executeQuery(String sql)用于执行SQL中的select语句,该方法返回一个表示查询结果的ResultSet对象
05. PreparedStatement接口

​ Statement接口封装了JDBC执行SQL语句的方法,可以完成Java程序执行SQL语句的操作。然而在实际开发过程中往往需要将程序中的变量作为SQL语句的查询条件,而使用Statement接口操作这些SQL语句会过于繁琐,并且存在安全方面的问题。针对这一问题,JDBC API 提供了扩展的PreparedStatement接口。

​ PreparedStatement是Statement的子接口,用于执行预编译的SQL语句。PreparedStatement接口扩展了带有参数的SQL语句的执行操作,应用该接口中的SQL语句可以使用占位符“?”代替参数,然后通过setter()方法为SQL语句的参数赋值。

PreparedStatement接口的常用方法

方法名称功能描述
executeUpdate()在此PreparedStatement对象中执行SQL语句,该语句必须是一个DML语句或者是无返回内容的SQL语句,比如 DDL 语句
executeQuery()在此PreparedStatement对象中执行SQL查询,该方法返回的是ResultSet对象
setInt(int parameterIndex, int x)将指定参数设置为给定的int值
setFloat(int parameterIndex, float x)将指定参数设置为给定的float值
setString(int parameterIndex, String x)将指定参数设置为给定的String值
setDate(int parameterIndex, Date x)将指定参数设置为给定的Date值
addBatch()将一组参数添加到此PreparedStatement对象的批处理命令中
setCharacterStream(int parameterIndex, java.io.Reader reader,int length)将指定的输入流写入数据库的文本字段
setBinaryStream(int parameterIndex, java.io.InputStream x, int length)将二进制的输入流数据写入到二进制字段中

​ 需要注意的是,setDate()方法可以设置日期内容,但参数Date的类型是java.sql.Date,而不是java.util.Date。在通过setter()方法为SQL语句中的参数赋值时,可以通过参数与SQL类型相匹配的方法(例如,如果参数类型为Integer,那么应该使用setInt()方法),也可以通过setObject()方法设置多种类型的输入参数。通过setter()方法为SQL语句中的参数赋值,具体示例代码如下所示:

String sql = "INSERT INTO users(id,name,email) VALUES(?,?,?)";
PreparedStatement  preStmt = conn.prepareStatement(sql);
preStmt.setInt(1, 1);                         //使用参数与SQL类型相匹配的方法
preStmt.setString(2, "zhangsan");    //使用参数与SQL类型相匹配的方法
preStmt.setObject(3, "zs@sina.com");//使用setObject()方法设置参数
preStmt.executeUpdate();
06. ResultSet接口

​ ResultSet接口用于保存JDBC执行查询时返回的结果集,该结果集封装在一个逻辑表格中。在ResultSet接口内部有一个指向表格数据行的游标(指针),ResultSet对象初始化时,游标在表格的第一行之前,调用next()方法可将游标移动到下一行。如果下一行没有数据,则返回false。在应用程序中经常调用next()方法作为while循环的条件来迭代ResultSet结果集。

ResultSet接口的常用方法

方法名称功能描述
getString(int columnIndex)用于获取指定字段的String类型的值,参数columnIndex代表字段的索引
getString(String columnName)用于获取指定字段的String类型的值,参数columnName代表字段的名称
getInt(int columnIndex)用于获取指定字段的int类型的值,参数columnIndex代表字段的索引
getInt(String columnName)用于获取指定字段的int类型的值,参数columnName代表字段的名称
getDate(int columnIndex)用于获取指定字段的Date类型的值,参数columnIndex代表字段的索引
getDate(String columnName)用于获取指定字段的Date类型的值,参数columnName代表字段的名称
方法名称功能描述
next()将游标从当前位置向下移一行
absolute(int row)将游标移动到此 ResultSet 对象的指定行
afterLast()将游标移动到此 ResultSet 对象的末尾,即最后一行之后
beforeFirst()将游标移动到此 ResultSet 对象的开头,即第一行之前
previous()将游标移动到此 ResultSet 对象的上一行
last()将游标移动到此 ResultSet 对象的最后一行

​ ResultSet接口中定义了大量的getter()方法,而采用哪种getter()方法获取数据,取决于字段的数据类型。程序既可以通过字段的名称获取指定数据,也可以通过字段的索引获取指定的数据,字段的索引是从1开始编号的。例如,数据表的第一列字段名为id,字段类型为int,那么既可以调用getInt(1),以字段索引的方式获取该列的值,也可以调用getInt(“id”),以字段名称的方式获取该列的值。

03. 实现第一个JDBC程序

实现第一个JDBC程序

  1. 加载并注册数据库驱动
DriverManager.registerDriver(Driver driver);
或
Class.forName("DriverName");

  1. 通过DriverManager获取数据库连接
获取数据库连接的具体方式如下:
Connection conn = DriverManager.getConnection(String url, String user, String pwd); 
	getConnection()方法有3个参数,它们分别表示连接数据库的URL地址、登录数据库的用户名和
密码。以MySQL数据库为例,MySQL 5.5及之前版本,其URL地址的书写格式如下:
jdbc:mysql://hostname:port/databasename
	MySQL 5.6及之后版本的MySQL数据库的时区设定比中国时间早8个小时,需要在URL地址后面指定
时区,具体如下所示:
jdbc:mysql://hostname:port/databasename?serverTimezone=GMT%2B8
	上面代码中,jdbc:mysql:是固定的写法,mysql指的是MySQL数据库,hostname指的是主机的名
称(如果数据库在本机中,hostname可以为localhost或127.0.0.1;如果要连接的数据库在其他电脑
上,hostname为所要连接电脑的IP),port指的是连接数据库的端口号(MySQL端口号默认为3306),
而databasename指的是MySQL中相应数据库的名称。

  1. 通过Connection对象获取Statement对象
通过Connection对象获取Statement对象的方式有如下三种:
	调用createStatement()方法:创建基本的Statement对象。
	调用prepareStatement()方法:创建PreparedStatement对象。
	调用prepareCall()方法:创建CallableStatement对象。

以创建基本的Statement对象为例,创建方式如下:
Statement stmt = conn.createStatement();

  1. 使用Statement对象执行SQL语句
所有的Statement对象都有如下三种执行SQL语句的方法:
	execute():可以执行任何SQL语句。
	executeQuery():通常执行查询语句,执行后返回代表结果集的ResultSet对象。
	executeUpdate():主要用于执行DML和DDL语句。执行DML语句,如 INSERT、UPDATE或     
                               DELETE时,返回受SQL语句影响的行数,执行DDL语句返回0。
以executeQuery()方法为例,其使用方式如下:
// 执行SQL语句,获取结果集ResultSet
ResultSet rs = stmt.executeQuery(sql);

  1. 操作ResultSet结果集
	如果执行的SQL语句是查询语句,执行结果将返回一个ResultSet对象,该对象保存了SQL语句查询
的结果。程序可以通过操作该ResultSet对象获取查询结果。
	每次操作数据库结束后都要关闭数据库连接,释放资源,包括ResultSet、Statement和
Connection等资源。

虽然使用DriverManager.registerDriver(new com.mysql.jdbc.Driver())方法也可以完成注册,但此方式
会使数据库驱动被注册两次。这是因为Driver类的源码,已经在静态代码块中完成了数据库驱动的注册。所以,
为了避免数据库驱动被重复注册,需要在程序中使用Class.forName()方法加载驱动类。需要注意的是,MySQL 
5.5及之前的版本使用的是旧版驱动,使用Class.forName("com.mysql.jdbc.Driver")方式加载驱动类;
MySQL 5.6以及之后的版本需要更新到新版驱动,使用Class.forName("com.mysql.cj.jdbc.Driver")方式加
载驱动类。

由于数据库资源非常宝贵,数据库允许的并发访问连接数量有限,所以,当数据库资源使用完毕后,一定要记得释
放资源。为了保证资源的释放,在Java程序中,应该将最终必须要执行的操作放在finally代码块中。

package com.miao.jdbc;

import java.sql.*;

/**
 * \* Created with IntelliJ IDEA.
 * \* User: maomao
 * \* Date: 2022/3/30
 * \* Time: 21:19
 * \* Description:
 * \
 */
public class JDBCConnection {

    public static void main(String[] args) {
        try {
            // 1.加载并注册数据库驱动
            //DriverManager.registerDriver(Driver driver);
            Class.forName("com.mysql.cj.jdbc.Driver");

            // 2.获取数据库链接
            String url = "jdbc:mysql://localhost:3306/jdbc?serverTimezone=GMT%2B8";
            String user = "root";
            String pass = "123456";
            Connection conn = DriverManager.getConnection(url,user,pass);

            // 3. 获得Statement对象
            Statement statement = conn.createStatement();

            // 准备sql语句
            String sql = "select * from users";

            // 4. 执行sql语句
            ResultSet resultSet = statement.executeQuery(sql);

            System.out.println("id | name   | password | email  | birthday");
            // 5. 遍历输出结果集
            while (resultSet.next()) {

                int id = resultSet.getInt("id");
                String name = resultSet.getString("name");
                String password = resultSet.getString("password");
                String email = resultSet.getString("email");
                Date birthday = resultSet.getDate("birthday");
                System.out.println(id + " | " + name + " | " + password + " | " + email
                        + " | " + birthday);
            }
        }catch (SQLException throwables) {
            throwables.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
        }
    }
}

0

04. PreparedStatement对象

​ SQL语句的执行是通过Statement对象实现的。Statement对象每次执行SQL语句时,都会对其进行编译。当相同的SQL语句执行多次时,Statement对象就会使数据库频繁编译相同的SQL语句,从而降低数据库的访问效率。

​ 为了解决上述问题,Statement提供了一个子类PreparedStatement。PreparedStatement对象可以对SQL语句进行预编译,预编译的信息会存储在PreparedStatement对象中。当相同的SQL语句再次执行时,程序会使用PreparedStatement对象中的数据,而不需要对SQL语句再次编译去查询数据库,这样就大大提高了数据的访问效率。

package com.miao.jdbc;

import java.sql.*;
import java.time.LocalDate;

/**
 * \* Created with IntelliJ IDEA.
 * \* User: maomao
 * \* Date: 2022/3/30
 * \* Time: 21:19
 * \* Description:
 * \
 */
public class JDBCConnection02 {

    public static void main(String[] args) {
        try {
            // 1.加载并注册数据库驱动
            //DriverManager.registerDriver(Driver driver);
            Class.forName("com.mysql.cj.jdbc.Driver");

            // 2.获取数据库链接
            String url = "jdbc:mysql://localhost:3306/jdbc?serverTimezone=GMT%2B8";
            String user = "root";
            String pass = "123456";
            Connection conn = DriverManager.getConnection(url,user,pass);

            // 准备sql语句
            String sql = "INSERT INTO users(name,password,email,birthday)"
                    + "VALUES(?,?,?,?)";

            // 3. 获得Statement对象
            PreparedStatement preparedStatement = conn.prepareStatement(sql);

//            preparedStatement.setInt(1, 3);
            preparedStatement.setString(1, "wangwu");
            preparedStatement.setString(2, "123456");
            preparedStatement.setString(3, "wangwu@qq.com");

            LocalDate pubDate = LocalDate.now();
            preparedStatement.setDate(4,Date.valueOf(pubDate));

            // 4. 执行sql语句
            int i = preparedStatement.executeUpdate();

            System.out.println(i);
        }catch (SQLException throwables) {
            throwables.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
        }
    }
}

在这里插入图片描述

在这里插入图片描述

05. ResultSet对象

​ ResultSet主要用于存储结果集,可以通过next()方法由前向后逐个获取结果集中的数据,如果想获取结果集中任意位置的数据,则需要在创建Statement对象时,设置两个ResultSet定义的常量,具体设置方式如下:

 Statement st = conn.createStatement(ResultSet.TYPE_SCROLL_INSENITIVE, 
                                     ResultSet.CONCUR_READ_ONLY);
 ResultSet rs = st.excuteQuery(sql);

在上述方式中,常量“Result.TYPE_SCROLL_INSENITIVE”表示结果集可滚动,常量“ResultSet.CONCUR_READ_ONLY”表示
以只读形式打开结果集。

package com.miao.jdbc;

import java.sql.*;
import java.time.LocalDate;

/**
 * \* Created with IntelliJ IDEA.
 * \* User: maomao
 * \* Date: 2022/3/30
 * \* Time: 21:19
 * \* Description:
 * \
 */
public class JDBCConnection03 {

    public static void main(String[] args) {
        try {
            // 1.加载并注册数据库驱动
            //DriverManager.registerDriver(Driver driver);
            Class.forName("com.mysql.cj.jdbc.Driver");

            // 2.获取数据库链接
            String url = "jdbc:mysql://localhost:3306/jdbc?serverTimezone=GMT%2B8";
            String user = "root";
            String pass = "123456";
            Connection conn = DriverManager.getConnection(url,user,pass);

            // 准备sql语句
            String sql = "select * from users";

            // 3. 获得Statement对象
            Statement statement = conn.createStatement(
                    ResultSet.TYPE_SCROLL_INSENSITIVE,
                    ResultSet.CONCUR_READ_ONLY);
            ResultSet rs = statement.executeQuery(sql);
//            preparedStatement.setInt(1, 3);


            //4.取出ResultSet中指定数据的信息
            System.out.print("第2条数据的name值为:");
            rs.absolute(2);        //将指针定位到结果集中第2行数据
            System.out.println(rs.getString("name"));
            System.out.print("第1条数据的name值为:");
            rs.beforeFirst();      //将指针定位到结果集中第1行数据之前
            rs.next();              //将指针向后滚动
            System.out.println(rs.getString("name"));
            System.out.print("第3条数据的name值为:");
            rs.afterLast();        //将指针定位到结果集中最后一条数据之后
            rs.previous();         //将指针向前滚动
            System.out.println(rs.getString("name"));

        }catch (SQLException throwables) {
            throwables.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
        }
    }
}

在这里插入图片描述

06. 动手实践:使用JDBC完成数据的增删改查

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

铲屎官白茶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值