JDBC概述
什么是JDBC
JDBC(Java DataBase Connectivity)是一种用于执行SQL语句的Java API,它由一组用Java语言编写的类和接口组成。通过这些类和接口,JDBC把SQL语句发送给不同类型的数据库进行处理并接收处理结果。
JDBC分类
- 对Java开发人员而言是API,对数据库提供商而言是接口。面向开发人员:作为API,JDBC为程序开发提供标准的接口.
- 面向数据库厂商:作为接口,让数据库厂商按标准方法来实现数据库连接与操作(数据库驱动程序)。
JDBC编程步骤
- 步骤一:根据应用程序所用的数据库,选择JDBC驱动程序类型。
- 步骤二:连接到数据库,得到Connection对象。
- 步骤三:通过Connection创建Statement对象
- 步骤四:使用Statement对象提交SQL语句
- 步骤五:操作结果集
- 步骤六:回收数据库资源
JDBC的四种驱动程序
- 类型一(JDBC-ODBC桥加ODBC驱动程序): 由SUN公司提供通用的驱动,能访问各种数据库,但效率极低。所以现在这种类型的驱动除了用于测试外, 不推荐使用。
- 类型二(本地API和部分基于Java的驱动程序): 本地库Java驱动程序,执行效率高,客户端必须安装本地驱动,维护不方便,加载困难,不便于移植,所以也不提倡使用。
- 类型三(为数据库中间件实现的纯Java驱动程序): 网络协议纯Java驱动程序(通用),客户端不必安装本地库,使用方便,但性能相对较低。这种驱动一般用在分布式系统的开发中。
- 类型四(本地协议纯Java驱动程序): 这类驱动程序将JDBC调用直接转换为DBMS所使用的网络协议,来自客户端机器上的请求可直接调用DBMS服务器。驱动程序是由纯Java所写成,不需要转换或者通过其他中介软件就可以与数据与数据库沟通,因此 性能是最好的。
四种类型的驱动程序的工作机理
在我们实际开发工程中,选择驱动器应遵循下面的原则即可:
- 如果我们编写的程序只访问一种类型的数据库,那么最好选择类型4。
- 如果程序需要同时访问多个类型的数据库,那么最好选择类型3。
- 如果类型3和4都不适用于所用的数据库,才选择类型2。
- 类型1通常不会考虑为部署级的驱动程序,一般只在开发或者测试中才会使用。
连接到数据库
我们要访问数据库,那么连接到数据库将是我们的第一步,在JDBC中有下面两种方法可以设置一个到数据库的连接:
- 使用java.sql. DriverManager 类的静态方法getConnection(),该方法带一个URL代表数据源的名称。
- 使用JNDI(Java Naming and Directory Interface,Java命名服务)查找数据源的名称,JNDI返回一个javax.sql. DataSource 对象,然后使用 DataSource 类的 getConnection() 方法。
DataSource类和DriverManager类的区别:
在了解这两个类的区别之前,我们应先要了解什么是连接池,以及连接池的作用。
在实际应用开发中,建立与数据库的连接是一件很耗资源的工作,频繁的数据库连接建立操作会产生较大的系统开销。为了解决这个问题,就出现了数据库连接池技术。数据库连接池技术将已经创建的数据库连接放在一个连接缓冲池中,当我们创建数据库连接时候,如果连接池中已经存在对该数据库的连接,就直接从池中取出,不用再重新建立,从而提升了效率。
DataSource类和DriverManager类的区别是:DataSource类是从数据库连接池中获取连接,而DriverManager类是直接建立与数据库的连接。所以,在大型多层应用开发中,一般都是首选使用DataSource类来连接数据库。但是,DataSource类通常需要使用第三方应用程序,所以,当我们只是编写一个独立的应用时那么最好使用DriverManager。
在驱动程序加载后,我们就可以用DriverManager的如下静态方法之一来建立数据库的连接:
- public static Connection getConnection(String url):设立一个到指定数据库的连接。如果装载了多个JDBC驱动程序,DriverManager会选择恰当的驱动程序。
- public static Connection getConnection(String url, String user, String password):与上个方法类似。如果数据库需要身份验证,就要传递用户名和密码。
- public static Connection getConnection(String url, Properties info):Properties对象包含了要连接的信息,包括URL、用户名和密码等。
这些方法的返回值都是一个java.sql.Connection对象,Connection代表数据库连接对象,每个Connection代表一个与数据库的物理连接会话。要想访问数据库,就必须先获得数据库连接。
通过Connection创建Statement对象
在JDBC中有三种类型的Statement对象:
- java.sql.Statement:代表一个没有参数的简单SQL语句。
- java.sql.PreparedStatement:PreparedStatement是Statement接口的子接口,一个PreparedStatement对象代表一个预编译的SQL语句。该SQL语句带有参数,参数需要在SQL语句执行前进行设置。
- java.sql.CallableStatement:CallableStatement是PreparedStatement接口的子接口。CallableStatement对象用于调用数据库中的存储过程。
Connection有三个方法分别用于创建这三类Statement:
- Statement createStatement():创建基本的Statement对象。
- PreparedStatement prepareStatement(String sql):根据传入的SQL语句创建PreparedStatement对象。
- CallableStatement prepareCall(String sql):根据传入的SQL语句创建CallableStatement对象。
使用JDBC执行SQL语句
创建Statement对象之后,我们就应该执行SQL语句了,下面是三种类型的Statement来执行SQL语句:
使用Statement执行SQL语句
java.sql.Statement接口代表一条简单的SQL语句。Statement对象常用于执行一个肯定只发生一次,并且没有参数的SQL语句。Connection接口包含了三个方法用于创建Statement对象:
- Statement createStatement():创建一个默认的Statement 对象,该Statement对象的结果集将是只读的并且只能向前滚动的。
- tatement createStatement(int resultSetType, int concurrency):创建一个给定结果集类型和并发类型的Statement对象。
- Statement createStatement(int resultSetType, int concurrency, int holdability):创建一个给定结果集类型、并发类型和可保存性类型的Statement对象。
这里,参数resultSetType代表结果集的类型,该参数可以是如下三个取值之一:
- ResultSet.TYPE_FORWARD_ONLY:该常量控制记录指针只能向前移动。
- ResultSet.TYPE_SCROLL_INSENSITIVE:该常量控制记录指针可以自由移动,但是底层数据库中数据的改变不会影响结果集中的内容。
- ResultSet.TYPE_SCROLL_SENSITIVE:该常量控制记录指针可以自由移动,但是底层数据库中数据的改变要影响结果集中的内容。
concurrency控制结果集的并发类型,该参数可以是如下两个取值之一:
- ResultSet.CONCUR_READ_ONLY:该常量指示结果集是只读的(默认)。
- ResultSet.CONCUR_UPDATABLE:该常量指示结果集是可更新的。
holdability用于控制提交事务时结果集的关闭策略,该参数可以是如下两个取值之一:
- ResultSet.HOLD_CURSORS_OVER_COMMIT:该常量指示提交当前事务时,具有此可保存性的打开的 ResultSet 对象将保持开放。
- ResultSet.CLOSE_CURSORS_AT_COMMIT:该常量指示提交当前事务时,具有此可保存性的打开的 ResultSet 对象将被关闭。
Statement对象代表任何SQL语句,同时Statement接口提供了定义和执行SQL语句的一些方法,包括:
- ResultSet executeQuery(String sql):执行一个返回单个结果集的SQL语句,只能该方法执行SELECT语句。
- int executeUpdate(String sql):使用该方法执行不返回结果集的DDL和DML(Update、Insert、Delete)语句。如果执行的是DML,则返回值为执行SQL语句影响的行数。如果是执行DDL语句,则返回值为0。
- boolean execute(String sql):该方法可以执行任何SQL语句。如果执行后第一个结果为ResultSet对象,则返回true;如果执行后第一个结果为受影响的行数或者没有任何结果,则返回false。只有在不清楚SQL语句的类型时,才推荐使用execute()方法。如果该语句产生了结果集,则通过getResultSet()方法获得该结果集。
使用PreparedStatement执行SQL语句
Connection接口中包含了如下六个方法用于创建PreparedStatement对象:
- prepareStatement(String sql):使用给定SQL语句,创建一个默认的PreparedStatement对象。
- prepareStatement(String sql, int resultSetType, int concurrency, int holdability):使用给定SQL语句、结果集类型、并发类型和可保存性类型,创建一个PreparedStatement对象。
- prepareStatement(String sql, int resultSetType, int concurrency) :使用给定SQL语句、结果集类型和并发类型,创建一个PreparedStatement对象。
- prepareStatement(String sql, int pk):创建一个默认 PreparedStatement 对象,该对象能获取自动生成的键。参数pk指示是否应该返回自动生成的键的标志,它是 Statement.RETURN_GENERATED_KEYS 或 Statement.NO_GENERATED_KEYS 之一 。
- prepareStatement(String sql, String [ ] keys):创建一个默认 PreparedStatement 对象,该对象能获取自动生成的键。keys字符串数组代表组成主键的列名。
- prepareStatement(String sql, int [ ] keys):与上一个方法类似,除了列数组是用列索引代替列名来描述。
注意,最后三个prepareStatement()方法包含了自动产生主键的信息,它只适用于Insert方法。
使用CallableStatement调用存储过程
CallableStatement接口是PreparedStatement接口的子接口,代表存储过程。我们可以使用Connection的如下几个方法创建的CallableStatement对象来调用存储过程:
- CallableStatement prepareCall(String sql):使用给定SQL语句,创建CallableStatement。
- CallableStatement prepareCall(String sql, int resultSetType, int concurrency):使用给定的SQL语句、结果集类型和并发类型创建CallableStatement。
- CallableStatement prepareCall(String sql, int resultSetType, int concurrency, int holdability):使用给定的SQL语句、结果集类型、并发类型和保存类型创建CallableStatement。
创建CallableStatement对象时,需要传入调用存储过程的SQL语句。调用存储过程的SQL语句总是"{call 存储过程名(?,?,?..)}"这种格式,其中的问号作为存储过程参数的占位符。