jdbc pdf
在本文中,我们提供了全面的JDBC教程(Java数据库连接性),这是Oracle提供的API,允许程序员处理Java应用程序中的不同数据库:它允许开发人员建立与数据库的连接,定义特定客户端如何访问给定的客户端。数据库,提供了用于读取,插入,更新和删除数据库中数据条目的机制,并负责处理由不同SQL语句组成的事务。
在本文中,我们将解释主要的JDBC组件,例如语句,结果集或存储过程。
JDBC需要程序员可能要使用的不同数据库的驱动程序。
我们将对此进行详细说明,并提供一些示例。
JDBC从一开始就与Java一起出现。 第一个发行版于1997年2月随JDK 1.1一起发布,此后,JDBC一直是Java的重要组成部分。 包含JDBC的主要软件包是http://docs.oracle.com/javase/8/docs/api/java/sql/package-summary.html和http://docs.oracle.com/javase/8/ docs / api / javax / sql / package-summary.html 。
有关最新的JDBC版本(4.2)及其开发和维护的所有信息,可以在JSR 221中找到。
本文显示的所有示例都是使用Java 8更新0_25和Eclipse SDK版本Luna 4.4实现的。 在本文末尾,您可以下载所有这些示例以及更多示例!
目录
- 1.组成 2.连接 3.数据类型 4.驱动程序 5.数据库 6.结果集 7.存储过程 8.陈述 9.批处理命令 10.交易 11. CRUD命令 12. Java 8 13.基于JDBC构建的Sql库 14.单元测试 15.总结 16.下载 17.链接
1.组成
JDBC API允许程序员和Java应用程序与数据库进行交互。 它支持执行不同SQL语句并处理来自不同数据源的结果。
在本节中,我们将尝试总结并列出每个Java应用程序中最重要的JDBC组件,所有这些组件将在下一章中进行详细说明。
- 首先,Java应用程序需要创建和建立特定数据库的连接。 使用驱动程序管理器(例如,接口
java.sql.DriverManager
一个实例)或直接通过JDBC数据源完成此操作。 为此,可以使用接口javax.sql.DataSource
。 如前所述,我们将在下一章中更详细地解释这些组件。 - 一旦与数据库连接,就可以使用
java.sql.Connection
执行CRUD(创建,读取,更新,删除)SQL语句或操作。 这些说明将在本教程中进行解释。 - 为了执行这些操作,程序员可以使用基于
java.sql.Statement
和java.sql.PreparedStatement
的类。 最后几次在多次执行同一条语句时效率更高,并提供了我们将在本教程中列出的其他好处。
JDBC接口连接提供了创建语句实例的机制:
PreparedStatement countriesStatement = connection.prepareStatement("UPDATE COUNTRIES SET NAME = ? WHERE ID = ?");
countriesStatement.setString(1, "Spain");
countriesStatement.setInt(2, 123456789);
- 诸如插入,更新或删除之类的操作将返回修改后的行数,而不会返回其他任何内容:
// countriesStatement belongs to the class Statement, returning number of updated rows
int n = countriesStatement.executeUpdate();
- 选择操作(查询)以
java.sql.ResultSet
内部的行java.sql.ResultSet
返回结果。 按名称或数字检索行; 结果元数据也可用:
// countriesStatement belongs to the class Statement
ResultSet rs = countriesStatement.executeQuery("SELECT NAME, POPULATION FROM COUNTRIES");
//rs contains the results in rows plus some metadata
...
- 通常,JDBC使用连接池来管理连接。 连接池(例如C3P0或DBCP)有不同的实现。 这些是JDBC连接组,在需要时从应用程序使用或借用它们,并在任务完成时释放。 关于如何在JDBC中使用和配置连接池的文档很多,可以在以下链接中找到很好的教程: http://docs.oracle.com/cd/E13222_01/wls/docs81/ConsoleHelp/jdbc_connection_pools.html 。
- 使用JDBC时,还可以使用其他功能:存储过程,可调用语句,批处理……所有这些功能都将在本教程中进行描述。
2.连接
为了连接到数据库,我们需要使用java.sql.Connection
对象。 我们可以使用java.sql.DriverManager
类的getConnection()
方法来完成此操作。 此方法接收数据库主机和凭据作为参数。
此代码段显示了如何为本地MySQL数据库创建连接。
//MySQL driver is loaded
Class.forName( "com.mysql.jdbc.Driver" );
//Connection object is created using the db host and credentials
Connection connect = DriverManager.getConnection("jdbc:mysql://localhost/countries?"+ "user=root&password=root" );
连接对象允许程序员执行以下操作:
- JDBC语句的创建:可以使用连接对象来创建
Statement
,PreparedStatement
或CallableStatement
实例,这些实例提供执行不同SQL语句的方法。 这是创建PreparedStatement
的示例:
//the connection conn is used to create a prepared statement with the given sql operation
PreparedStatement updateStmt = conn.prepareStatement( sql );
该语句可以执行作为参数传递的sql更新。
- 提供了提交或回滚给定事务的可能性。 JDBC连接支持两种不同的工作方式:
autocommit=true
和autocommit=false
。 第一个将所有事务直接提交到数据库,第二个需要特殊的命令来提交或回滚事务。 我们将在本教程的相关章节中看到更多详细信息。 以下代码段显示了如何更改JDBC连接的自动提交模式:
//it changes the mode to auto commit=false
connect.setAutoCommit( false );
- 可能获取有关已使用数据库的元信息。
- 其他选项,例如批处理,存储过程等。
我们将详细解释所有这些功能,目前最好知道什么是JDBC连接以及使用JDBC连接可以完成的操作。
3.数据类型
JDBC将Java数据类型转换为适当的JDBC类型,然后再在数据库中使用它们。 Java和JDBC数据类型之间存在默认映射,该映射提供了数据库实现和驱动程序之间的一致性。
下表包含这些映射:
SQL | JDBC / Java | 二传手 | 吸气剂 |
---|---|---|---|
VARCHAR | java.lang.String | setString | getString |
焦炭 | java.lang.String | setString | getString |
LONGVARCHAR | java.lang.String | setString | getString |
比特 | 布尔值 | setBoolean | getBoolean |
数字 | 大十进制 | setBigDecimal | getBigDecimal |
天音 | 字节 | setByte | getByte |
小灵通 | 短 | setShort | getShort |
整数 | 整型 | setInt | getInt |
比金特 | 长 | setLong | getLong |
真实 | 浮动 | setFloat | getFloat |
浮动 | 浮动 | setFloat | getFloat |
双 | 双 | setDouble | getDouble |
VARBINARY | 字节[] | setBytes | getBytes |
二进制 | 字节[] | setBytes | getBytes |
日期 | java.sql.Date | 设置日期 | getDate |
时间 | java.sql.Time | 设置时间 | getTime |
时间戳 | java.sql.Timestamp | setTimestamp | getTimestamp |
CLOB | java.sql.Clob | setClob | getClob |
BLOB | java.sql.Blob | setBlob | getBlob |
阵列 | java.sql.Array | setARRAY | getARRAY |
参考 | java.sql.Ref | SetRef | getRef |
结构 | java.sql.Struct | SetStruct | getStruct |
在SQL和Java中,空值的处理方式有所不同。 在Java中使用SQL空值进行处理时,最好遵循一些最佳做法,例如避免使用基本类型,因为它们不能为空,但可以转换为默认值,例如int为0,布尔值为false等。
取而代之的是,建议对原始类型使用包装器类。 ResultSet
类包含一个名为wasNull()
的方法,在这些情况下非常有用。 这是一个用法示例:
Statement stmt = conn.createStatement( );
String sql = "SELECT NAME, POPULATION FROM COUNTRIES";
ResultSet rs = stmt.executeQuery(sql);int id = rs.getInt(1);
if( rs.wasNull( ) ) {id = 0;
}
4.驱动程序
JDBC驱动程序管理器java.sql.DriverManager
是JDBC API的最重要元素之一。 它是处理JDBC驱动程序列表的基本服务。 它包含允许Java应用程序连接到所需JDBC驱动程序的机制和对象。 它负责管理不同类型的JDBC数据库驱动程序。 总结驱动程序管理器的主要任务是了解可用驱动程序的列表,并处理特定选定驱动程序和数据库之间的连接。
此类中最常用的方法是DriverManager.getConnetion()
。 此方法建立与数据库的连接。
这是一个用法示例:
// Create the connection with the default credentials
java.sql.Connection conn = DriverManager.getConnection("jdbc:hsqldb:mem:mydb", "SA", "" );
我们可以使用DriverManager.registerDriver().
方法注册驱动程序DriverManager.registerDriver().
:
new org.hsqldb.jdbc.JDBCDriver();
DriverManager.registerDriver( new org.hsqldb.jdbc.JDBCDriver() );
我们还可以通过调用Class.forName()
方法来加载驱动程序:
// Loading the HSQLDB JDBC driver
Class.forName( "org.hsqldb.jdbc.JDBCDriver" );...// connection to JDBC using mysql driver
Class.forName( "com.mysql.jdbc.Driver" );
主要区别在于方法registerDriver()
需要驱动程序在编译时可用,加载驱动程序类不需要驱动程序在编译时可用。 在JDBC 4之后,不需要真正调用这些方法,并且应用程序不需要单独注册驱动程序,也不需要加载驱动程序类。 也建议不要使用registerDriver()
方法手动注册驱动程序。
DriverManager
类的其他有趣方法是getDriver(String url)
,它尝试通过给定的字符串查找驱动程序,而getDrivers()
返回先前已在Driver Manager中注册的所有驱动程序的枚举:
Enumeration drivers = DriverManager.getDrivers();
while( drivers.hasMoreElements() )
{Driver driver = drivers.nextElement();System.out.println( driver.getClass() );
}
5.数据库
JDBC支持大量数据库。 它使用不同的驱动程序来抽象其差异和工作方式。 DriverManager
类负责加载正确的数据库,在加载正确的数据库之后,用于访问数据库以查询和修改数据的代码将保持(或多或少)不变。
这是JDBC(在Oracle中正式注册)受支持的数据库的列表: http : //www.oracle.com/technetwork/java/index-136695.html 。
在本章中,我们将展示如何使用不同的数据库:MySQL和HSQLDB。 第一个是程序员众所周知的且已被广泛使用,第二个是HSQLDB,它是一个非常有用的测试数据库,具有内存功能。 我们将看到如何同时使用这两种方法,并且会发现,除了加载适当的JDBC驱动程序之外,应用程序的其余部分保持不变:
MySQL示例:
public static void main( String[] args ) throws ClassNotFoundException, SQLException{// connection to JDBC using mysql driverClass.forName( "com.mysql.jdbc.Driver" );Connection connect = DriverManager.getConnection("jdbc:mysql://localhost/countries?"+ "user=root&password=root" );selectAll( connect );// close resources, in case of exception resources are not properly cleared
...}/*** select statement and print out results in a JDBC result set* * @param conn* @throws SQLException*/private static void selectAll( java.sql.Connection conn ) throws SQLException{Statement statement = conn.createStatement();ResultSet resultSet = statement.executeQuery( "select * from COUNTRIES" );while( resultSet.next() ){String name = resultSet.getString( "NAME" );String population = resultSet.getString( "POPULATION" );System.out.println( "NAME: " + name );System.out.println( "POPULATION: " + population );}}
内存中(HSQLDB)示例:
public static void main( String[] args ) throws ClassNotFoundException, SQLException{// Loading the HSQLDB JDBC driverClass.forName( "org.hsqldb.jdbc.JDBCDriver" );// Create the connection with the default credentialsjava.sql.Connection conn = DriverManager.getConnection( "jdbc:hsqldb:mem:mydb", "SA", "" );// Create a table in memoryString countriesTableSQL = "create memory table COUNTRIES (NAME varchar(256) not null primary key, POPULATION varchar(256) not null);";// execute the statement using JDBC normal StatementsStatement st = conn.createStatement();st.execute( countriesTableSQL );// nothing is in the database because it is just in memory, non persistentselectAll( conn );// after some insertions, the select shows something different, in the next execution these// entries will not be thereinsertRows( conn );selectAll( conn );}.../*** select statement and print out results in a JDBC result set* * @param conn* @throws SQLException*/private static void selectAll( java.sql.Connection conn ) throws SQLException{Statement statement = conn.createStatement();ResultSet resultSet = statement.executeQuery( "select * from COUNTRIES" );while( resultSet.next() ){String name = resultSet.getString( "NAME" );String population = resultSet.getString( "POPULATION" );System.out.println( "NAME: " + name );System.out.println( "POPULATION: " + population );}}
正如我们在最后的程序中看到的那样, selectAll
方法的代码完全相同,只是JDBC驱动程序的加载和连接创建发生了变化。 您可以想象在不同环境下工作时,它的功能多么强大。 HSQLDB版本的代码还包含负责创建内存数据库并插入一些行的代码,但这只是出于显示和清晰目的,可以用不同的方式完成。
6.结果集
类java.sql.ResultSet
表示数据库表的结果集。 通常创建它; 通过执行SQL查询(使用Statement或PreparedStatement的select语句)。 它包含数据行,数据存储在该行中。 这些数据可以通过索引(以1开头)或属性名称进行访问:
// creating the result setResultSet resultSet = statement.executeQuery( "select * from COUNTRIES" );// iterating through the results rowswhile( resultSet.next() ){// accessing column values by index or nameString name = resultSet.getString( "NAME" );int population = resultSet.getInt( "POPULATION" );System.out.println( "NAME: " + name );System.out.println( "POPULATION: " + population );// accessing column values by index or nameString name = resultSet.getString( 1 );int population = resultSet.getInt( 2 );System.out.println( "NAME: " + name );System.out.println( "POPULATION: " + population );}
如前所示,ResultSets包含用于获取不同Java类型的列值的getter方法。 它还包含一个指向当前数据行的光标。 最初,光标指向第一行之前。 next方法将光标移动到下一行: java.sql.ResultSet.next()
。
可以使用默认属性(例如仅向前移动且不可更新的光标)创建ResultSets。 如果程序员想使用其他类型的属性,则可以在创建Statement时指定,以便通过更改传递的参数来生成结果集:
/**
* indicating result sets properties that will be created from this statement: type,
* concunrrency and holdability
*/
Statement statement = conn.createStatement( ResultSet. TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE, ResultSet.CLOSE_CURSORS_AT_COMMIT );
使用这种结果集,可以在两个方向上移动光标,并为此目的使用结果集将新数据更新或插入数据库中。
7.存储过程
在本章中,我们将解释什么是存储过程以及如何在JDBC中使用它们。 对于示例,我们将使用基于MySQL的存储过程。
存储过程是SQL语句集,作为执行逻辑单元的一部分并执行定义的任务。 当封装一组要在数据库上执行的操作时,它们非常有用。
首先,我们将在MySQL数据库中创建一个过程,以下脚本将帮助我们完成此任务:
delimiter //CREATE PROCEDURE spanish (OUT population_out INT)BEGINSELECT COUNT(*) INTO population_out FROM countries;END//delimiter ;CALL simpleproc(@a);
基本上,以上脚本创建了一个名为Spanish的过程,该过程具有一个类型为int且没有输入参数的输出属性。 该过程返回数据库中所有国家的计数。
一旦创建了过程,就可以从Java应用程序中使用它。为了调用存储过程,我们需要使用接口java.sql.CallableStatement
特殊语句,这些语句允许程序员执行存储过程,以指示输出属性和要使用的输入参数。 在我们的简单示例中,仅配置了输出属性。 这是一个例子:
CallableStatement callableStatement = null;// the procedure should be created in the databaseString spanishProcedure = "{call spanish(?)}";// callable statement is usedcallableStatement = connect.prepareCall( spanishProcedure );// out parameters, also in parameters are possible, not in this casecallableStatement.registerOutParameter( 1, java.sql.Types.VARCHAR );// execute using the callable statement method executeUpdatecallableStatement.executeUpdate();// attributes are retrieved by indexString total = callableStatement.getString( 1 );System.out.println( "amount of spanish countries " + total );
我们可以理解如何使用java.sql.PreparedStatement.executeUpdate()
方法指示如何将过程的输出存储在何处以及如何执行该过程。 大多数数据库都支持存储过程,但是它们的语法和行为可能有所不同,因此,根据存储过程的数据库,处理存储过程的Java应用程序可能会有所不同。
8.陈述
如本教程中已经提到的,JDBC使用接口java.sql.Statement
来执行不同SQL查询和操作,例如插入,更新或删除。 这是基本接口,包含所有基本方法,例如java.sql.Statement.executeQuery(String)
或java.sql.Statement.executeUpdate(String)
。
当程序员不需要多次执行相同的查询或不需要对查询和语句进行参数化时,建议使用此接口的实现。 通常,我们可以说此接口适合于执行DDL语句(创建,更改,删除)。 这些语句通常不会多次执行,并且不需要支持不同的参数。
如果程序员在重复SQL查询或参数化时需要更高的效率,则应使用java.sql.PreparedStatement
。 该接口继承了前面提到的基本语句接口,并提供了参数设置。 由于此功能,此接口可更安全地防止SQL注入攻击。 这是一段代码,显示了此接口的示例:
System.out.println( "Updating rows for " + name + "..." );String sql = "UPDATE COUNTRIES SET POPULATION=? WHERE NAME=?";PreparedStatement updateStmt = conn.prepareStatement( sql );// Bind values into the parameters.
updateStmt.setInt( 1, 10000000 ); // population
updateStmt.setString( 2, name ); // name// update prepared statement using executeUpdate
int numberRows = updateStmt.executeUpdate();System.out.println( numberRows + " rows updated..." );
使用准备好的语句的另一个好处是可以通过使用setObject()
方法来处理非标准对象。 这是一个例子:
PreparedStatement updateStmt2 = conn.prepareStatement( sql );// Bind values into the parameters using setObject, can be used for any kind and type of// parameter.updateStmt2.setObject( 1, 10000000 ); // populationupdateStmt2.setObject( 2, name ); // name// update prepared statement using executeUpdatenumberRows = updateStmt2.executeUpdate();System.out.println( numberRows + " rows updated..." );updateStmt2.close();
就像在与存储过程有关的章节中提到的那样,为此目的可以使用另一个接口,它称为java.sql.CallableStatement
并扩展了PreparedStatement。
9.批处理命令
JDBC提供了批量执行SQL语句列表的可能性,也就是说,可以全部执行。 程序员使用代码的方式取决于语句的类型,但总体思路是相同的。 在下一个代码片段中,显示了如何对java.sql.Statement
使用批处理:
Statement statement = null;statement = connect.createStatement();// adding batchs to the statement
statement.addBatch( "update COUNTRIES set POPULATION=9000000 where NAME='USA'" );
statement.addBatch( "update COUNTRIES set POPULATION=9000000 where NAME='GERMANY'" );
statement.addBatch( "update COUNTRIES set POPULATION=9000000 where NAME='ARGENTINA'" );// usage of the executeBatch method
int[] recordsUpdated = statement.executeBatch();int total = 0;
for( int recordUpdated : recordsUpdated )
{total += recordUpdated;
}System.out.println( "total records updated by batch " + total );
并使用java.sql.PreparedStatement
:
String sql = "update COUNTRIES set POPULATION=? where NAME=?";PreparedStatement preparedStatement = null;preparedStatement = connect.prepareStatement( sql );preparedStatement.setObject( 1, 1000000 );preparedStatement.setObject( 2, "SPAIN" );// adding batchespreparedStatement.addBatch();preparedStatement.setObject( 1, 1000000 );preparedStatement.setObject( 2, "USA" );// adding batchespreparedStatement.addBatch();// executing all batchsint[] updatedRecords = preparedStatement.executeBatch();int total = 0;for( int recordUpdated : updatedRecords ){total += recordUpdated;}System.out.println( "total records updated by batch " + total );
我们可以看到,这些区别基本上是使用SQL查询参数的方式以及如何构建查询的,但是在一行上执行多个语句的想法是相同的。 在第一种情况下,使用方法java.sql.Statement.executeBatch()
,在第二种情况下使用java.sql.PreparedStatement.addBatch()
和java.sql.Statement.executeBatch()
。
10.交易
JDBC支持事务,并包含实现基于事务的应用程序的方法和功能。 我们将在本章中列出最重要的那些。
-
java.sql.Connection.setAutoCommit(boolean)
:此方法接收布尔值作为参数,如果为true(这是默认行为),则所有SQL语句将自动保存在数据库中。 如果为false,将不会自动保留更改,这将通过使用java.sql.Connection.commit()
方法来完成。 -
java.sql.Connection.commit()
。 仅当自动提交设置为false或禁用时,才可以使用此方法。 也就是说,它仅适用于非自动提交模式。 执行此方法时,自上次提交/回滚以来的所有更改都将保留在数据库中。 -
java.sql.Connection.rollback()
。 仅当禁用自动提交时,才可以使用此方法。 它撤消或还原当前事务中完成的所有更改。
这是一个用法示例,在此示例中,我们可以看到如何使用setAutoCommit(false)
方法禁用自动提交模式。 调用commit()
时,所有更改都将commit()
并且使用rollback()
方法将当前事务更改rollback()
:
Class.forName( "com.mysql.jdbc.Driver" );
Connection connect = null;
try
{// connection to JDBC using mysql driverconnect = DriverManager.getConnection( "jdbc:mysql://localhost/countries?"+ "user=root&password=root" );connect.setAutoCommit( false );System.out.println( "Inserting row for Japan..." );String sql = "INSERT INTO COUNTRIES (NAME,POPULATION) VALUES ('JAPAN', '45000000')";PreparedStatement insertStmt = connect.prepareStatement( sql );// insert statement using executeUpdateinsertStmt.executeUpdate( sql );connect.rollback();System.out.println( "Updating row for Japan..." );// update statement using executeUpdate -> will cause an error, update will not be// executed becaues the row does not existsql = "UPDATE COUNTRIES SET POPULATION='1000000' WHERE NAME='JAPAN'";PreparedStatement updateStmt = connect.prepareStatement( sql );updateStmt.executeUpdate( sql );connect.commit();}
catch( SQLException ex )
{ex.printStackTrace();//undoes all changes in current transactionconnect.rollback();
}
finally
{connect.close();
}
11. CRUD命令
CRUD来自创建,读取,更新和删除。 JDBC支持所有这些操作和命令,在本章中,我们将展示执行所有这些操作的Java代码的不同片段:
创建语句。 可以使用JDBC创建数据库,这是创建内存数据库的示例:
// Create a table in memory
String countriesTableSQL = "create memory table COUNTRIES (NAME varchar(256) not null primary key, POPULATION varchar(256) not null);";// execute the statement using JDBC normal Statements
Statement st = conn.createStatement();
st.execute( countriesTableSQL );
插入语句。 JDBC支持插入。 程序员可以使用普通SQL语法,并将它们传递给JDBC提供的不同的语句类,例如Statement
, PreparedStatement
或CallableStatement
。 以下是几个示例:
Statement insertStmt = conn.createStatement();String sql = "INSERT INTO COUNTRIES (NAME,POPULATION) VALUES ('SPAIN', '45Mill')";
insertStmt.executeUpdate( sql );sql = "INSERT INTO COUNTRIES (NAME,POPULATION) VALUES ('USA', '200Mill')";
insertStmt.executeUpdate( sql );sql = "INSERT INTO COUNTRIES (NAME,POPULATION) VALUES ('GERMANY', '90Mill')";
insertStmt.executeUpdate( sql );
这些语句返回插入的行数。 这同样适用于update语句,这是如何更新数据库中的一组行的示例:
System.out.println( "Updating rows for " + name + "..." );Statement updateStmt = conn.createStatement();// update statement using executeUpdateString sql = "UPDATE COUNTRIES SET POPULATION='10000000' WHERE NAME='" + name + "'";int numberRows = updateStmt.executeUpdate( sql );System.out.println( numberRows + " rows updated..." );
输出为:
Updating rows for SPAIN...
4 rows updated...
选择对帐单。 可以使用JDBC语句执行任何(几乎)种类SQL查询。 这是一个非常简单的示例,该示例读取给定表的所有行并在标准控制台中将它们打印出来:
Statement statement = conn.createStatement();ResultSet resultSet = statement.executeQuery( "select * from COUNTRIES" );while( resultSet.next() )
{String name = resultSet.getString( "NAME" );String population = resultSet.getString( "POPULATION" );System.out.println( "NAME: " + name );System.out.println( "POPULATION: " + population );
}
其输出为(取决于数据库状态):
NAME: GERMANY
POPULATION: 90Mill
NAME: SPAIN
POPULATION: 45Mill
NAME: USA
POPULATION: 200Mill
删除语句。 最后,JDBC支持删除行以及删除表和其他SQL元素。 这是一个片段,显示删除具有特定条件的所有行(在这种情况下,名称必须为“ JAPAN”):
System.out.println( "Deleting rows for JAPAN..." );
String sql = "DELETE FROM COUNTRIES WHERE NAME='JAPAN'";
PreparedStatement deleteStmt = connect.prepareStatement( sql );// delete statement using executeUpdate
int numberRows = deleteStmt.executeUpdate( sql );System.out.println( numberRows + " rows deleted..." );
Delete语句返回受影响的行数,在这种情况下,输出将是(取决于数据库状态):
Deleting rows for JAPAN...
0 rows deleted...
这些例子都是非常简单的例子。 它们是出于学习目的而编写的,但是您可以想象,只需更改传递给executeQuery()
或executeUpdate()
方法的参数,就可以执行更复杂SQL查询。
12. Java 8
Java 8不包含与JDBC或JDBC框架相关的任何重大更改。 但是,在使用JDBC时,可以应用Java 8的多种功能,效果非常好。 我们将展示其中的一些。 例如,有可能以与过去非常不同的方式执行选择查询。 这是一个没有Java 8功能的情况下的示例,它与本文中所有示例中的操作大致相同:
// we always need to write this code
System.out.println( "using Java 7" );
// connection to JDBC using mysql driver
Class.forName( "com.mysql.jdbc.Driver" );
Connection connect = DriverManager.getConnection( "jdbc:mysql://localhost/countries?"+ "user=root&password=root" );// select query
PreparedStatement statement = connect.prepareStatement( "select * from COUNTRIES" );
ResultSet resultSet = statement.executeQuery();// iterating results
while( resultSet.next() )
{// access via nameObject name = resultSet.getObject( 1 );Object population = resultSet.getObject( 2 );System.out.println( "Name: " + name );System.out.println( "Population: " + population );
}// close resources, in case of exception resources are not properly cleared
resultSet.close();
statement.close();
connect.close();
这是一个使用Lambdas的相同版本。
// select method is called and lambda expression is provided, this expression will be used
// in the handle method of the functional interface
select( connect, "select * from COUNTRIES", ( resultSet ) -> {System.out.println( resultSet.getObject( 1 ) );System.out.println( resultSet.getObject( 2 ) );
} );
上面显示的这段代码包含一个select方法调用,其中第一个参数是Connection对象,第二个参数是SQL查询,第三个参数是Lambda表达式。 该Lambda表达式接收一个参数( ResultSet
实例)并打印出其前两个属性,但是使用Lambda表达式主体中的该结果集可以完成任何操作。 这是select()
方法的实现:
public static void select( Connection connect, String sql, ResultSetHandler handler ) throws SQLException{PreparedStatement statement = connect.prepareStatement( sql );try (ResultSet rs = statement.executeQuery()){while( rs.next() ){handler.handle( rs );}}}
和功能接口ResultSetHandler
:
@FunctionalInterface
public interface ResultSetHandler
{/*** This method will be executed by the lambda expression* * @param resultSet* @throws SQLException*/public void handle( ResultSet resultSet ) throws SQLException;}
我们在这里可以看到,使用某些Java 8新功能时,代码更加清晰,而且大大减少了(或没有减少)。
13.基于JDBC构建的Sql库
几个著名的Java库使用JDBC来构建它们的API。 在本节中,我们将列出其中一些:
- HSQLDB(超级SQL数据库)是一种关系数据库管理系统,可提供内存和持久性存储。 它具有JDBC驱动程序(如某些示例所示)。 它具有非持久性功能,并且几乎支持所有SQL核心功能,因此对于测试目的非常有用。 有关更多信息,请访问http://hsqldb.org/
- DBUnit是JUnit的扩展。 当涉及数据库时,它对于单元测试非常有用。 该框架负责测试之间的数据库状态,并在测试时抽象出几个数据库属性。 要下载源代码和更多文档,请访问http://www.dbunit.org
- DBUtils是一个Apache Commons库,旨在简化JDBC的使用。 该库包含的一些功能包括:清理资源,减少代码量,更轻松和自动填充结果集。 该库小巧,透明且快速,应由希望直接使用JDBC的开发人员使用。 使用此库需要Java 1.6或更高版本。 有关更多文档,请访问http://commons.apache.org/proper/commons-dbutils/
- Spring Data还包含与JDBC相关的模块。 它被称为Spring Data JDBC Extensions。 它提供了对JDBC最常用功能的支持。 它提供了用于处理Oracle数据库的特殊功能。 如果您想了解有关此库的更多信息,请访问http://projects.spring.io/spring-data-jdbc-ext/
- JOOQ是使用JDBC的公司数据仓库中非常有趣的框架。 它从SQL数据库生成Java代码,并提供API以建立JDBC连接,查询数据并以简单的方式处理结果。 有关更多信息,请访问其git hub帐户: https : //github.com/jOOQ/jOOL 。
14.单元测试
当涉及到单元测试和数据库时,总是存在几个问题:
- 我们使用什么环境进行测试?
- 我们是否用真实数据进行测试?
- 还是我们使用合成的生成数据?
- 如果没有适当的凭据,我们如何测试数据库?
几个库可以帮助我们完成这些任务。 在本章中,我们将列出其中一些并提供一些有用的链接,在这些链接中可以找到更多信息:
- DBUnit:如前所述,DBUnit是一个与Junit协作的测试框架。 有关更多信息,请访问http://dbunit.org
- TestNG:此测试框架涵盖许多测试场景,例如单元测试,功能测试,集成测试等。它基于注释。 有关此框架的更多信息,请访问其网站: http : //testng.org/doc/index.html
- JOOQ。 该框架提供了JDBC模拟和测试功能。 它是非常有据可查的,易于使用。 有关更多信息,请访问http://jooq.org
15.总结
JDBC(Java数据库连接性)是用于Java与大量数据库和数据源(从基于SQL的数据库到Excel电子表格)之间的数据库连接性的标准API。 在本教程中,我们试图解释JDBC体系结构以及如何使用它。 我们列出了JDBC使用的主要组件,并且列出了一些用于广泛使用的数据库(例如MySql)的驱动程序。
要记住的最重要的几点是:
- 驱动程序是使Java应用程序能够与数据库一起使用的组件。 JDBC需要每个特定数据库的驱动程序。 可以在http://www.oracle.com/technetwork/java/index-136695.html上找到JDBC可用驱动程序的列表。
- 每次都将SQL语句直接发送到数据库服务器。 JDBC包含一种称为
PreparedStatement
的机制,该机制具有预定的执行路径,该机制可提高效率并更好地利用资源。 - 结果集是用于查询中的行的表示形式。
- 存储过程是组合在一起的一组SQL语句,可以按名称调用它们,而无需分别调用它们。
- 事务是一组SQL语句。 当调用
commit()
或rollback()
时,事务结束。 这种分组允许不同的并行工作。 - CRUD命令是
create
,read
,update
和delete
命令。 JDBC提供了执行这些命令的机制。
本教程包含一些与Java 8有关的与JDBC有关的新可能性的信息,例如JOOQ。 我们还提到了一些使用JDBC实现的重要库,例如Spring-Data或Apache DBUtils。
16.下载JDBC教程源代码
您可以在此处下载本教程的完整源代码: jdbc_ultimate_tutorial 。
17.链接
除了本文所指向的所有链接和资源之外,如果您想了解有关JDBC API及其功能和机制的更多信息,可以在Oracle官方网站上找到最新的最佳信息源:
- http://docs.oracle.com/javase/8/docs/api/javax/sql/package-summary.html
- http://docs.oracle.com/javase/8/docs/api/javax/sql/package-summary.html
翻译自: https://www.javacodegeeks.com/2015/02/jdbc-tutorial.html
jdbc pdf