http://shelaine.javaeye.com/blog/336627
有的时候JDBC运行的不够理想,这就促使我们写一些与特定数据库相关的存储过程。作为一个替换方案,不妨试一下Statement的批处理特征,看看一次执行所有的SQL语句是否会带来速度的提升。
存储过程最简单的形式就是整个过程只包含一组SQL语句。将这些语句放到一起能容易管理也可以提高运行速度。Statement类具有包含一串SQL语句的能力,因此它允许所有的SQL语句在一个数据库会话中被执行,从而避免了向数据库进行一连串的执行调用。
使用批处理功能涉及到两个方法:
addBatch(String)方法
executeBatch方法
addBatch方法可以接受一段标准的SQL(如果你使用一个Statement)作为参数,也可以什么参数都不带(如果你使用一个PreparedStatement)。
executeBatch方法接着执行SQL语句,返回一个int型数组。这个数组包括每条语句影响到的行数。如果在一个批处理中使用是一个SELECT或者其它只返回结果的语句,那么将会产生一个SQLException异常。
下面是一个简单的java.sql.Statement的例子:
Statement stmt = conn.createStatement();
stmt.insert("DELETE FROM Users");
stmt.insert("INSERT INTO Users VALUES('rod', 37, 'circle')");
stmt.insert("INSERT INTO Users VALUES('jane', 33, 'triangle')");
stmt.insert("INSERT INTO Users VALUES('freddy', 29, 'square')");
int[] counts = stmt.executeBatch();
使用PreparedStatement会稍有不同。它只能处理一段SQL语句,但可以带很多参数。下面的是使用PreparedStatement重写的上面的例子:
//注意我们并没有做任何删除动作
PreparedStatement stmt = conn.prepareStatement( _
"INSERT INTO Users VALUES(?,?,?)" );
User[ ] users = ...;
for(int i=0; i
{
stmt.setInt(1, users.getName());
stmt.setInt(2, users.getAge());
stmt.setInt(3, users.getShape());
stmt.addBatch( );
}
int[ ] counts = stmt.executeBatch();
这是处理那些不知道具体执行次数的SQL代码的一个好方法。没有批处理,如果要添加50个用户,其性能可能受到影响。如果谁写了一段添加10000个用户的脚本,其运行速度就难以忍受。增加批处理将有助于提升性能,在后一种情况里,甚至可以改善代码的可读性。
使用PreparedStatement减少开发时间
JDBC(Java Database
Connectivity,java数据库连接)的API中的主要的四个类之一的java.sql.Statement要求开发者付出大量的时间和精力。
在使用Statement获取JDBC访问时所具有的一个共通的问题是输入适当格式的日期和时间戳:2002-02-05 20:56 或者
02/05/02 8:56
PM。通过使用java.sql.PreparedStatement,这个问题可以自动解决。一个PreparedStatement是从
java.sql.Connection对象和所提供的SQL字符串得到的,SQL字符串中包含问号(?),这些问号标明变量的位置,然后提供变量的值,
最后执行语句,例如:
Stringsql = "SELECT * FROM People p WHERE p.id = ? AND p.name =
?";PreparedStatement ps =
connection.prepareStatement(sql);ps.setInt(1,id);ps.setString(2,name);ResultSet
rs = ps.execute();
使用PreparedStatement的另一个优点是字符串不是动态创建的。下面是一个动态创建字符串的例子:
Stringsql = "SELECT * FROM People p WHERE p.i = "+id;
这允许JVM(JavaVirtual Machine,Java虚拟机)和驱动/数据库缓存语句和字符串并提高性能。
PreparedStatement也提供数据库无关性。当显示声明的SQL越少,那么潜在的SQL语句的数据库依赖性就越小。
由于PreparedStatement具备很多优点,开发者可能通常都使用它,只有在完全是因为性能原因或者是在一行SQL语句中没有变量的时候才使用通常的Statement。
发出查询和处理结果
在任何你想向数据库运行一个SQL语句的时候, 你都需要一个 Statement 或 PreparedStatement 实例。
一旦你拥有了一个 Statement 或 PreparedStatement,你就可以 发出一个查询。 这样将返回一个 ResultSet
实例, 在其内部包含整个结果。 Example 31-1 演示了这个过程。
Example 31-1. 在 JDBC 里处理一个简单的查询
这个例子将发出一个简单的查询然后用一个 Statement打印出每行的第一个字段。
Statement st = db.createStatement();ResultSet rs =
st.executeQuery("SELECT * FROM mytable WHERE columnfoo = 500");while
(rs.next()) { System.out.print("Column 1 returned ");
System.out.println(rs.getString(1));}rs.close();st.close();
这个例子将使用 PreparedStatement 发出和前面一样的查询,并且在查询中制作数值。
int foovalue = 500;PreparedStatement st =
db.prepareStatement("SELECT * FROM mytable WHERE columnfoo =
?");st.setInt(1, foovalue);ResultSet rs = st.executeQuery();while
(rs.next()) { System.out.print("Column 1 returned ");
System.out.println(rs.getString(1));}rs.close();st.close();
31.3.1. 使用 Statement或 PreparedStatement 接口
在使用 Statement或 PreparedStatement接口时必须考虑下面的问题:
你可以将一个 Statement或 PreparedStatement实例使用任意次。 你可以在打开一个联接后马上创建一个
Statement 实例, 并且在联接的生存期里使用之。 你必须记住每个 Statement或 PreparedStatement只能存在一个
ResultSet。
如果你需要在处理一个 ResultSet的时候执行一个查询, 你只需要创建并且使用另外一个 Statement。
如果你使用了 threads (线程),并且有几个使用数据库, 你对每个线程必须使用一个独立的 Statement。 如果考虑使用线程, 请参考本文档稍后的 Section 31.8 章节, 因为这些内容包含一些重要的信息。
在你用完 Statement 或者 PreparedStatement 之后,你应该关闭它。
31.3.2. 使用 ResultSet(结果集)接口
使用 ResultSet接口时必须考虑下面的问题:
在读取任何数值的时候,你必须调用 next()。 如果还有结果则返回真(true),但更重要的是,它为处理准备了数据行。
在 JDBC 规范里,你对一个字段应该只访问一次。 遵循这个规则是最安全的,不过目前 PostgreSQL 驱动将允许你对一个字段访问任意次。
一旦你结束对一个 ResultSet 的处理,你必须对之调用 close()来关闭它。
一旦你使用那个创建 ResultSet的 Statement做另一个查询请求, 当前打开的 ResultSet 实例将自动关闭。
目前的 ResultSet 是只读的。 你不能通过 ResultSet 来更新数据。 如果你想更新数据,那么你就需要使用普通的方法来做∶ 通过发出一条 SQL 更新语句。这么做是和 JDBC 规范兼容的,它并不要求驱动提供可更新的结果集的支持。
阅读(1013) | 评论(0) | 转发(0) |