运维开发网

Java Mybatis在spring中使用xml配置返回大结果

运维开发网 https://www.qedev.com 2020-04-15 08:07 出处:网络 作者:运维开发网整理
我需要将数据从oracle中的表转储到elasticsearch(1亿条记录), 我的JVM内存限制为256M,我使用以下代码和配置从oracle(mybatis spring)获取数据: 界面: package com.fudy.mapper; import java.util.List; import com.fudy.domain.Person; public interface Perso
我需要将数据从oracle中的表转储到elasticsearch(1亿条记录),

我的JVM内存限制为256M,我使用以下代码和配置从oracle(mybatis spring)获取数据:

界面:

package com.fudy.mapper;
import java.util.List;
import com.fudy.domain.Person;
public interface PersonMapper {
    List<Person> selectAllPerson();
}

xml配置:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.fudy.mapper.PersonMapper">
    <resultMap type="com.fudy.domain.Person" id="PersonAlias">
        <id column="ID" property="id" />
        <result column="NAME" property="name" />
    </resultMap>
    <select id="selectAllPerson" fetchSize="10000" resultMap="PersonAlias">
        SELECT * FROM person
    </select>
</mapper>

ApplicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    <context:annotation-config />
    <tx:annotation-driven transaction-manager="transactionManager" />

    <context:property-placeholder location="classpath:db.properties"/>

    <bean id="dataSource" class="oracle.jdbc.pool.OracleDataSource" destroy-method="close">
        <property name="URL" value="${jdbc.url}" />
        <property name="user" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="connectionCachingEnabled" value="true"/>
    </bean>



    <!-- define the SqlSessionFactory, notice that configLocation is not needed 
        when you use MapperFactoryBean -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />

        <property name="configLocation" value="classpath:Configuration.xml" />  

    </bean>

    <!-- scan for mappers and let them be autowired -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.fudy.mapper" />
        <!-- optional unless there are multiple session factories defined -->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
    </bean>

    <bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean> 

</beans>

我的junit测试:

package com.fudy.mapper;

import java.util.List;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.fudy.domain.Person;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"/ApplicationContext.xml"})
public class PersonMapperTest {
    @Autowired
    private PersonMapper mapper;
    @Test
    public void testSelectAllPerson() {
        List<Person> list = mapper.selectAllPerson();
        for ( Person person : list) {
            System.out.println(person.getId());
            System.out.println(person.getName());
            //TODO insert into elasticsearch 
        }
    }
}

你可以从junit测试中看到,Mybatis将返回结果的整个列表,这将导致内存不足问题.谷歌之后,我发现ResultHandler可以解决问题,但我找不到工作的演示.

有两种选择:

>使用ResultHandler

>自3.4.1起使用Cursor

ResultHandler

这就是你可以使用自定义ResultHandler的方法:

PersonMapper.xml

<mapper namespace="com.fudy.mapper.PersonMapper">
  <resultMap type="com.fudy.domain.Person" id="PersonAlias">
    <id column="ID" property="id" />
    <result column="NAME" property="name" />
  </resultMap>
  <select id="selectAllPerson" resultMap="PersonAlias">
     SELECT * FROM person
  </select>
</mapper>

PersonMapper.java

public interface PersonMapper {
     void selectAllPersons(ResultHandler handler);
}

MyService.java

class PersonResultHandler implements ResultHandler {
    @Override
    public void handleResult(ResultContext context) { 
        Person person = (Person)context.getResultObject(); 
        // process person here
    }
};
PersonResultHandler handler = new PersonResultHandler();
PersonMapper personMapper = ...;
personMapper.selectAllPersons(handler);

光标

从mybatis 3.4.1开始,你可以返回Cursor这是Iterable并且可以像这样使用(在结果有序的情况下,详见上面的Cursor API java doc):

PersonMapper.java

public interface PersonMapper {
     Cursor<Person> selectAllPersons();
}

MyService.java

PersonMapper personMapper = ...;
try (Cursor<Person> persons = personMapper.selectAllPersons()) {
   for (Person person : persons) {
      // process one person
   }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消