12

MyBatis 3 & Spring 3 を使用して、insert ステートメントでバッチ操作を実装する方法を知りたいですか?

たとえば、現在行われていることは次のとおりです。

spring.xml:

<bean id="jndiTemplateDatasource" class="org.springframework.jndi.JndiTemplate">
    <property name="environment">
      <props>
        <prop key="java.naming.factory.initial">${context.factory}</prop>
      </props>
    </property>
</bean>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
  <property name="jndiTemplate" ref="jndiTemplateDatasource"/>
  <property name="jndiName" value="${connectionpool.jndi}"/>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource"/>
</bean>

<tx:annotation-driven transaction-manager="transactionManager"/>

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  <property name="dataSource" ref="dataSource" />
  <property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  <property name="basePackage" value="com.test" />
</bean>

MyService.xml:

<insert id="insertMyRecord" parameterType="com.test.MyRecord"  >
   insert into ... // code removed
</insert> 

MyService.java:

public interface MyService {

  public void insertMyRecord (MyRecord);
}

MyController.java:

@Controller
public class MyController {

  @Autowired
  private MyService myService;

  @Transactional
  @RequestMapping( .... )
  public void bulkUpload (@RequestBody List<MyRecord> myRecords) {
    for (MyRecord record : myRecords) {
      myService.insertMyRecord(record);
    }
  }
}

免責事項: これはデモンストレーション用の単なる擬似コードです

では、それをバッチ プロセスにするにはどうすればよいでしょうか。

理想的には、コードへの「侵入」を最小限に抑えてそれを実行できるようにしたい、つまりアノテーションをより優先的に使用したいのですが、それができない場合、次善の策は何ですか?

また、これは、プロジェクト内のすべてではなく、この 1 つのサービスに対してのみ構成する必要があります。

4

3 に答える 3

10

これは実行およびテストされた例です...バッチを使用して複数の行を更新します(ibatis + java)

この例では。partyid に対応するテーブルから出席数を更新しています。

public static int updateBatch(List<MyModel> attendingUsrList) {
    SqlSession session = ConnectionBuilderAction.getSqlSession();
    PartyDao partyDao = session.getMapper(PartyDao.class);
    try {
        if (attendingUsrList.size() > 0) {
            partyDao.updateAttendingCountForParties(attendingUsrList);
        }
        session.commit();
    } catch (Throwable t) {
        session.rollback();
        logger.error("Exception occurred during updateBatch : ", t);
        throw new PersistenceException(t);
    } finally {
        session.close();
    }
}

変数が定義されているモデル クラス:

public class MyModel  {

    private long attending_count;
    private String eid;

    public String getEid() {
        return eid;
    }

    public void setEid(String eid) {
        this.eid = eid;
    }

    public long getAttending_count() {
        return attending_count;
    }

    public void setAttending_count(long attending_count) {
        this.attending_count = attending_count;
    }


}

party.xml コード

バッチが実行される実際のクエリ

<foreach collection="attendingUsrList" item="model"  separator=";">
    UPDATE parties SET attending_user_count = #{model.attending_count}
    WHERE  fb_party_id = #{model.eid}  
</foreach>

インターフェースコードはこちら

public interface PartyDao {
    int updateAttendingCountForParties (@Param("attendingUsrList") List<FBEventModel>attendingUsrList);
}

これが私のバッチセッションコードです

public static synchronized SqlSession getSqlBatchSession() {
    ConnectionBuilderAction connection = new ConnectionBuilderAction();
    sf = connection.getConnection();
    SqlSession session = sf.openSession(ExecutorType.BATCH);
    return session;
}

SqlSession session = ConnectionBuilderAction.getSqlSession();
于 2013-09-05T10:48:27.160 に答える
2

質問を完全に正しく理解しているかどうかはわかりませんが、私の考えを伝えようとします。

単一のサービスを作成するには、サービス インターフェイスを生成することをお勧めします。

public void bulkUpload (@RequestBody List<T> myRecords) 

次に、オブジェクトのタイプを確認して、適切なマッパー リポジトリを呼び出すことができます。

次に、共通のインターフェイスを作成することで、それをさらに生成できます。

public interface Creator<T> {
    void create(T object);
}

マッパーインターフェースでそれを拡張します:

public interface MyService extends Creator<MyRecord>{}

ここで最も複雑なステップ: 特定のタイプのオブジェクトを取得し、正確なマッパーがこのクラスの Creator インターフェイスを実装しているものを (Java リフレクション API を使用して) 確認し、特定のメソッドを呼び出します。

ここで、私のプロジェクトの 1 つで使用するコードを示します。

package com.mydomain.repository;

//imports ...
import org.reflections.Reflections;

@Repository(value = "dao")
public class MyBatisDao {

    private static final Reflections REFLECTIONS = new Reflections("com.mydomain");

    @Autowired
    public SqlSessionManager sqlSessionManager;

    public void create(Object o) {
        Creator creator = getSpecialMapper(Creator.class, o);
        creator.create(o);
    }

    // other CRUD methods

    @SuppressWarnings("unchecked")
    private <T> T getSpecialMapper(Class<T> specialClass, Object parameterObject) {
        Class parameterClass = parameterObject.getClass();
        Class<T> mapperClass = getSubInterfaceParametrizedWith(specialClass, parameterClass);
        return sqlSessionManager.getMapper(mapperClass);
    }

    private static <T, P> Class<? extends T> getSubInterfaceParametrizedWith(Class<T> superInterface, Class<P> parameterType) {
        Set<Class<? extends T>> subInterfaces = REFLECTIONS.getSubTypesOf(superInterface);
        for (Class<? extends T> subInterface: subInterfaces) {
            for (Type genericInterface : subInterface.getGenericInterfaces()) {
                if (!(genericInterface instanceof ParameterizedType)) continue;
                ParameterizedType parameterizedType = (ParameterizedType) genericInterface;
                Type rawType = parameterizedType.getRawType();
                if (rawType instanceof Class<?> && ((Class<?>) rawType).isAssignableFrom(superInterface)) {
                    for (Type type: parameterizedType.getActualTypeArguments()) {
                        if (type instanceof Class<?> && ((Class<?>) type).isAssignableFrom(parameterType)) {
                            return subInterface;
                        }
                    }
                }

            }
        }
        throw new IllegalStateException(String.format("No extension of %s found for parametrized type %s ", superInterface, parameterType));
    }
}

警告!このアプローチはパフォーマンスに悪影響を与える可能性があるため、パフォーマンスが重要でないアクションで使用してください

一括挿入が必要な場合は、ここで説明されているように、一括挿入に mybatis foreach を使用することをお勧めします。

すべてのタイプのオブジェクトに対して sql を書きたくない場合は、Hibernate またはその他の高度な ORM を使用することをお勧めします。MyBatis は単なる SQL マッピング インターフェイスです。

于 2013-07-29T16:41:42.813 に答える