简介:JDBC 中的语句处理

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

JDBC 中有三种类型的语句对象:

  1. 常规语句(General statement)
  2. 预置语句(Prepared statement)
  3. 可调用语句(Callable statement)

语句对象与一个连接相关联,所以要创建一个语句对象,首先应该建立一个数据库连接。

创建连接

清单 1 中的代码示例演示了如何创建连接:

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

现在逐个考察这三种类型的语句对象。

 

回页首

常规语句

可以使用连接的 createStatement 方法创建这种语句。这种语句专用于不需要传递任何值作为参数的 SQL 语句。

清单 2. 演示创建语句的示例代码
  1. Statement stmt = con.createStatement();
  2. cmd = "create database testDB;";
  3. rc = stmt.executeUpdate(cmd);
  4. stmt.close();
 

回页首

预置语句

预置语句是 statement 类的一个子类。预置语句与 statement 类的主要区别在于,前者可以只编译和优化一次,然后通过设置不同的参数值多次使用。所以,如果想多次执行一条语句,那么预置语句是更好的选择。由于已经预先编译好,所以减少了执行时间。因此,预置语句的优点是,它不仅包含一条 SQL 语句,而且还是一条预先编译好的 SQL 语句。另一个区别是,SQL 语句在创建后就被提供给预置语句。

清单 3. 解释预置语句的示例代码
  1. PreparedStatement pstmt = con.prepareStatement("UPDATE tab1 "+
  2. "set col1 = ? where key = 1");
  3. pstmt.setShort(1, (short)2);
  4. int rowcount = pstmt.executeUpdate();

在此,同一个预置语句可用于不同的 col1 值。参数一旦设定,它的值将保持不变,直到被重新设置或者 clearParameters 被调用。这项特性使得预置语句可以用于批量处理 INSERT/UPDATE

批量更新

通过设置多个值,批量更新特性提高了需要多次执行的语句的性能。这样可以将多个更新操作提交到一个数据源并进行一次性处理。语句对象也可以使用批量更新。但语句对象提交不同的 SQL 语句进行批处理,而预置语句提交的是一组参数。

清单 4 显示了如何使用预置语句进行批量插入:

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

addBatch 方法将语句添加到一个缓存中,然后使用 executeBatch() 方法转储到数据库中。所以它节省了语句的编译/优化,因为它只编译一次(对于预置语句),而且还节省了与服务器之间的往返,因为它一次性发送了批量插入。

 

回页首

可调用语句

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

  1. 顺序位置
  2. 命名参数

顺序位置是传统的参数设置方式,它根据参数在 CallableStatements 中的位置来设置参数。但是,命名参数则提供了更大的灵活性,它允许根据名称而不是顺序位置来设置参数。在调用例程时,必须以名称或顺序格式指定 CallableStatement 的参数。例如,如果对一个参数使用了参数名称,那么对所有其他参数也必须使用参数名称。

在调用具有许多参数,而且其中一些参数有默认值的存储过程时,命名参数特别有用。如果过程是惟一的,那么可以省略有默认值的参数,并且可以按任意顺序输入参数。命名参数使应用程序更加健壮,所以,即使存储过程中参数的顺序发生了改变,也不必修改应用程序。

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

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

获取存储过程的参数名称

可以使用 DatabaseMetaData 的 getprocedureColumns 获取存储过程的参数名称,该方法的定义如清单 6 所示:

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

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

清单 7 显示了 CallableStatements 中的命名参数的使用。

创建存储过程

清单 7. 可调用 OUT 参数的使用
  1. create procedure createProductDef(productname varchar(64),
  2. productdesc varchar(64),
  3. listprice float,
  4. minprice float,
  5. out prod_id float);
  6. . . .
  7. let prod_id="value for prod_id";
  8. end procedure;

清单 8 中的 Java 代码首先创建一个有 5 个参数的 CallableStatement,这 5 个参数与存储过程中的参数相对应。JDBC 调用的括号中的问号字符 (?) 对参数进行引用。设置或注册所有的参数。使用格式 cstmt.setString("arg", name); 命名参数,其中 arg 是相应的存储过程中的参数名称。这里不需要按照存储过程中的参数顺序来命名参数。

清单 8. 可调用命名参数的使用
  1. String sqlCall = "{call CreateProductDef(?,?,?,?,?)}";
  2. CallableStatement cstmt = conn.prepareCall(sqlCall);
  3.  
  4. cstmt.setString("productname", name); // Set Product Name.
  5. cstmt.setString("productdesc", desc); // Set Product Description.
  6. cstmt.setFloat("listprice", listprice); // Set Product ListPrice.
  7. cstmt.setFloat("minprice", minprice); // Set Product MinPrice.
  8.  
  9. // Register out parameter which should return the product is created.
  10.  
  11. cstmt.registerOutParameter("prod_id", Types.FLOAT);
  12.  
  13. // Execute the call.
  14. cstmt.execute();
  15.  
  16. // Get the value of the id from the OUT parameter: prod_id
  17. float id = cstmt.getFloat("prod_id");

