JDBC的Statement对象

以下内容引用自http://wiki.jikexueyuan.com/project/jdbc/statements.html

一旦获得了数据库的连接,就可以和数据库进行交互。JDBC的Statement,CallableStatement和PreparedStatement接口定义的方法和属性,可以发送SQL命令或PL/SQL命令到数据库,并从数据库接收数据。

在数据库中,它们还定义了帮助Java和SQL数据类型之间转换数据差异的方法。

下表提供了每个接口的用途概要,根据实际目的决定使用哪个接口。

接口推荐使用
Statement 可以正常访问数据库,适用于运行静态SQL语句。 Statement接口不接受参数。
PreparedStatement 计划多次使用SQL语句, PreparedStatement接口运行时接受输入的参数。
CallableStatement 适用于当要访问数据库存储过程的时候, CallableStatement接口运行时也接受输入的参数。

一、Statement对象

1、创建Statement对象

在准备使用Statement对象执行SQL语句之前,需要使用Connection对象的createStatement()方法创建一个,如下面的示例所示:

Statement stmt = null;
try {
   stmt = conn.createStatement( );
   . . .
}
catch (SQLException e) {
   . . .
}
finally {
   . . .
}

当创建了一个Statement对象之后,可以用它的三个执行方法的任一方法来执行SQL语句。

  • boolean execute(String SQL) : 如果ResultSet对象可以被检索,则返回的布尔值为true,否则返回false 。当需要使用真正的动态SQL时,可以使用这个方法来执行SQL DDL语句。

  • int executeUpdate(String SQL) : 返回执行SQL语句影响的行的数目。使用该方法来执行SQL语句,是希望得到一些受影响的行的数目,例如,INSERT,UPDATE或DELETE语句。

  • ResultSet executeQuery(String SQL) : 返回一个ResultSet对象。当希望得到一个结果集时使用该方法,就像使用一个SELECT语句。

2、关闭Statement对象

正如关闭一个Connection对象来节约数据库资源,出于同样的原因也应该关闭Statement对象。

简单的调用close()方法就可以完成这项工作。如果关闭了Connection对象,那么它也会关闭Statement对象。然而,应该始终明确关闭Statement对象,以确保真正的清除。

Statement stmt = null;
try {
   stmt = conn.createStatement( );
   . . .
}
catch (SQLException e) {
   . . .
}
finally {
   stmt.close();
}

示例:

//STEP 1. Import required packages
import java.sql.*;

public class FirstExample {
    // JDBC driver name and database URL
    static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
    static final String DB_URL = "jdbc:mysql://localhost/Test?serverTimezone=UTC";

    // Database credentials
    static final String USER = "root";
    static final String PASS = "root";

