zoukankan      html  css  js  c++  java
  • Java数据库操作

    问题及答案来源自《Java程序员面试笔试宝典》第四章 Java基础知识 4.11Java数据库操作

    1、如何通过JDBC访问数据库

    什么是JDBC:

    Java数据库连接(Java database connectivity,JDBC)用于在Java程序中实现数据库操作功能,它提供了执行SQL语句、

    访问各种数据库的方法,并为各种不同的数据库提供统一的操作接口,java.sql包中包含了JDBC操作数据库的所有类

    通过JDBC访问数据库的步骤如下:

    • 加载JDBC驱动器,把数据库的JDBC驱动加载到classpath中(把目标数据库的JDBC驱动复制到项目的lib文件夹下)
    • 加载JDBC驱动,并将其注册到DriverManager中,一般使用反射Class.forName(String driveName)方式实现
    • 建立数据库连接,取得Connection对象,一般通过DriverManager.getConnection(url, username, password)方式实现
    • 建立Statement对象或是PreparedStatement对象
    • 执行SQL语句
    • 访问结果集ResultSet对象
    • 依次将上述对象关闭,释放掉所占用的资源

    用JDBC访问MySQL实例(看看就行):

      1 import java.util.*;
      2 import java.sql.DriverManager;
      3 import java.sql.ResultSet;
      4 import java.sql.Statement;
      5 import java.sql.Connection;
      6 import java.sql.PreparedStatement;
      7 
      8 // 远程数据库访问接口
      9 public class DataBase{
     10 
     11     // 数据库配置系列:
     12     private static final String DRIVER = "com.mysql.jdbc.Driver";
     13     private static final String DB_URI = "jdbc:mysql://localhost:3306/game_test";
     14     private static final String DB_USER = "root";
     15     private static final String DB_PWD = "root";
     16 
     17     // SQL语句(MySQL):
     18     // 查询前五个最高分的用户名和分数
     19     private static final String LOAD_SQL = "SELECT user_name, point FROM user_point WHERE game_type = 1 ORDER BY point DESC limit 5";
     20     // 存储用户名和分数
     21     private static final String SAVE_SQL = "INSERT INTO user_point(user_name, point, game_type) VALUES (?, ?, ?)";
     22     
     23     // 静态构造函数 -> 类加载的时候调用
     24     static {
     25         try {
     26             Class.forName(DRIVER); // 加载类 =》加载JDBC驱动
     27         } catch (ClassNotFoundException e) {
     28             e.printStackTrace();
     29         }
     30     }
     31 
     32     @Override
     33     public List<Player> loadData() {
     34         Connection conn = null;
     35         ResultSet rs = null;
     36         List<Player> players = new ArrayList<Player>();
     37         try {
     38         // 建立数据库连接
     39             conn = DriverManager.getConnection(DB_URI, DB_USER, DB_PWD);
     40        // 建立Statement对象
     41             Statement stmt = conn.createStatement();
     42        // 执行SQL语句(导出数据)
     43             rs = stmt.executeQuery(LOAD_SQL);
     44        // 访问结果集ResultSet对象 将数据保存到List中
     45             while(rs.next()){
     46                 players.add(new Player(rs.getString(1), rs.getInt(2)));
     47             }
     48             stmt.close();
     49         } catch (Exception e) {
     50             e.printStackTrace();
     51         } finally{
     52         // 关闭对象并释放资源
     53             try{
     54                 if(conn!=null){
     55                     conn.close();
     56                 }
     57                 if(rs!=null){
     58                     rs.close();
     59                 }
     60             } catch(Exception e){
     61                 e.printStackTrace();
     62             }
     63             
     64         }
     65 
     66         return players;
     67     }
     68 
     69     @Override
     70     public void saveData(Player player) {
     71         Connection conn = null;
     72         PreparedStatement stmt = null;
     73         try {
     74        // 建立数据库连接
     75             conn = DriverManager.getConnection(DB_URI, DB_USER, DB_PWD);
     76        // 建立prepareStatement对象
     77             stmt = conn.prepareStatement(SAVE_SQL);
     78             stmt.setObject(1, player.getName());
     79             stmt.setObject(2, player.getPoint());
     80             stmt.setObject(3, 1);
     81        // 执行SQL语句(保存)
     82             stmt.execute();
     83         } catch (Exception e) {
     84             e.printStackTrace();
     85         } finally{
     86        // 关闭对象并释放资源
     87             try{
     88                 if(conn!=null){
     89                     conn.close();
     90                 }
     91                 if(stmt!=null){
     92                     stmt.close();
     93                 }
     94             } catch(Exception e){
     95                 e.printStackTrace();
     96             }
     97             
     98         }
     99 
    100     }
    101 
    102 }

    2、JDBC处理事务采用什么方法?

    什么是事务:

    一个事务是由一条或多条对数据库操作的SQL语句所组成的一个不可分割的工作单元,只有当事务中的所有操作

    都正常执行完了,整个事务才会被提交给数据库。

    JDBC中事务的操作:

    • commit方法或rollback方法:都是结束事务的操作 
    • commit():表示完成对事务的提交,事务操作成功后系统将自动调用commit方法
    • rollback():表示完成事务回滚,多用于在处理事务的过程中出现了异常的情况

    当然在JDBC中,也可以通过调用setAutoCommit(false)方法来禁止自动提交,然后就可以把多个数据库操作的表达式作为

    一个事务,在操作完成后调用commit方法,在这种情况下就可以在异常捕获的代码块中调用rollback方法进行事务回滚

    通过这种方法可以保证对数据库的多次操作后,数据仍然保持一致性

    JDBC的事务隔离级别(由低到高):

    TRANSACTION_NONE JDB:不支持事务

    TRANSACTION_READ_UNCOMMITTED:未提交读,说明在提交前一个事务可以看到另一个事务的变化,

    这样读脏数据、不可重复读和虚读都是允许的

    TRANSACTION_READ_COMMITTED:已提交读,说明读取未提及的数据是不允许的, 这样不可重复读和

    虚读都是允许的

    TRANSACTION_REPEATABLE_READ:可重复读,说明事务保证能够再次读取相同的数据而不会失败,但

    虚读仍然会出现

    TRANSACTION_SERIALIZABLE:可序列化,是最高的事务等级,它防止读脏数据、不可重复读和虚读

    关于读脏数据、不可重复读和虚读:

    读脏数据:一个事务读取了另一个事务尚未提交的数据,例如事务A和事务B并发执行,当事务A更新后事务B查询

    读取到事务A尚未提交的数据,此时事务A回滚,则事务B读取到的数据是无效的脏数据

    不可重复读:一个事务的操作导致另一个事务前后两次读取到不同的数据,例如当事务A与事务B并发执行时,当

    事务B查询读取数据后,事务A更新操作更改事务B查询到的数据,此时事务B再次读该数据,发现前后两次的数据

    不一样

    虚读:一个事务的操作导致另一个事务前后两次查询的结果数据量不同,例如当事务A与事务B并发执行时,当事务

    B查询读取数据后,事务A新增或删除了一条满足事务B的查询条件的记录,此时事务B再次查询发现查询不到上一次

    存在的记录或查询到上一次不存在的记录

    JDBC如何设置事务隔离级别:

    事务隔离级别越高,为避免冲突所花的精力也就越多,可以通过Connection对象的conn.setTransactionLevel()方法来

    设置事务隔离级别,通过conn.getTransactionIsolation()方法来确定当前事务的隔离级别

    3、Class.forName的作用是什么?

    在Java语言中,任何类只有被装载到JVM上才能允许,Class.forName()方法的作用就是把类加载到JVM中,它会返回一个

    与带有给定字符串类名的类或接口相关联的Class对象,并且JVM会加载这个类,同时JVM会执行该类的静态代码段

    JDBC规范中要求Driver类在使用前必须向DriverManager注册自己,所有当执行Class.forName("com.mysql.jdbc.Driver")

    时,JVM会加载名字为"com.mysql.jdbc.Driver"对应的Driver类,这个类的部分实现代码如下:

    1 public class Driver extends NonRegisteringDriver implements Java.sql.Driver{
    2     static{
    3         try{
    4             java.sql.DriverManager.registerDriver(new Driver);
    5         } catch(SQLException e){
    6             throw new RuntimeException("Can't register driver!");
    7         }
    8     }
    9 }

    在调用Class.forName()方法时,这个Driver类就被加载了,由于静态部分被执行,依次Driver也被注册到了DriverManager中

    4、Statement、PreparedStatement和CallableStatement有什么区别?

    Statement用于执行不带参数的简单SQL语句并返回它所生成结果的对象,每次执行SQL语句时,数据库都要编译该SQL语句,

    示例如下:

    1 Statement stmt = conn.getStatement();
    2 stmt.executeUpdate("insert into client values('aa', 'aaaa')");

    PreparedStatement表示预编译的SQL语句的对象,用于执行带参数的预编译SQL语句,示例如下:

    1 PreparedStatement stmt = conn.prepareStatement("select * from Employee where id = ?");
    2 stmt.setInt(1, 1);  // 传递参数,第一个问号
    3 ResultSet rs = stmt.executeQuery();

    CallableStatement则提供了用来调用数据库中存储过程的接口,如果有输出参数要注册,说明是输出参数

    CallableStatement由prepareCall()方法创建,它为所有DBMS提供了一种标准形式调用已存储过程的方法,它从

    prepareStatement中继承了用于处理输入参数的方法,而且还增加了调用数据库中的存储过程和函数以及设置输出

    类型参数的功能

    虽然Statement对象与PrepareStatement对象能够完成相同的功能,但相比执行,PrepareStatement具有以下优点:

    • 效率更高
    • 代码可读性和可维护性更好
    • 安全性更好

    5、getString()方法和getObject()方法有什么区别?

    JDBC提供了getString()、getInt()和getData()方法从ResultSet中获取数据,当查询结果集中的数据量较小时,不用考虑

    性能,使用这些方法完全能够满足需求,但是当查询结果集中的数据量非常大时则会抛出异常,而通常情况下使用getObject()

    方法就可以解决这个问题

    getString()或getInt()等方法在被调用时,程序会一次性地把数据都放到内存中,然后通过调用ResultSet对象的next()和getString()方法

    来获取数据,当数据量大到内存中放不下的时候会抛出异常,而使用getObject就不会抛出异常,因为数据不会一次性被读到内存中,

    而是每次调用直接从数据库中去获取数据,因此使用getObject方法不会因为数据量过大而出错

    6、使用JDBC时需要注意哪些问题?

    及时释放连接:

    JDBC编程需要先建立数据库连接才能进行对数据库的访问,因而数据库连接成了非常重要的资源。JDBC连接池提供

    了JDBC连接定义和有限的连接资源。编程时需要保证数据库接的正常和及时地关闭,及时释放不使用的连接

    Statement和PreparedStatement的使用原则:

    (1)放在循环外面初始化。因为每次执行conn.createStatement()和conn.preparedStatemetn(),相当于在数据库中打开游标,

    放在循还内反复打开游标浪费资源,不能及时关闭则可能导致抛出异常

    (2)只要不再使用结果集,就立即关闭对应的Statement

    7、什么是JDO

    JDO:Java数据对象(Java Data Object)是一个用于存取某种数据仓库中的对象的标准API,它使开发人员能够间接访问数据库

    JDO是JDBC的一个补充,它提供了透明的对象存储,因此对于开发人员来说,存储数据对象完全不需要额外的代码,这些繁琐

    的工作已经转移到JDO产品提供商身上,让开发人员的精力和时间集中到业务逻辑上。

    8、JDBC与Hibernate有什么区别?

    Hibernate是JDBC的封装,采用配置文件的形式将数据库的连接参数写到XML文件中,对数据库的访问还是通过JDBC来完成

    (1)Hibernate是一个持久层框架,它将表的信息映射到XML文件中,再从XML文件映射到相应的持久化类中,这样就可以使用

    Hibernate独特的查询语言(HQL)了,Hibernate的HQL查询语句返回的是List<Object[.]>类,而JDBC通过statement返回的查询

    结果是ResultSet,并且有时候需要自己封装到List中

    (2)Hibernate具有访问层(DAO层,数据访问接口),该层是HQL查询语句唯一出现的位置,再往上层都不会出现查询语句,

    而JDBC可以随时连接随时访问,例如有100个类都有SQL查询语句,如果表名变了,那么要使用JDBC的方式必须重写

    所有查询语句,而采用Hibernate的方式只需要修改DAO层的类即可,因此Hibernate具有很好的维护性和扩展性

  • 相关阅读:
    mysql8.0.x中datasource信息
    IDEA关联mysql失败Server returns invalid timezone. Go to 'Advanced' tab and set 'serverTimezon'
    SpringSecurity配置文件
    druid监控
    Redis安装教程
    一个简单的springboot+mybatis-plus+thymeleaf的学生管理系统
    RestFul风格
    Vue利用v-for渲染时表单信息出不来
    springboot项目Invalid bound statement (not found): com.xxxx.dao.xxxDAO.xxx解决方法
    JSON
  • 原文地址:https://www.cnblogs.com/wyb666/p/10356692.html
Copyright © 2011-2022 走看看