使用命名参数的CallableStatement处理

    技术2024-04-16  105

    简介:JDBC中的语句处理

    在JDBC应用程序中,JDBC语句对象用于将SQL语句发送到数据库服务器。 语句对象与连接相关联,它是处理应用程序与数据库服务器之间通信的语句对象。

    JDBC提供三种类型的语句对象:

    一般性发言 准备好的声明 可赎回声明

    语句对象与连接关联,因此您应该建立数据库连接以创建语句对象。

    建立连接

    下面清单1中的代码示例说明了如何创建连接:

    清单1.加载Informix驱动程序并创建连接的示例代码
    Connection con = null; try { Class.forName("com.informix.jdbc.IfxDriver"); String url = "jdbc:informix-sqli://hostname:port_number/dbname: informixserver=servername; userid=userid;password=pwd;"; con = DriverManager.getConnection(url); }

    现在让我们逐一检查三种语句对象。

    一般声明

    连接的createStatement方法用于创建此语句。 它专门用于不需要传递任何值作为参数SQL语句。

    清单2.示例代码说明了create语句
    Statement stmt = con.createStatement(); cmd = "create database testDB;"; rc = stmt.executeUpdate(cmd); stmt.close();

    准备好的陈述

    准备好的语句是语句类的子类。 主要区别在于,与语句类不同,预处理语句仅被编译和优化一次,并且可以通过设置不同的参数值来多次使用。 因此,当您想多次执行一条语句时,准备语句是一个更好的选择。 由于采用编译形式,因此减少了执行时间。 因此,好处是预处理语句不仅包含SQL语句,而且还包含预编译SQL语句。 另一个区别是,SQL语句在创建时即被赋予准备好的语句。

    清单3.示例代码说明准备好的语句
    PreparedStatement pstmt = con.prepareStatement("UPDATE tab1 "+ "set col1 = ? where key = 1"); pstmt.setShort(1, (short)2); int rowcount = pstmt.executeUpdate();

    在这里,相同的准备好的语句可以用于col1的另一组值。 设置clearParameters参数后,它将保留该值,直到将其重置或clearParameters为止。 此功能使准备好的语句可用于批处理INSERT / UPDATE 。

    批量更新

    批处理更新功能提高了具有多个值设置的多次执行的单个语句的性能。 这允许将多个更新操作提交到数据源以立即进行处理。 语句对象也可以使用批处理更新。 但是,语句对象将不同SQL语句提交给批处理,而准备好的语句将一组参数提交给批处理。

    清单4显示了如何将批处理插入与预准备语句一起使用:

    清单4.演示批处理更新的示例代码
    PreparedStatement pst = conn.prepareStatement("insert into tab1 values (?)"); for loop.... { pst.setInt (1, i); pst.addBatch(); } pst.executeBatch();

    addBatch方法将语句添加到缓存中,并使用executeBatch()方法刷新到数据库。 因此,它只保存一次(使用预准备语句),从而节省了语句的编译/优化工作,并且一次发送批处理插入内容,还节省了往返服务器的时间。

    可赎回声明

    这是调用SQL语句的第三种方法,它提供了一种从Java™程序调用服务器上存储过程的方法。 还需要首先准备可调用语句,然后使用set方法设置其参数。 可以通过以下两种方式之一设置参数值:

    顺序位置 命名参数

    顺序位置是通过参数在CallableStatements中的位置来设置参数的传统方法。 但是,命名参数提供了灵活性,可以按名称(而不是按顺序位置)设置参数。 在例程的一次调用中,必须通过名称或顺序格式指定CallableStatement的参数。 例如,如果为一个参数命名一个参数,则必须为所有参数使用参数名称。

    命名参数对于调用具有许多参数的存储过程特别有用,其中一些参数具有默认值。 如果该过程是唯一的,则可以省略具有默认值的参数,并以任意顺序输入参数。 命名参数使应用程序更强大,因此即使存储过程中参数的顺序发生了变化,您也无需更改应用程序。

    JDBC驱动程序提供DatabaseMetaData.supportsNamedParameters()方法来确定驱动程序和RDMS支持的CallableStatement中的命名参数。 如果支持命名参数,则系统返回true。 例如:

    清单5. supportNamedParameters()的用法
    Connection myConn = . . . // connection to the RDBMS for Database DatabaseMetaData dbmd = myConn.getMetaData(); if (dbmd.supportsNamedParameters() == true) { System.out.println("NAMED PARAMETERS FOR CALLABLE" + "STATEMENTS IS SUPPORTED"); }

    检索存储过程的参数名称

    可以使用DatabaseMetaData getprocedureColumns检索存储过程的参数名称,如清单6所示:

    清单6. getProcedureColumn()方法的用法
    Connection myConn = . . . // connection to the RDBMS for Database . . DatabaseMetaData dbmd = myConn.getMetaData(); ResultSet rs = dbmd.getProcedureColumns( "myDB", schemaPattern, procedureNamePattern, columnNamePattern); rs.next() { String parameterName = rs.getString(4); - - - or - - - String parameterName = rs.getString("COLUMN_NAME"); - - - System.out.println("Column Name: " + parameterName);

    将显示与getProcedureColumns()方法的参数匹配的所有列的名称。

    清单7显示了具名参数用于CallableStatements的用法。

    创建一个存储过程

    清单7.可调用OUT参数的用法
    create procedure createProductDef(productname varchar(64), productdesc varchar(64), listprice float, minprice float, out prod_id float); . . . let prod_id="value for prod_id"; end procedure;

    清单8中的Java代码首先创建带有五个参数的CallableStatement,这些参数对应于存储过程。 JDBC调用括号内的问号字符(?)指代参数。 设置或注册所有参数。 使用cstmt.setString(“ arg”,name)格式命名参数; ,其中arg是相应存储过程中参数的名称。 您不需要以与存储过程中的参数相同的顺序来命名参数。

    清单8.可调用命名参数的用法
    String sqlCall = "{call CreateProductDef(?,?,?,?,?)}"; CallableStatement cstmt = conn.prepareCall(sqlCall); cstmt.setString("productname", name); // Set Product Name. cstmt.setString("productdesc", desc); // Set Product Description. cstmt.setFloat("listprice", listprice); // Set Product ListPrice. cstmt.setFloat("minprice", minprice); // Set Product MinPrice. // Register out parameter which should return the product is created. cstmt.registerOutParameter("prod_id", Types.FLOAT); // Execute the call. cstmt.execute(); // Get the value of the id from the OUT parameter: prod_id float id = cstmt.getFloat("prod_id");

    如果CallableStatement中的参数数量小于存储过程中的参数数量,则其余参数必须具有默认值。 您不需要为具有默认值的参数设置值,因为服务器会自动使用默认值。 例如,如果存储过程有10个参数,其中四个具有非默认值,六个具有默认值,则CallableStatement中必须至少有四个问号。 或者,您可以使用五个,六个或最多十个问号。 在以下唯一的存储过程中,参数listprice和minprice具有默认值:

    清单9.使用带有默认值的参数创建一个过程
    create procedure createProductDef(productname varchar(64), productdesc varchar(64), listprice float default 100.00, minprice float default 90.00, out prod_id float); . . . let prod_id = value for prod_id; end procedure;

    下面的清单10中的Java代码使用比存储过程中的参数更少的参数来调用存储过程(四个参数代表五个参数)。 由于listprice具有默认值,因此可以从CallableStatement中将其省略。

    清单10.默认参数的用法
    String sqlCall = "{call CreateProductDef(?,?,?,?)}"; // 4 params for 5 args CallableStatement cstmt = conn.prepareCall(sqlCall); cstmt.setString("productname", name); // Set Product Name. cstmt.setString("productdesc", desc); // Set Product Description. cstmt.setFloat("minprice", minprice); // Set Product MinPrice. // Register out parameter which should return the product id created. cstmt.registerOutParameter("prod_id", Types.FLOAT); // Execute the call. cstmt.execute(); // Get the value of the id from the OUT parameter: prod_id float id = cstmt.getFloat("prod_id");

    如果可调用语句包含OUT或INOUT参数,那么你需要注册使用这些参数registerOutParameter CallableStatement中的。 清单11使用out参数prod_id与OUT参数一起创建存储过程。 同样,可以使用关键字INOUT创建INOUT参数。

    清单11. INOUT和OUT参数的用法
    create procedure createProductDef(productname varchar(64), productdesc varchar(64), inout listprice float default 100.00, minprice float default 90.00, out prod_id float);

    清单12使用CallableStatements的registerOutparameter方法注册CallableStatement的out参数。

    清单12.用CallableStatement注册OUT参数
    cstmt.registerOutParameter("prod_id", Types.FLOAT);

    清单13将所有语句与命名参数功能的功能合并在一起:

    清单13.用于命名参数功能的演示程序
    package Callable; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.sql.Types; public class out1 { static Connection conn; public static void main(String[] args) { getConnect(); System.out.println("Connection Established"); createProc(); runthis(); System.out.println("\n=============Finished============="); System.exit(0); } private static void getConnect() { try { Class.forName("com.informix.jdbc.IfxDriver"); String url = "jdbc:informix-sqli://host name or ip :porn number/database name:informixserver=dbservername;"; System.out.println("URL: "+url); conn = DriverManager.getConnection(url); } catch( Exception e ) { e.printStackTrace(); System.exit(1); } } private static void createProc() { String str=null; Statement stmt = null; try { stmt = conn.createStatement(); } catch (SQLException e2) { e2.printStackTrace(); } str="drop function c_out_proc"; try { stmt.executeUpdate (str); } catch (SQLException e1) { } str = "create function c_out_proc ( i int, OUT d varchar(20) ) \n" + "returning float; \n" + "define f float; \n" + "let d= \"Hello OUT\"; \n" + "let f=i*2; \n" + "return f; \n" + "end function; \n"; try { stmt.executeUpdate (str); System.out.println("Function created \n"); } catch (SQLException e) { System.out.println("Error on creating function: " + e.toString()); System.exit(1); } } private static void runthis() { CallableStatement cstmt = null; String command = "{? = call c_out_proc(?, ?)} "; try { cstmt = conn.prepareCall (command); cstmt.setInt(1, 2); cstmt.registerOutParameter(2, Types.VARCHAR); ResultSet rs = cstmt.executeQuery(); if (rs == null) { System.out.println("rs is null *** this is BAD."); System.exit(0); } else { rs.next(); System.out.println(rs.getFloat(1)); System.out.println(cstmt.getString(2)); } } catch (SQLException e) { e.printStackTrace(); } } }

    结论

    本文首先介绍了IDS JDBC驱动程序可用的各种语句类型。 然后,它描述了命名参数功能,并讨论了如何在CallableStatement中使用该功能。

    本文最后列出了一个使用IDS 11服务器使用命名参数功能的演示程序。 现在,您已经拥有了可以自己尝试的工具,并可以看到命名参数功能的好处。


    翻译自: https://www.ibm.com/developerworks/data/library/techarticle/dm-0802tiwary/index.html

    Processed: 0.013, SQL: 12