JDBC 面试题

时间:2022-06-11 22:16:47

什么是JDBC,什么时候用的到它

JDBC的全程是 Java DataBase Connection,也就是Java数据库连接,我们可以用它来操作关系型数据库。JDBC接口及相关类在java.sql包和javax.sql包里。我们可以用它来连接数据库,执行SQL查询,存储过程,并处理返回的结果。

JDBC接口让Java程序和JDBC驱动实现了减耦合,使得切换不同的数据库变得简单。

有哪些不同的类型的JDBC驱动?

有四类JDBC驱动,和数据库进行交互的java程序分成两个部分,一部分是JDBC的API,实际工作的驱动则是另一部分。

A JDC-ODBC Bridge plus ODBC Driver:它使用ODBC驱动连接数据库。需要安装ODBC以便连接数据库,正因为这样,这种方式现在已经基本淘汰了。
B Native API partly Java technology-enabled driver:这种驱动把JDBC调用适配成数据库的本地接口的调用。
C Pure Java Driver for Database Middleware:这个驱动把JDBC调用转发给中间件服务器,由它去和不同的数据库进行连接。用这种类型的驱动需要部署中间件服务器。这种方式增加了额外的网络调用,导致性能变差,因此很少使用。
D Direct-to-Database Pure Java Driver:这个驱动把JDBC转化成数据库使用的网络协议。这种方案最简单,也适合通过网络连接数据库。不过使用这种方式的话,需要根据不同数据库选用特定的驱动程序,比如OJDBC是Oracle开发的Oracle数据库的驱动,而MySQL Connector/J是MySQL数据库的驱动。

JDBC是如何实现Java程序和JDBC驱动的松耦合

JDBC API使用Java的反射机制来实现Java程序和JDBC驱动的松耦合。随便看一个简单的JDBC示例,你会发现所有操作都是通过JDBC接口完成的,而驱动只有在通过Class.forName反射机制来加载的时候才会出现。
这是Java核心库里反射机制的最佳实践之一,它使得应用程序和驱动程序之间进行了隔离,让迁移数据库的工作变得更简单。

什么是JDBC连接,在Java中如何创建一个JDBC连接?

建立jdbc连接过程如下:

1、注册数据库驱动

2、建立数据库连接

3、创建一个Statement

4、执行SQL语句

5、处理结果集

6、关闭数据库连接



package com.xyfer;
 
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
 
public class JdbcTest {
 
