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具有很好的维护性和扩展性

原文地址:https://www.cnblogs.com/wyb666/p/10356692.html