以下是这使得使用PreparedStatement以及打开和关闭statments的例子:
基于对环境和数据库安装在前面的章节中进行这个范例程式码已被写入。
复制下面的例子中JDBCExample.java,编译并运行,如下所示:
//STEP 1. Import required packages import java.sql.*; public class JDBCExample { // JDBC driver name and database URL static final String JDBC_DRIVER = "com.mysql.jdbc.Driver"; static final String DB_URL = "jdbc:mysql://localhost/EMP"; // Database credentials static final String USER = "username"; static final String PASS = "password"; public static void main(String[] args) { Connection conn = null; PreparedStatement stmt = null; try{ //STEP 2: Register JDBC driver Class.forName("com.mysql.jdbc.Driver"); //STEP 3: Open a connection System.out.println("Connecting to database..."); conn = DriverManager.getConnection(DB_URL,USER,PASS); //STEP 4: Execute a query System.out.println("Creating statement..."); String sql = "UPDATE Employees set age=? WHERE id=?"; stmt = conn.prepareStatement(sql); //Bind values into the parameters. stmt.setInt(1, 35); // This would set age stmt.setInt(2, 102); // This would set ID // Let us update age of the record with ID = 102; int rows = stmt.executeUpdate(); System.out.println("Rows impacted : " + rows ); // Let us select all the records and display them. sql = "SELECT id, first, last, age FROM Employees"; ResultSet rs = stmt.executeQuery(sql); //STEP 5: Extract data from result set while(rs.next()){ //Retrieve by column name int id = rs.getInt("id"); int age = rs.getInt("age"); String first = rs.getString("first"); String last = rs.getString("last"); //Display values System.out.print("ID: " + id); System.out.print(", Age: " + age); System.out.print(", First: " + first); System.out.println(", Last: " + last); } //STEP 6: Clean-up environment rs.close(); stmt.close(); conn.close(); }catch(SQLException se){ //Handle errors for JDBC se.printStackTrace(); }catch(Exception e){ //Handle errors for Class.forName e.printStackTrace(); }finally{ //finally block used to close resources try{ if(stmt!=null) stmt.close(); }catch(SQLException se2){ }// nothing we can do try{ if(conn!=null) conn.close(); }catch(SQLException se){ se.printStackTrace(); }//end finally try }//end try System.out.println("Goodbye!"); }//end main }//end JDBCExample
现在来编译上面的例子如下:
C:>javac JDBCExample.java C:>
当运行JDBCExample,它会产生以下结果:
C:>java JDBCExample Connecting to database... Creating statement... Rows impacted : 1 ID: 100, Age: 18, First: Zara, Last: Ali ID: 101, Age: 25, First: Mahnaz, Last: Fatma ID: 102, Age: 35, First: Zaid, Last: Khan ID: 103, Age: 30, First: Sumit, Last: Mittal Goodbye! C:>
下面是利用CallableStatement连同下列getEmpName()的MySQL存储过程的例子:
请确定已经在EMP数据库中创建该存储过程。可以使用MySQL查询浏览器来完成它。
DELIMITER $$ DROP PROCEDURE IF EXISTS `EMP`.`getEmpName` $$ CREATE PROCEDURE `EMP`.`getEmpName` (IN EMP_ID INT, OUT EMP_FIRST VARCHAR(255)) BEGIN SELECT first INTO EMP_FIRST FROM Employees WHERE ID = EMP_ID; END $$ DELIMITER ;
基于对环境和数据库安装在前面的章节中进行,这个范例程式码已被写入。
复制下面的例子中JDBCExample.java,编译并运行,如下所示:
//STEP 1. Import required packages import java.sql.*; public class JDBCExample { // JDBC driver name and database URL static final String JDBC_DRIVER = "com.mysql.jdbc.Driver"; static final String DB_URL = "jdbc:mysql://localhost/EMP"; // Database credentials static final String USER = "username"; static final String PASS = "password"; public static void main(String[] args) { Connection conn = null; CallableStatement stmt = null; try{ //STEP 2: Register JDBC driver Class.forName("com.mysql.jdbc.Driver"); //STEP 3: Open a connection System.out.println("Connecting to database..."); conn = DriverManager.getConnection(DB_URL,USER,PASS); //STEP 4: Execute a query System.out.println("Creating statement..."); String sql = "{call getEmpName (?, ?)}"; stmt = conn.prepareCall(sql); //Bind IN parameter first, then bind OUT parameter int empID = 102; stmt.setInt(1, empID); // This would set ID as 102 // Because second parameter is OUT so register it stmt.registerOutParameter(2, java.sql.Types.VARCHAR); //Use execute method to run stored procedure. System.out.println("Executing stored procedure..." ); stmt.execute(); //Retrieve employee name with getXXX method String empName = stmt.getString(2); System.out.println("Emp Name with ID:" + empID + " is " + empName); stmt.close(); conn.close(); }catch(SQLException se){ //Handle errors for JDBC se.printStackTrace(); }catch(Exception e){ //Handle errors for Class.forName e.printStackTrace(); }finally{ //finally block used to close resources try{ if(stmt!=null) stmt.close(); }catch(SQLException se2){ }// nothing we can do try{ if(conn!=null) conn.close(); }catch(SQLException se){ se.printStackTrace(); }//end finally try }//end try System.out.println("Goodbye!"); }//end main }//end JDBCExample
现在编译上面的例子如下:
C:>javac JDBCExample.java C:>
当运行JDBCExample,它会产生以下结果:
C:>java JDBCExample Connecting to database... Creating statement... Executing stored procedure... Emp Name with ID:102 is Zaid Goodbye! C:>
从数据库查询读取数据的SQL语句返回的结果集的数据。 SELECT语句的标准方法来选择从一个数据库中的行并查来在一个结果集。java.sql.ResultSet接口表示一个数据库查询的结果集。
一个ResultSet对象维护一个游标指向当前行的结果集。术语“结果集”是指包含在ResultSet对象中的行和列的数据。
ResultSet接口的方法可分为三类:
-
导航方法:用于移动光标.
-
获取方法:用于查看当前行的光标所指向的列中的数据。
-
更新方法:用于更新当前行的列中的数据。这些更新然后可以在基础数据库中,以及更新。
将光标移动基于ResultSet的属性。所创建生成ResultSet相应的声明时,这些属性被指定。
JDBC提供下列连接方法来创建所需的ResultSet语句:
-
createStatement(int RSType, int RSConcurrency);
-
prepareStatement(String SQL, int RSType, int RSConcurrency);
-
prepareCall(String sql, int RSType, int RSConcurrency);
第一个参数表示ResultSet对象的类型,第二个参数是2的ResultSet常量,用于指定一个结果集是否为只读或可更新之一。
ResultSet的类型:
可能的RSType如下,如果不指定ResultSet类型,将自动获得一个是TYPE_FORWARD_ONLY。
Type | 描述 |
---|---|
ResultSet.TYPE_FORWARD_ONLY | 游标只能向前移动的结果集。 |
ResultSet.TYPE_SCROLL_INSENSITIVE | 游标可以向前和向后滚动,结果集不是别人向创建结果集后发生的数据库更改敏感。 |
ResultSet.TYPE_SCROLL_SENSITIVE. | 游标可以向前和向后滚动,结果集是别人向创建结果集后发生的数据库更改敏感。 |
并发性的ResultSet:
可能的RSConcurrency如下,如果不指定任何并发类型,将自动获得一个为CONCUR_READ_ONLY。
并发 | 描述 |
---|---|
ResultSet.CONCUR_READ_ONLY | 创建结果集只读。这是默认的 |
ResultSet.CONCUR_UPDATABLE | 创建一个可更新的结果集。 |
到目前为止已写入的例子可以写成如下的初始化一个Statement对象来创建一个只进,只读的ResultSet对象:
try { Statement stmt = conn.createStatement( ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); } catch(Exception ex) { .... } finally { .... }
导航结果集:
有几种方法在ResultSet接口涉及移动光标,包括:
S.N. | 方法 & 描述 |
---|---|
1 | public void beforeFirst() throws SQLException 将光标移动到正好位于第一行之前 |
2 | public void afterLast() throws SQLException 将光标移动到刚刚结束的最后一行 |
3 | public boolean first() throws SQLException 将光标移动到第一行 |
4 | public void last() throws SQLException 将光标移动到最后一行。 |
5 | public boolean absolute(int row) throws SQLException 将光标移动到指定的行 |
6 | public boolean relative(int row) throws SQLException 从它目前所指向向前或向后移动光标行的给定数量。 |
7 | public boolean previous() throws SQLException 将光标移动到上一行。上一行关闭的结果集此方法返回false |
8 | public boolean next() throws SQLException 将光标移动到下一行。如果没有更多的行结果集中的此方法返回false |
9 | public int getRow() throws SQLException 返回的行号,该光标指向的行. |
10 | public void moveToInsertRow() throws SQLException 将光标移动到一个特殊的行,可以用来插入新行插入到数据库中的结果集。当前光标位置被记住. |
11 | public void moveToCurrentRow() throws SQLException 移动光标返回到当前行,如果光标在当前插入行,否则,这个方法不执行任何操作 |
为了更好地理解,建议学习导航示例代码
查看结果集:
ResultSet接口中含有几十种用于获取当前行的数据的方法。
有一个get方法为每个可能的数据类型,并且每个get方法有两个版本:
-
即需要在一个列名。
-
即需要在列中索引。
例如,如果有兴趣查看的列包含一个整数,需要使用ResultSet调用getInt()方法之一:
S.N. | 方法 & 描述 |
---|---|
1 | public int getInt(String columnName) throws SQLException 返回整数的当前行中名为ColumnName列 |
2 | public int getInt(int columnIndex) throws SQLException 返回整数的当前行中指定列的索引。列索引从1开始,意味着一个行的第一列是1,行的第二列是2,依此类推。 |
与此类似的还有get方法在ResultSet接口为每个八个Java原始类型,以及常见的类型比如java.lang.String,java.lang.Object和java.net.URL
也有用于获取SQL数据类型java.sql.Date,java.sql.Time,java.sql.Timestamp,java.sql.Clob,java.sql.Blob中的方法。检查有关使用这些SQL数据类型的详细信息的文档。
为了更好地理解,建议学习 查看 - 示例代码.
更新的结果集:
ResultSet接口中包含的更新方法用于更新的结果集的数据的集合。
由于get方法,有两种更新方法为每种数据类型:
-
即需要在一个列名。
-
即需要在列中索引。
例如,要更新一个结果集的当前行的String列,可以使用下面的updateString()方法之一:
S.N. | 方法& 描述 |
---|---|
1 | public void updateString(int columnIndex, String s) throws SQLException 指定列中的字符串更改为s的值。 |
2 | public void updateString(String columnName, String s) throws SQLException 类似于前面的方法,不同之处在于由它的名称,而不是它的索引指定的列。 |
有更新方法八个原始数据类型,以及字符串,对象,URL,并在java.sql包中的SQL数据类型。
更新结果集中的行改变当前行的列中的ResultSet对象,而不是基础数据库中。要更新更改数据库中的一行,需要调用下面的方法之一。
S.N. | 方法 & 描述 |
---|---|
1 | public void updateRow() 通过更新数据库中相应的行更新当前行。 |
2 | public void deleteRow() 从数据库中删除当前行 |
3 | public void refreshRow() 刷新在结果集的数据,以反映最新变化在数据库中。 |
4 | public void cancelRowUpdates() 取消所做的当前行的任何更新。 |
5 | public void insertRow() 插入一行到数据库中。当光标指向插入行此方法只能被调用。 |
为了更好地理解,建议学习更新示例代码。
JDBC驱动程序将其发送到数据库之前的Java数据类型转换为相应的JDBC类型。它采用了默认的映射对于大多数数据类型。例如,一个Java整型转换为SQL INTEGER。创建默认映射提供的驱动程序之间的一致性。
下表总结了Java数据类型转换为当调用PreparedStatement中的setXXX()方法或CallableStatement对象或ResultSet.updateXXX()方法的默认JDBC数据类型。
SQL | JDBC/Java | setXXX | updateXXX |
---|---|---|---|
VARCHAR | java.lang.String | setString | updateString |
CHAR | java.lang.String | setString | updateString |
LONGVARCHAR | java.lang.String | setString | updateString |
BIT | boolean | setBoolean | updateBoolean |
NUMERIC | java.math.BigDecimal | setBigDecimal | updateBigDecimal |
TINYINT | byte | setByte | updateByte |
SMALLINT | short | setShort | updateShort |
INTEGER | int | setInt | updateInt |
BIGINT | long | setLong | updateLong |
REAL | float | setFloat | updateFloat |
FLOAT | float | setFloat | updateFloat |
DOUBLE | double | setDouble | updateDouble |
VARBINARY | byte[ ] | setBytes | updateBytes |
BINARY | byte[ ] | setBytes | updateBytes |
DATE | java.sql.Date | setDate | updateDate |
TIME | java.sql.Time | setTime | updateTime |
TIMESTAMP | java.sql.Timestamp | setTimestamp | updateTimestamp |
CLOB | java.sql.Clob | setClob | updateClob |
BLOB | java.sql.Blob | setBlob | updateBlob |
ARRAY | java.sql.Array | setARRAY | updateARRAY |
REF | java.sql.Ref | SetRef | updateRef |
STRUCT | java.sql.Struct | SetStruct | updateStruct |
JDBC3.0增强了对BLOB,CLOB,ARRAY和REF数据类型的支持。 ResultSet 对象现在有UPDATEBLOB(),updateCLOB(),updateArray(),和updateRef()方法,可以直接操作服务器上的相应数据。
setXXX()和updateXXX()方法能够将特定Java类型转换为特定的JDBC数据类型。该方法setObject()和updateObject(),能够将几乎任何Java类型映射到JDBC数据类型。
ResultSet对象为每个数据类型来检索列值对应的getXXX()方法。每个方法可用于与列名或由它的序数位置。
SQL | JDBC/Java | setXXX | getXXX |
---|---|---|---|
VARCHAR | java.lang.String | setString | getString |
CHAR | java.lang.String | setString | getString |
LONGVARCHAR | java.lang.String | setString | getString |
BIT | boolean | setBoolean | getBoolean |
NUMERIC | java.math.BigDecimal | setBigDecimal | getBigDecimal |
TINYINT | byte | setByte | getByte |
SMALLINT | short | setShort | getShort |
INTEGER | int | setInt | getInt |
BIGINT | long | setLong | getLong |
REAL | float | setFloat | getFloat |
FLOAT | float | setFloat | getFloat |
DOUBLE | double | setDouble | getDouble |
VARBINARY | byte[ ] | setBytes | getBytes |
BINARY | byte[ ] | setBytes | getBytes |
DATE | java.sql.Date | setDate | getDate |
TIME | java.sql.Time | setTime | getTime |
TIMESTAMP | java.sql.Timestamp | setTimestamp | getTimestamp |
CLOB | java.sql.Clob | setClob | getClob |
BLOB | java.sql.Blob | setBlob | getBlob |
ARRAY | java.sql.Array | setARRAY | getARRAY |
REF | java.sql.Ref | SetRef | getRef |
STRUCT | java.sql.Struct | SetStruct | getStruct |
日期和时间数据类型:
java.sql.Date中的类映射到SQL DATE类型,以及java.sql.Time和java.sql.Timestamp类映射分别到SQL TIME和SQL TIMESTAMP数据类型。
下面的例子显示了日期和时间格式类标准的Java日期和时间值相匹配的SQL数据类型的要求。
import java.sql.Date; import java.sql.Time; import java.sql.Timestamp; import java.util.*; public class SqlDateTime { public static void main(String[] args) { //Get standard date and time java.util.Date javaDate = new java.util.Date(); long javaTime = javaDate.getTime(); System.out.println("The Java Date is:" + javaDate.toString()); //Get and display SQL DATE java.sql.Date sqlDate = new java.sql.Date(javaTime); System.out.println("The SQL DATE is: " + sqlDate.toString()); //Get and display SQL TIME java.sql.Time sqlTime = new java.sql.Time(javaTime); System.out.println("The SQL TIME is: " + sqlTime.toString()); //Get and display SQL TIMESTAMP java.sql.Timestamp sqlTimestamp = new java.sql.Timestamp(javaTime); System.out.println("The SQL TIMESTAMP is: " + sqlTimestamp.toString()); }//end main }//end SqlDateTime
现在让我们来编译上面的例子如下:
C:>javac SqlDateTime.java C:>
当运行JDBCExample,它会产生以下结果:
C:>java SqlDateTime The Java Date is:Tue Aug 18 13:46:02 GMT+04:00 2009 The SQL DATE is: 2009-08-18 The SQL TIME is: 13:46:02 The SQL TIMESTAMP is: 2009-08-18 13:46:02.828 C:>
处理NULL值:
SQL使用NULL值和Java使用null是不同的概念。那么,如何处理Java中的SQL NULL值?有三种策略可以使用:
-
避免使用返回原始数据类型的getXXX()方法。
-
使用包装类的基本数据类型,并使用ResultSet对象的wasNull()方法来测试是否是收到getXXX()方法返回的值,包装类变量应该被设置为null。
-
使用原始数据类型和ResultSet对象的wasNull()方法来测试是否是收到getXXX()方法返回的值的原始变量应设置为你已经选择代表一个NULL可接受的值。
下面是一个例子来处理NULL值:
Statement stmt = conn.createStatement( ); String sql = "SELECT id, first, last, age FROM Employees"; ResultSet rs = stmt.executeQuery(sql); int id = rs.getInt(1); if( rs.wasNull( ) ) { id = 0; }