• JAVA面试—JDBC


    1、写出JDBC连接数据库的步骤?

    1. 注册驱动
    2. 获取连接
    3. 获取可以执行SQL语句的对象(Statement / Preparedstatement)
    4. 执行SQL语句
    5. 处理结果集
    6. 关闭连接   
    Connection connection = null;
    Statement statement = null;
    ResultSet resultSet = null;
    
    try {
    
        /*
        * 加载驱动有两种方式
        *
        * 1:会导致驱动会注册两次,过度依赖于mysql的api,脱离的mysql的开发包,程序则无法编译
        * 2:驱动只会加载一次,不需要依赖具体的驱动,灵活性高
        *
        * 我们一般都是使用第二种方式
        * */
    
        //1.
        //DriverManager.registerDriver(new com.mysql.jdbc.Driver());
    
        //2.
        Class.forName("com.mysql.jdbc.Driver");
    
        //获取与数据库连接的对象-Connetcion
        connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/zhongfucheng", "root", "root");
    
        //获取执行sql语句的statement对象
        statement = connection.createStatement();
    
        //执行sql语句,拿到结果集
        resultSet = statement.executeQuery("SELECT * FROM users");
    
        //遍历结果集,得到数据
        while (resultSet.next()) {
    
            System.out.println(resultSet.getString(1));
    
            System.out.println(resultSet.getString(2));
        }
    
    } catch (SQLException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } finally {
    
        /*
        * 关闭资源,后调用的先关闭
        *
        * 关闭之前,要判断对象是否存在
        * */
    
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
    
        }
        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
    
        }
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
    
        }
    
    }
    代码展示

     

    2、JDBC的Statement和PreparedStatement的区别?

    1. PreparedStatement继承于Statement
    2. Statement对象编译SQL语句时,如果SQL语句有变量,就需要使用分隔符来隔开,如果变量非常多,就会使SQL变得非常复杂。而PreparedStatement可以使用占位符,简化sql的编写
    3. Statement会频繁编译SQL。PreparedStatement可对SQL进行预编译,提高效率,预编译的SQL存储在PreparedStatement对象中
    4. PreparedStatement防止SQL注入。【Statement通过分隔符‘++’,编写永等式,可以不需要密码就能进入数据库】

     

    3、数据库连接池的工作机制是什么?有什么优点?

    1. J2EE服务器启动时会建立一定数量的池连接,并一直维持不少于此数目的池连接
    2. 客户端程序需要连接时,池驱动程序会返回一个未使用的池连接并将其标记为忙
    3. 如果当时池中没有空闲连接,池驱动就会新建一定数量的连接,新建连接的数量由配置参数决定。
    4. 当使用的池连接调用完成后,会把连接归还给连接池,并且池驱动会将此连接标记为空闲,其他调用就可以使用这个连接
    5. 当连接数量达到连接池最大值时,池驱动将不会创建新连接,只能等连接池中连接空闲后才能使用。
    6. 优点:连接少的时候可以复用。

     

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

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

      mysql语法:

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

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

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

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

    • setAutoCommit(Boolean autoCommit):设置是否自动提交事务,默认为自动提交,即为true,通过设置false禁止自动提交事务;
    • commit():提交事务;
    • rollback():回滚事务.
    • savepoint:保存点

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

     

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

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

     

    7、PreparedStatement的缺点是什么,怎么解决这个问题?

      PreparedStatement的一个缺点是,我们不能直接用它来执行in条件语句;需要执行IN条件语句的话,下面有一些解决方案:

    • 分别进行单条查询——这样做性能很差,不推荐。
    • 使用存储过程——这取决于数据库的实现,不是所有数据库都支持。
    • 动态生成PreparedStatement——这是个好办法,但是不能享受PreparedStatement的缓存带来的好处了。
    • 在PreparedStatement查询中使用NULL值——如果你知道输入变量的最大个数的话,这是个不错的办法,扩展一下还可以支持无限参数。

     

    8、JDBC的DriverManager是用来做什么的?

    • JDBC的DriverManager是一个工厂类,我们通过它来创建数据库连接。
    • 当JDBC的Driver类被加载进来时,它会自己注册到DriverManager类里面
    • 然后我们会把数据库配置信息传成DriverManager.getConnection()方法,DriverManager会使用注册到它里面的驱动来获取数据库连接,并返回给调用的程序。

     

    9、JDBC的ResultSet是什么?

    • 在查询数据库后会返回一个ResultSet,它就像是查询结果集的一张数据表。
    • ResultSet对象维护了一个游标,指向当前的数据行。开始的时候这个游标指向的是第一行。如果调用了ResultSet的next()方法游标会下移一行,如果没有更多的数据了,next()方法会返回false。可以在for循环中用它来遍历数据集。
    • 默认的ResultSet是不能更新的,游标也只能往下移。也就是说你只能从第一行到最后一行遍历一遍。不过也可以创建可以回滚或者可更新的ResultSet
    • 当生成ResultSet的Statement对象要关闭或者重新执行或是获取下一个ResultSet的时候,ResultSet对象也会自动关闭。
    • 可以通过ResultSet的getter方法,传入列名或者从1开始的序号来获取列数据。

     

    10、有哪些不同的ResultSet?

      根据创建Statement时输入参数的不同,会对应不同类型的ResultSet。如果你看下Connection的方法,你会发现createStatement和prepareStatement方法重载了,以支持不同的ResultSet和并发类型。

      一共有三种ResultSet对象。

    • ResultSet.TYPE_FORWARD_ONLY:这是默认的类型,它的游标只能往下移。
    • ResultSet.TYPE_SCROLL_INSENSITIVE:游标可以上下移动,一旦它创建后,数据库里的数据再发生修改,对它来说是透明的。
    • ResultSet.TYPE_SCROLL_SENSITIVE:游标可以上下移动,如果生成后数据库还发生了修改操作,它是能够感知到的。

      ResultSet有两种并发类型。

    • ResultSet.CONCUR_READ_ONLY:ResultSet是只读的,这是默认类型。
    • ResultSet.CONCUR_UPDATABLE:我们可以使用ResultSet的更新方法来更新里面的数据。

     

    11、JDBC的DataSource是什么,有什么好处? 

      DataSource即数据源,它是定义在javax.sql中的一个接口,跟DriverManager相比,它的功能要更强大。我们可以用它来创建数据库连接,当然驱动的实现类会实际去完成这个工作。除了能创建连接外,它还提供了如下的特性:

    • 缓存PreparedStatement以便更快的执行
    • 可以设置连接超时时间
    • 提供日志记录的功能
    • ResultSet大小的最大阈值设置
    • 通过JNDI的支持,可以为servlet容器提供连接池的功能

     

    12、常见的JDBC异常有哪些?

      有以下这些:

    • java.sql.SQLException——这是JDBC异常的基类。
    • java.sql.BatchUpdateException——当批处理操作执行失败的时候可能会抛出这个异常。这取决于具体的JDBC驱动的实现,它也可能直接抛出基类异常java.sql.SQLException。
    • java.sql.SQLWarning——SQL操作出现的警告信息。
    • java.sql.DataTruncation——字段值由于某些非正常原因被截断了(不是因为超过对应字段类型的长度限制)。

     

    13、JDBC中存在哪些不同类型的锁?

      从广义上讲,有两种锁机制来防止多个用户同时操作引起的数据损坏。

    • 乐观锁——只有当更新数据的时候才会锁定记录。
    • 悲观锁——从查询到更新和提交整个过程都会对数据记录进行加锁。

     

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

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

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

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

    • Serializable【TRANSACTION_SERIALIZABLE】
    • Repeatable read【TRANSACTION_REPEATABLE_READ】
    • Read committed【TRANSACTION_READ_COMMITTED】

     

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

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

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

     

    16、什么是JDBC的最佳实践?

    • 数据库资源是非常昂贵的,用完了应该尽快关闭它。Connection, Statement, ResultSet等JDBC对象都有close方法,调用它就好了。
    • 养成在代码中显式关闭掉ResultSet,Statement,Connection的习惯,如果你用的是连接池的话,连接用完后会放回池里,但是没有关闭的ResultSet和Statement就会造成资源泄漏了。
    • 在finally块中关闭资源,保证即便出了异常也能正常关闭。
    • 大量类似的查询应当使用批处理完成。
    • 尽量使用PreparedStatement而不是Statement,以避免SQL注入,同时还能通过预编译和缓存机制提升执行的效率。
    • 如果你要将大量数据读入到ResultSet中,应该合理的设置fetchSize以便提升性能。
    • 你用的数据库可能没有支持所有的隔离级别,用之前先仔细确认下。
    • 数据库隔离级别越高性能越差,确保你的数据库连接设置的隔离级别是最优的。
    • 如果在WEB程序中创建数据库连接,最好通过JNDI使用JDBC的数据源,这样可以对连接进行重用。
    • 如果你需要长时间对ResultSet进行操作的话,尽量使用离线的RowSet。
    一个小小后端的爬行痕迹
  • 相关阅读:
    java实现第四届蓝桥杯好好学习
    java实现第四届蓝桥杯好好学习
    java实现第四届蓝桥杯好好学习
    IntelliJ Idea 常用快捷键 列表(实战终极总结!!!!)
    Intelli IDEA快捷键(配合IdeaVim)
    findBugs学习小结
    Long.ValueOf("String") Long.parseLong("String") 区别 看JAVA包装类的封箱与拆箱
    【报错】IntelliJ IDEA中绿色注释扫描飘红报错解决
    IDEA入门级使用教程----你怎么还在用eclipse?
    玩转Vim 编辑器
  • 原文地址:https://www.cnblogs.com/heikedeblack/p/14861907.html
Copyright © 2020-2023  润新知