我有需要使用MyBatis调用的存储过程。无论如何,我设法调用了这个存储过程。过程具有多个out参数。其中一个参数是oracle游标。我需要对Oracle Cursor进行迭代,但当我在没有使用fetchSize属性对jdbc驱动程序进行任何微调的情况下进行迭代时,它会逐行进行,并且这个解决方案非常缓慢。我可以在过程调用中设置fethcSize属性:
<select id="getEvents" statementType="CALLABLE" parameterMap="eventInputMap" fetchSize="1000">
{call myProc(?, ?, ?, ?, ?)}
</select>
但这一点帮助都没有。我认为这不起作用,因为有多个out参数——所以程序不知道这个获取大小应该应用在哪里——在哪个out参数上。有没有办法在ResultSet(Oracle游标)上设置获取大小?就像当我使用java.sql包中的CallableStatemen时,我可以设置ResultSet的获取大小。
以下是映射文件和程序调用:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//ibatis.apache.org//DTD Mapper 3.0//EN"
"http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd">
<mapper namespace="mypackage.EventDao">
<resultMap id="eventResult" type="Event">
<result property="id" column="event_id" />
<result property="name" column="event_name" />
</resultMap>
<parameterMap id="eventInputMap" type="map" >
<parameter property="pnNetworkId" jdbcType="NUMERIC" javaType="java.lang.Integer" mode="IN"/>
<parameter property="pvUserIdentityId" jdbcType="VARCHAR" javaType="java.lang.String" mode="IN"/>
<parameter property="result" resultMap="eventResult" jdbcType="CURSOR" javaType="java.sql.ResultSet" mode="OUT" />
<parameter property="success" jdbcType="INTEGER" javaType="java.lang.Integer" mode="OUT"/>
<parameter property="message" jdbcType="VARCHAR" javaType="java.lang.String" mode="OUT"/>
</parameterMap>
<select id="getEvents" statementType="CALLABLE" parameterMap="eventInputMap" fetchSize="1000">
{call myProc(?, ?, ?, ?, ?)}
</select>
</mapper>
并从程序调用:
SqlSession session = sqlSessionFactory.openSession();
Map<String, Object> eventInputMap = new HashMap<String, Object>();
try {
EventDao ed = session.getMapper(EventDao.class);
eventInputMap.put("pnNetworkId", networkId);
eventInputMap.put("pvUserIdentityId", identityId);
eventInputMap.put("success", 0);
eventInputMap.put("message", null);
ed.getEvents(eventInputMap);
session.selectList("EventDao.getEvents", eventInputMap);
} catch (Exception e) {
e.printStackTrace();
}finally{
session.close();
}
提前感谢!
提供的代码可以正常工作。我甚至检查了3种编写方法:比如这里有parameterMap,没有parameterMap[/em>(直接在语句中映射),通过注释,一切都正常。
我曾经认为fetchSize设置不会从main语句传播到OUT param resultSet,直到最近我真正测试了这一点。为了了解是否使用了获取大小以及它的效果,结果必须包含足够多的行。当然,最差的是从应用程序到数据库的延迟,更明显的是效果。对于我的测试,过程使用的游标返回了5400行120列(但最重要的是行数)。为了给出一个数量级,我测量了获取时间,即从存储过程返回到语句返回,结果列表中充满了从游标获取的数据。然后我记录映射的第一个对象的状态,这发生在全局获取的开始附近,可能在第一次获取之后:
public static boolean firstInstance = true;
public Item() {
if (firstInstance) {
LOGGER.debug("Item first instance");
firstInstance=false;
}
}
我在会话结束后再次登录。selectList返回。
这仅用于测试目的。不要让这是你的代码。找到一种干净的方法。
以下是一些取决于配置的提取大小的时间:
- fetchSize=1 => 13000 ms
- fetchSize=10 => 5300 ms
- fetchSize=100 => 3800 ms
- fetchSize=300 => 3700 ms
- fetchSize=500 => 3650 ms
- fetchSize=1000 => 3600 ms
Oracle JDBC驱动程序默认fetchSize为10。
使用fetchSize=1进行测试可以证明使用了提供的设置。
有了100,这里可以节省30%。除此之外,增益可以忽略不计(在这种用例和环境下)
无论如何,如果能够知道过程执行何时结束以及结果获取何时开始,那将是一件有趣的事情。不幸的是,Mybatis的日志很少。我认为自定义结果处理程序会有所帮助,但查看类org.apache.ibati.executor.resultset.DefaultResultSetHandler的源代码,我注意到与允许使用自定义结果处理程序的方法handleResultSet(用于简单的select语句)不同,方法handleRefCursorOutputParameter不允许(此处用于过程OUT游标)。然后无需尝试传递自定义结果处理程序:它将被忽略。如果有人有解决方案的话,我对它感兴趣。但这似乎需要一个进化的要求。