如果 CallableStatement 中的参数数量少于存储过程中的参数数量,那么剩下的参数必须有默认值。不需要为有默认值的参数设置值,因为服务器会自动使用默认值。例如,如果一个存储过程有 10 个参数,其中 4 个参数没有默认值,6 个参数有默认值,那么在 CallableStatement 中必须至少有 4 个问号。也可以使用 5 个、6 个或至多 10 个问号。在下面这个惟一的存储过程中,参数 listprice 和 minprice 有默认值:

清单 9. 创建包括具有默认值的参数的过程
  1. create procedure createProductDef(productname varchar(64),
  2. productdesc varchar(64),
  3. listprice float default 100.00,
  4. minprice float default 90.00,
  5. out prod_id float);
  6. . . .
  7. let prod_id = value for prod_id;
  8. end procedure;

清单 10 中的 Java 代码使用少于存储过程中参数数量的参数(存储过程中有 5 个参数,而代码中只使用 4 个参数)调用存储过程。由于listprice 有一个默认值,因此可以在 CallableStatement 中省略它。

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

如果可调用语句包含 OUT 或 INOUT 参数,那么需要使用 CallableStatement 的 registerOutParameter 注册这些参数。清单 11 使用 out 参数 prod_id 创建一个具有 OUT 参数的存储过程。类似地,可以使用关键字 INOUT 创建 INOUT 参数。

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

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

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

清单 13 将使用命名参数特性的所有语句合并在一起:

清单 13. 演示命名参数功能的程序
  1. package Callable;
  2.  
  3. import java.sql.CallableStatement;
  4. import java.sql.Connection;
  5. import java.sql.DriverManager;
  6. import java.sql.ResultSet;
  7. import java.sql.SQLException;
  8. import java.sql.Statement;
  9. import java.sql.Types;
  10. public class out1 {
  11. static Connection conn;
  12. public static void main(String[] args) {
  13. getConnect();
  14. System.out.println("Connection Established");
  15. createProc();
  16. runthis();
  17. System.out.println("\n=============Finished=============");
  18. System.exit(0);
  19. }
  20. private static void getConnect() {
  21. try
  22. {
  23. Class.forName("com.informix.jdbc.IfxDriver");
  24. String url = "jdbc:informix-sqli://host name or ip :porn number/database
  25. name:informixserver=dbservername;";
  26. System.out.println("URL: "+url);
  27. conn = DriverManager.getConnection(url);
  28. }
  29. catch( Exception e )
  30. {
  31. e.printStackTrace();
  32. System.exit(1);
  33. }
  34. }
  35. private static void createProc() {
  36. String str=null;
  37. Statement stmt = null;
  38. try
  39. {
  40. stmt = conn.createStatement();
  41. }
  42. catch (SQLException e2)
  43. {
  44. e2.printStackTrace();
  45. }
  46. str="drop function c_out_proc";
  47. try
  48. {
  49. stmt.executeUpdate (str);
  50. }
  51. catch (SQLException e1)
  52. { }
  53. str = "create function c_out_proc ( i int, OUT d varchar(20) ) \n" +
  54. "returning float; \n" +
  55. "define f float; \n" +
  56. "let d= \"Hello OUT\"; \n" +
  57. "let f=i*2; \n" +
  58. "return f; \n" +
  59. "end function; \n";
  60. try
  61. {
  62. stmt.executeUpdate (str);
  63. System.out.println("Function created \n");
  64. }
  65. catch (SQLException e)
  66. {
  67. System.out.println("Error on creating function: " + e.toString());
  68. System.exit(1);
  69. }
  70. }
  71. private static void runthis()
  72. {
  73. CallableStatement cstmt = null;
  74. String command = "{? = call c_out_proc(?, ?)} ";
  75. try
  76. {
  77. cstmt = conn.prepareCall (command);
  78. cstmt.setInt(1, 2);
  79. cstmt.registerOutParameter(2, Types.VARCHAR);
  80. ResultSet rs = cstmt.executeQuery();
  81. if (rs == null)
  82. {
  83. System.out.println("rs is null *** this is BAD.");
  84. System.exit(0);
  85. }
  86. else
  87. {
  88. rs.next();
  89. System.out.println(rs.getFloat(1));
  90. System.out.println(cstmt.getString(2));
  91. }
  92. }
  93. catch (SQLException e)
  94. {
  95. e.printStackTrace();
  96. }
  97. }
  98. }
 

回页首

结束语

本文首先介绍了 IDS JDBC Driver 提供的各种语句类型。然后描述了命名参数特性,并讨论了如何在 CallableStatement 中使用命名参数。

本文最后列出了一个演示程序,该程序使用了 IDS 11 服务器中的命名参数特性。现在,您拥有了尝试这个特性的工具,并且了解了命名参数特性的优点。

转自:http://www.ibm.com/developerworks/cn/data/library/techarticles/dm-0802tiwary/