    public static void main(String[] args) {
        Connection conn = null;
        Statement 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...");
            stmt = conn.createStatement();
            String sql;
            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 FirstExample

这将产生如下所示结果:

二、PreparedStatement对象

PreparedStatement接口扩展了Statement接口,它用一个常用的Statement对象增加几个高级功能。

这个Statement对象可以提供灵活多变的动态参数。

1、创建PreparedStatement对象

PreparedStatement pstmt = null;
try {
   String SQL = "Update Employees SET age = ? WHERE id = ?";
   pstmt = conn.prepareStatement(SQL);
   . . .
}
catch (SQLException e) {
   . . .
}
finally {
   . . .
}

JDBC中所有的参数都被用?符号表示,这是已知的参数标记。在执行SQL语句之前,必须赋予每一个参数确切的数值。

setXXX()方法将值绑定到参数,其中XXX表示希望绑定到输入参数的Java数据类型。如果忘了赋予值,将收到一个SQLException。

每个参数标记映射它的序号位置。第一标记表示位置1,下一个位置为2等等。这种方法不同于Java数组索引,它是从0开始的。

所有的Statement对象的方法都与数据库交互,(a)execute(),(b)executeQuery(),及(c)executeUpdate()也能被PreparedStatement对象引用。然而,这些方法被SQL语句修改后是可以输入参数的。

2、关闭PreparedStatement对象

正如关闭一个Statement对象,出于同样的原因,也应该关闭PreparedStatement对象。

简单的调用close()方法可以完成这项工作。如果关闭了Connection对象,那么它也会关闭PreparedStatement对象。然而,应该始终明确关闭PreparedStatement对象,以确保真正的清除。

PreparedStatement pstmt = null;
try {
   String SQL = "Update Employees SET age = ? WHERE id = ?";
   pstmt = conn.prepareStatement(SQL);
   . . .
}
catch (SQLException e) {
   . . .
}
finally {
   pstmt.close();
}

示例:

//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/Test?serverTimezone=UTC";

    // Database credentials
    static final String USER = "root";
    static final String PASS = "root";

    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

这将产生如下所示结果:

三、CallableStatement对象

正如一个Connection对象可以创建Statement对象和PreparedStatement对象,它也可以创建被用来执行调用数据库存储过程的CallableStatement对象。

1、创建CallableStatement对象

假如需要执行以下的Oracle存储过程:

CREATE OR REPLACE PROCEDURE getEmpName 
   (EMP_ID IN NUMBER, EMP_FIRST OUT VARCHAR) AS
BEGIN
   SELECT first INTO EMP_FIRST
   FROM Employees
   WHERE ID = EMP_ID;
END;

注意:上面的存储过程已经写入到Oracle数据库中,但正在使用MySQL数据库,那么可以在MySQL的EMP数据库中创建相同的存储过程。

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 ;

三种类型的参数有:IN,OUT和INOUT。PreparedStatement对象只使用IN参数。CallableStatement对象可以使用所有的三个参数。

这里是每个参数的定义:

参数描述
IN 在SQL语句创建的时候该参数是未知的。可以用setXXX()方法将值绑定到IN参数中。
OUT 该参数由SQL语句的返回值提供。可以用getXXX()方法获取OUT参数的值。
INOUT 该参数同时提供输入输出的值。可以用setXXX()方法将值绑定参数,并且用getXXX()方法获取值。

下面的代码片段展示了基于存储过程如何使用Connection.prepareCall()方法来实例化CallableStatement对象。

CallableStatement cstmt = null;
try {
   String SQL = "{call getEmpName (?, ?)}";
   cstmt = conn.prepareCall(SQL);
   . . .
}
catch (SQLException e) {
   . . .
}
finally {
   . . .
}

SQL的String变量使用参数占位符表示存储过程。

使用CallableStatement对象就像使用PreparedStatement对象。必须在执行该语句之前将值绑定到所有的参数,否则将收到一个SQL异常。

如果有IN参数,只要使用适用于PreparedStatement对象相同的规则和技巧;使用setXXX()方法绑定对应的Java数据类型。

当使用OUT和INOUT参数时,就必须使用额外的CallableStatement方法-registerOutParameter()。 registerOutParameter()方法绑定JDBC数据类型,该数据是存储过程返回的值。

一旦调用存储过程,可以用适当的getXXX()方法来获取OUT参数的值。这个方法将检索到的SQL类型映射成Java数据类型。

2、关闭CallableStatement对象

正如关闭其它的Statement对象,出于同样的原因,也应该关闭PreparedStatement对象。

简单的调用close()方法可以完成这项工作。如果关闭了Connection对象,那么它也会关闭CallableStatement对象。然而,应该始终明确关闭CallableStatement对象,以确保真正的清除。

CallableStatement cstmt = null;
try {
   String SQL = "{call getEmpName (?, ?)}";
   cstmt = conn.prepareCall(SQL);
   . . .
}
catch (SQLException e) {
   . . .
}
finally {
   cstmt.close();
}

示例:

创建存储过程:

DELIMITER $$

DROP PROCEDURE IF EXISTS `Test`.`getEmpName` $$
CREATE PROCEDURE `Test`.`getEmpName` 
   (IN EMP_ID INT, OUT EMP_FIRST VARCHAR(255))
BEGIN
   SELECT first INTO EMP_FIRST
   FROM Employees
   WHERE ID = EMP_ID;
END $$

DELIMITER ;

代码:

//STEP 1. Import required packages
import java.sql.*;

public class JDBCExample2 {
    // JDBC driver name and database URL
    static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
    static final String DB_URL = "jdbc:mysql://localhost/Test?serverTimezone=UTC";

    // Database credentials
    static final String USER = "root";
    static final String PASS = "root";

    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

这将产生如下所示结果:

测试工程:https://github.com/easonjim/5_java_example/tree/master/jdbcbasics/test3

原文地址:https://www.cnblogs.com/EasonJim/p/6994014.html