9.7 参数的输入与输出
要实现使用SQL语句的输入与输出参数,必须在PreparedStatement类的对象上进行操作;同时由于CallableStatement类是PrepareStatement类的子类,所以在CallableStatemen对象上的操作也可以使用输入与输出参数;其主要的编程原理是在生成CallableStatement或PreparedStatement类的对象时,可以在SQL语句中指定输入或输出参数,在执行这个SQL语句之前,要对输入参数进行赋值。
(1)使用PreparedStatement类的对象
通过prepareStatement类的对象可以实现在查询语句与数据更新语句方面都可以设置输入参数。
具体的方法是在SQL语句中用“?”标明参数,在执行SQL语句之前,使用setXXX方法给参数赋值,然后使用executeQuery()或executeUpdate()来执行这个SQL语句。每次执行SQL语句之前,可以给参数重新赋值。
setXXX方法用于给相应的输入参数进行赋值,其中XXX是JDBC的数据类型,如:Int、String等。setXXX方法有两个参数,第一个是要赋值的参数在SQL语句中的位置, SQL语句中的第一个参数的位置为1,第二个参数的位置为2;setXXX方法的第二个参数是要传递的值,如100、“Peking”等,随XXX的不同而为不同的类型。
PreparedStatement pstmt=con.prepareStatement("Update TableName set Name=? where ID=?");
pstmt.setString(1,"zhang Hua"); //设置第一个参数(Name)为 “zhang Hua”
for(int i=1;i<3;i++)
{
pstmt.setInt(2,i); //设置第二个参数(ID)为 1,2
pstmt.executeUpdate();
}
要点:最终实现 Update TableName set Name=zhang Hua where ID=1 与Update TableName set Name=zhang Hua where ID=2的效果。
(2)使用CallableStatement对象
如果要求调用数据库的存储过程,要使用CallableStatement对象。另外还有些存储过程要求用户输入参数,这可以在生成CallableStatement对象的存储过程调用语句中设置输入参数。在执行这个存储过程之前使用setXXX方法给参数赋值,然后再执行这个存储过程。
CallableStatement cstmt=con.prepareCall("{call Query(?)}"); //Query为存储过程名
cstmt.setString(1,"输入参数"); //为存储过程提供输入参数
ResultSet rs=cstmt.executeQuery();
(3)接收输出参数
某些存储过程可能会返回输出参数,这时在执行这个存储过程之前,必须使用CallableStatement的registerOutParameter方法首先登记输出参数,在registerOutParameter方法中要给出输出参数的相应位置以及输出参数的SQL数据类型。在执行完存储过程以后,必须使用getXXX方法来获得输出参数的值。并在getXXX方法中要指出获得哪一个输出参数(通过序号来指定)的值。
实例:存储过程getTestData有三个输入参数并返回一个输出参数,类型分别为VARCHAR。在执行完毕后,分别使用getString()方法来获得相应的值。
CallableStatement cstmt = con.prepareCall(“{? = call getTestData (?,?,?)}”);
cstmt.setString(1,Value);//设置输入参数
cstmt.setInt(2,Value);
cstmt.setFloat(3,Value);
cstmt.registerOutParameter(1,java.sql.Types.VARCHAR);//登记输出参数
ResultSet rs = cstmt.executeQuery();//执行存储过程
rs.getString(1);//获得第一个字段的值
String returnResult=cstmt.getString(1);//获得返回的输出参数的值
要点:由于getXXX方法不对数据类型作任何转换,在registerOutParameter方法中指明数据库将返回的SQL数据类型,在执行完存储过程以后必须采用相应匹配的getXXX方法来获得输出参数的值。
9.8 批量处理JDBC语句提高处理速度
有时候JDBC运行得不够快,这可以使用数据库相关的存储过程。当然,作为存储过程的一个替代方案,可以试试使用Statement 的批量处理特性以提高速度。
存储过程的最简单的形式就是包含一系列SQL语句的过程,将这些语句放在一起便于在同一个地方管理也可以提高速度。Statement 类可以包含一系列SQL语句,因此允许在同一个数据库事务执行所有的那些语句而不是执行对数据库的一系列调用。
使用批量处理功能涉及下面的两个方法:
addBatch(String) 方法
executeBatch方法
如果你正在使用Statement 那么addBatch 方法可以接受一个通常的SQL语句,或者如果你在使用PreparedStatement ,那么也可以什么都不向它增加。
executeBatch 方法执行那些SQL语句并返回一个int值的数组,这个数组包含每个语句影响的数据的行数。
注意:如果将一个SELECT语句或者其他返回一个ResultSet的SQL语句放入批量处理中就会导致一个SQLException异常。
关于java.sql.Statement 的简单范例可以是:
con = DriverManager.getConnection(url,"myLogin", "myPassword");
con.setAutoCommit(false);
stmt = con.createStatement();
stmt.addBatch("INSERT INTO student " + "VALUES(4,'Yang',20,True)");
stmt.addBatch("INSERT INTO student " + "VALUES(5,'li',20,True)");
stmt.addBatch("INSERT INTO student " + "VALUES(6,'zhang',20,True)");
stmt.addBatch("INSERT INTO student " + "VALUES(7,'wang',20,True)");
stmt.addBatch("INSERT INTO student " + "VALUES(8,'liu',20,True)");
int [] updateCounts = stmt.executeBatch();
con.commit();
con.setAutoCommit(true);
PreparedStatement 有些不同,它只能处理一部分SQL语法,但是可以有很多参数,因此重写上面的范例的一部分就可以得到下面的结果:
// 注意这里没有删除语句
PreparedStatement stmt = conn.prepareStatement(
"INSERT INTO student VALUES(?,?,?,?)"
);
User[ ] users = ...;
for(int i=0; i
stmt.setInt(1, users[i].getID());
stmt.setString(2, users[i].getName());
stmt.setInt(3, users[i].getAge());
stmt.setBoolean(4, users[i].getSex());
stmt.addBatch( );
}
int[ ] counts = stmt.executeBatch();
如果你不知道你的语句要运行多少次,那么这是一个很好的处理SQL代码的方法。在不使用批量处理的情况下,如果添加50个用户,那么性能就有影响,如果某个人写了一个脚本添加一万个用户,程序可能变得很糟糕。添加批处理功能就可以帮助提高性能,而且在后面的那种情况下代码的可读性也会更好。