使用命名参数处理 CallableStatement的更多相关文章

  1. .NET中那些所谓的新语法之一:自动属性、隐式类型、命名参数与自动初始化器

    开篇:在日常的.NET开发学习中,我们往往会接触到一些较新的语法,它们相对以前的老语法相比,做了很多的改进,简化了很多繁杂的代码格式,也大大减少了我们这些菜鸟码农的代码量.但是,在开心欢乐之余,我们也 ...

  2. hibernate查询语句hql中的占位符?参数与命名参数:name设值方式搞混

    先贴出异常 Struts has detected an unhandled exception: Messages: Position beyond number of declared ordin ...

  3. c#方法重载,可选参数,命名参数。

    其实这里没什么可说哦,c++的语法大同小异.先看一段代码. class Program { public static void Test(int a) { Console.WriteLine(&qu ...

  4. Python: 收集所有命名参数

    有时候把Python函数调用的命名参数都收集到一个dict中可以更方便地做参数检查,或者直接由参数创建attribute等.更简单的理解就是def foo(*args, **kwargs): pass ...

  5. C#方法的六种参数,值参数、引用参数、输出参数、参数数组、命名参数、可选参数

    方法的参数有六种,分别是值参数.引用参数.输出参数.参数数组.命名参数.可选参数. 值参数 值参数是方法的默认类型,通过复制实参的值到形参的方式把数据传递到方法,方法被调用时,系统作两步操作: 在栈中 ...

  6. C#4.0新特性:可选参数,命名参数,Dynamic

    1.可选参数 可以为方法的参数设置一个默认值,如下: class Program { static void Main(string[] args) { Show(); Show("cary ...

  7. ibernate学习笔记5---实体类或属性名与数据库关键字冲突、hql命名参数、hql实现通用分页

    一.实体类或属性名与数据库关键字冲突问题1.实体类名与数据库中的关键字冲突比如:实体表User与oracle中的系统表冲突解决方式1:在xml中添加table属性,指定表名,使其不与name默认相等 ...

  8. c# 方法参数(传值,传引用,ref,out,params,可选参数,命名参数)

       一.方法参数的类型----值类型和引用类型 当方法传递的参数是值类型时,变量的栈数据会完整地复制到目标参数中即实参和形参中的数据相同但存放在内存的不同位置.所以,在目标方法中对形参所做的更改不会 ...

  9. C# 命名参数【转】

    命名参数(Named Arguments)就是说在调用函数时可以通过指定参数名称的方式来调用参数.它最大的好处就是方便调用参数时按调用者的需要来排列顺序,而不必死守函数声明时的顺序(相对于“位置参数” ...

随机推荐

  1. chromiumFx编译使用

    CEF chormeFx 为针对.Net的CEF框架,下载链接为: https://bitbucket.org/chromiumfx/chromiumfx 点击Download可以下载chromium ...

  2. day5模块学习--random模块

    Python中的random模块用于生成随机数 下面具体介绍random模块的功能:   1.random.random() #用于生成一个0到1的浮点数   随机浮点数:0<= n < ...

  3. php输出多余的空格或者空行

    1,文件是否有bom.可以通过脚步检测,或者利用notepa++打开,查看编码格式. 2.  <?php echo 'something'; ?>  或许是你的php标签外,有空格或者空行 ...

  4. react篇章-React Props

    state 和 props 主要的区别在于 props 是不可变的,而 state 可以根据与用户交互来改变.这就是为什么有些容器组件需要定义 state 来更新和修改数据. 而子组件只能通过 pro ...

  5. 历史文章分类汇总-Anaconda安装第三方包(whl文件)

    本文主要是对公众号之前发布的文章进行分类整理,方面大家查阅,以后会不定期对文章汇总进行更新与发布.   一.推荐阅读: Anaconda安装第三方包(whl文件) 福布斯系列之数据分析思路篇 福布斯系 ...

  6. 如何保证Redis中的数据都是热点数据

    redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略.redis 提供 6种数据淘汰策略:volatile-lru:从已设置过期时间的数据集(server.db[i].expires) ...

  7. 安装部署VMware vSphere 5.5文档 (6-5) 安装配置vCenter

    部署VMware vSphere 5.5 实施文档 ########################################################################## ...

  8. 配置k8s dns

    DNS (domain name system),提供域名解析服务,解决了难于记忆的IP地址问题,以更人性可读可记忆可标识的方式映射对应IP地址. Cluster DNS扩展插件用于支持k8s集群系统 ...

  9. BZOJ 1061: [Noi2008]志愿者招募 [单纯形法]【学习笔记看另一篇吧】

    1061: [Noi2008]志愿者招募 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 3975  Solved: 2421[Submit][Stat ...

  10. 用Win32编写发送消息至Notepad++的程序

    这次利用Win32编程写一个发送"Win32 Assembly,My First SendMessage Program !" 每个程序要发送消息至另一个程序的时候,通常使用Sen ...