使用Hibernate查询DB2时Query接口setFetchSize方法的正确使用方式

公司有个项目,采用DB2数据库,持久化技术为Hibernate。

近期有个同事发现Hibernate生成的分页SQL语句查询速度很慢,凭经验,他在该sql语句后面加上了

fetch first 10 rows only

查询速度一下子提高上去了,因此他在Hibernate中的Query调用中增加了.setFetchSize(10)。但是发现Hibernate解析出来的sql并没有增加上面的fetch子句。

其实这个问题的原因在于Hibernate的Dialect不正确,一般的,我们会选择org.hibernate.dialect.DB2Dialect,但其实应该选择org.hibernate.dialect.DB2400Dialect,该类源代码(部分):

	public String getLimitString(String sql, int offset, int limit) {
		if ( offset > 0 ) {
			throw new UnsupportedOperationException( "query result offset is not supported" );
		}
		return new StringBuffer( sql.length() + 40 )
				.append( sql )
				.append( " fetch first " )
				.append( limit )
				.append( " rows only " )
				.toString();
	}

注意到,DB2400Dialect类是继承于DB2Dialect类的。

这样改后, Hibernate解析出来的sql语句就顺利地加上fetch子句了。

 

另记录一下搭建测试代码时碰到的一些问题:

1. DB2的JDBC驱动:我在MAC上使用DbVisualizer-8.0.9,该工具自带了DB2的一个驱动包,放置于/Applications/DbVisualizer-8.0.9.app/Contents/Resources/app/jdbc/db2/db2jcc.jar,手工install到本地Maven仓库

$mvn install:install-file -Dfile=db2jcc.jar -DgroupId=com.ibm.db2.jcc -DartifactId=db2jcc -Dversion=8 -Dpackaging=jar

 

2. Hibernate版本: 搭建测试代码时,首先使用的是Hibernate4,pom文件(部分):

  	<dependency>
  		<groupId>org.hibernate</groupId>
  		<artifactId>hibernate-core</artifactId>
  		<version>4.1.2.Final</version>
  		<!-- 
  		<exclusions>
  			<exclusion>
  				<groupId>org.jboss.logging</groupId>
  				<artifactId>jboss-logging</artifactId>
  			</exclusion>
  		</exclusions>
  		 -->
  	</dependency>

运行测试代码时报错:

DEBUG: org.hibernate.engine.jdbc.spi.SqlExceptionHelper - Could not open connection [n/a]
java.sql.SQLException: No suitable driver found for jdbc:db2://(略去)
	at java.sql.DriverManager.getConnection(DriverManager.java:602)
	at java.sql.DriverManager.getConnection(DriverManager.java:154)

死活不知道原因,后来将Hibernate版本降至3.6.0.Final,顺利通过测试,相关pom文件

  <dependencies>
  	<dependency>
  		<groupId>org.hibernate</groupId>
  		<artifactId>hibernate-core</artifactId>
  		<version>3.6.0.Final</version>
  		<!-- 
  		<exclusions>
  			<exclusion>
  				<groupId>org.jboss.logging</groupId>
  				<artifactId>jboss-logging</artifactId>
  			</exclusion>
  		</exclusions>
  		 -->
  	</dependency>
  	<dependency>
  		<groupId>javassist</groupId>
  		<artifactId>javassist</artifactId>
  		<version>3.12.1.GA</version>
  	</dependency>
  	<dependency>
  		<groupId>org.slf4j</groupId>
  		<artifactId>slf4j-log4j12</artifactId>
  		<version>1.6.1</version>
  	</dependency>
  	<dependency>
  		<groupId>log4j</groupId>
  		<artifactId>log4j</artifactId>
  		<version>1.2.16</version>
  	</dependency>
  	<dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
       <version>4.8.2</version>
   </dependency>
   <!-- 
   <dependency>
       <groupId>com.h2database</groupId>
       <artifactId>h2</artifactId>
       <version>1.2.145</version>
   </dependency>
    -->
   <dependency>
	   <groupId>com.ibm.db2.jcc</groupId>
	   <artifactId>db2jcc</artifactId>
	   <version>8</version>
  </dependency> 
   
  </dependencies>

唔,从这方面以及控制台输入的日志内容看Hibernate4对比Hibernate3的改动是非常大的。

至于为什么Hibernate4报错,留给未来*有时间*再研究吧。

 

参考链接:

What is difference between setMaxResults and setFetchSize in org.hibernate.Query?

Can not get N first results of query with DB2 dialect (neither with setMaxResults nor with setFetchSize)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用JDBC处理大结果集,可能会遇到Java堆空间不足的问题。这通常发生在结果集太大,无法一次性加载到内存中。为了解决这个问题,可以使用MySQL JDBC的setFetchSize()方法setFetchSize()方法是JDBC API的一部分,用于设置从数据库中获取行的数量。默认情况下,JDBC会将所有行一次性加载到内存中。但是,通过设置fetchSize,可以控制JDBC在内存中缓存的行的数量。 以下是使用setFetchSize()方法来解决JDBC处理大结果集的示例代码: ```java import java.sql.*; public class JdbcExample { public static void main(String[] args) throws Exception { String url = "jdbc:mysql://localhost:3306/mydatabase"; String user = "myuser"; String password = "mypassword"; Connection conn = DriverManager.getConnection(url, user, password); Statement stmt = conn.createStatement(); String sql = "SELECT * FROM mytable"; stmt.setFetchSize(100); // 设置每次获取100行结果 ResultSet rs = stmt.executeQuery(sql); while (rs.next()) { // 处理结果 } rs.close(); stmt.close(); conn.close(); } } ``` 在上面的示例代码中,我们将每次获取100行结果,这样就可以避免将所有结果一次性加载到内存中,从而避免Java堆空间不足的问题。 需要注意的是,setFetchSize()方法不是所有JDBC驱动程序都支持的。如果你的驱动程序不支持这个方法,那么你需要使用其他方法来处理大结果集,例如使用分页查询或者将结果写入文件中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值