    public static void main(String[] args) {
        
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        
        try {
            //加载数据库驱动
            Class.forName("com.mysql.jdbc.Driver");
            
            //通过驱动管理类获取数据库链接
            connection =  DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "root");
            //定义sql语句 ?表示占位符
            String sql = "select * from user where username = ?";
            //获取预处理statement
            preparedStatement = connection.prepareStatement(sql);
            //设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值
            preparedStatement.setString(1, "小黑");
            //向数据库发出sql执行查询,查询出结果集
            resultSet =  preparedStatement.executeQuery();
            //遍历查询结果集
            while(resultSet.next()){
                System.out.println(resultSet.getString("id") "  " resultSet.getString("username"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            //释放资源
            if(resultSet!=null){
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            if(preparedStatement!=null){
                try {
                    preparedStatement.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            if(connection!=null){
                try {
                    connection.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
 
}

JDBC中的 Statement、PreparedStatement 和 CallableStatement的区别?

区别:

  • PreparedStatement是预编译的SQL语句,效率高于Statement。

  • PreparedStatement支持?操作符,相对于Statement更加灵活。

  • PreparedStatement可以防止SQL注入,安全性高于Statement。

  • CallableStatement适用于执行存储过程。

JDBC中大数据量的分页解决方法?

最好的方法就是利用sql语句进行分页,这样每次查询出的结果集中就只包含某页的数据内容

mysql语法:


    SELECT * FROM 表名 LIMIT [START], length;
    

oracle语法:

    SELECT *FROM (
        SELECT 列名,列名,ROWNUM rn
        FROM 表名
        WHERE ROWNUM<=(currentPage*lineSize)) temp
    
    WHERE temp.rn>(currentPage-1)*lineSize;

数据库连接池工作原理和实现方案?

工作原理:

  • JAVA EE服务器启动时会建立一定数量的池连接,并一直维持不少于此数目的池连接。客户端程序需要连接时,池驱动程序会返回一个未使用的池连接并将其表记为忙。如果当前没有空闲连接,池驱动程序就新建一定数量的连接,新建连接的数量有配置参数决定。当使用的池连接调用完成后,池驱动程序将此连接表记为空闲,其他调用就可以使用这个连接。

实现方案:

  • 连接池使用集合来进行装载,返回的Connection是原始Connection的代理,代理Connection的close方法,当调用close方法时,不是真正关连接,而是把它代理的Connection对象放回到连接池中,等待下一次重复利用。

Java中如何进行事务的处理?

1.事务是作为单个逻辑工作单元执行的一系列操作。
2.一个逻辑工作单元必须有四个属性,称为原子性、一致性、隔离性和持久性 (ACID) 属性,只有这样才能成为一个事务

Connection类中提供了4个事务处理方法:

  • setAutoCommit(Boolean autoCommit):设置是否自动提交事务,默认为自动提交,即为true,通过设置false禁止自动提交事务

  • commit():提交事务

  • rollback():回滚事务

  • savepoint:保存点

    • 注意:savepoint不会结束当前事务,普通提交和回滚都会结束当前事务的

JDBC是如何实现Java程序和JDBC驱动的松耦合的?

通过制定接口,数据库厂商来实现。我们只要通过接口调用即可。随便看一个简单的JDBC示例,你会发现所有操作都是通过JDBC接口完成的,而驱动只有在通过Class.forName反射机制来加载的时候才会出现。

execute,executeQuery,executeUpdate的区别是什么?

  • Statement的execute(String query)方法用来执行任意的SQL查询,如果查询的结果是一个ResultSet,这个方法就返回true。如果结果不是ResultSet,比如insert或者update查询,它就会返回false。我们可以通过它的getResultSet方法来获取ResultSet,或者通过getUpdateCount()方法来获取更新的记录条数。

  • Statement的executeQuery(String query)接口用来执行select查询,并且返回ResultSet。即使查询不到记录返回的ResultSet也不会为null。我们通常使用executeQuery来执行查询语句,这样的话如果传进来的是insert或者update语句的话,它会抛出错误信息为 “executeQuery method can not be used for update”的java.util.SQLException。

  • Statement的executeUpdate(String query)方法用来执行insert或者update/delete(DML)语句,或者 什么也不返回DDL语句。返回值是int类型,如果是DML语句的话,它就是更新的条数,如果是DDL的话,就返回0。

  • 只有当你不确定是什么语句的时候才应该使用execute()方法,否则应该使用executeQuery或者executeUpdate方法。

?

JDBC的脏读是什么?哪种数据库隔离级别能防止脏读?

脏读:一个事务读取到另外一个事务未提交的数据

例子:A向B转账,A执行了转账语句,但A还没有提交事务,B读取数据,发现自己账户钱变多了!B跟A说,我已经收到钱了。A回滚事务【rollback】,等B再查看账户的钱时,发现钱并没有多。

下面的三种个隔离级别都可以防止:

  • Serializable【TRANSACTION_SERIALIZABLE】

  • Repeatable read【TRANSACTION_REPEATABLE_READ】

  • Read committed【TRANSACTION_READ_COMMITTED】

?

什么是幻读,哪种隔离级别可以防止幻读?

是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。

只有TRANSACTION_SERIALIZABLE隔离级别才能防止产生幻读。

JDBC的DriverManager是用来做什么的?

  • JDBC的DriverManager是一个工厂类,我们通过它来创建数据库连接。

  • 当JDBC的Driver类被加载进来时,它会自己注册到DriverManager类里面

  • 然后我们会把数据库配置信息传成DriverManager.getConnection()方法,DriverManager会使用注册到它里面的驱动来获取数据库连接,并返回给调用的程序。

JDBC的ResultSet是什么?

  • 在查询数据库后会返回一个ResultSet,它就像是查询结果集的一张数据表。

  • ResultSet对象维护了一个游标,指向当前的数据行。开始的时候这个游标指向的是第一行。如果调用了ResultSet的next()方法游标会下移一行,如果没有更多的数据了,next()方法会返回false。可以在for循环中用它来遍历数据集。

  • 默认的ResultSet是不能更新的,游标也只能往下移。也就是说你只能从第一行到最后一行遍历一遍。不过也可以创建可以回滚或者可更新的ResultSet

  • 当生成ResultSet的Statement对象要关闭或者重新执行或是获取下一个ResultSet的时候,ResultSet对象也会自动关闭。

  • 可以通过ResultSet的getter方法,传入列名或者从1开始的序号来获取列数据。