如何使用MyBatis / Spring实现批处理操作?
我想知道如何使用MyBatis 3和Spring 3使用insert语句实现批处理操作?
例如,以下是目前正在进行的操作:
spring.xml:
${context.factory}
MyService.xml:
insert into ... // code removed
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 myRecords) { for (MyRecord record : myRecords) { myService.insertMyRecord(record); } } }
免责声明:这只是用于演示目的的伪代码
那么我该怎么做才能把它变成一个批处理过程呢?
理想情况下,我希望能够以最少的“入侵”代码进行,即使用注释更优先,但如果不可能,那么下一个最好的东西是什么?
此外,这需要仅针对此一项服务进行配置,而不是针对项目中的所有内容进行配置。
这是运行和测试的示例…使用批处理更新多行(ibatis + java)
在这个前。 我正在更新参加桌子的人数和派对。
public static int updateBatch(List 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代码
批处理执行的实际查询
UPDATE parties SET attending_user_count = #{model.attending_count} WHERE fb_party_id = #{model.eid}
接口代码在这里
public interface PartyDao { int updateAttendingCountForParties (@Param("attendingUsrList") ListattendingUsrList); }
这是我的批处理会话代码
public static synchronized SqlSession getSqlBatchSession() { ConnectionBuilderAction connection = new ConnectionBuilderAction(); sf = connection.getConnection(); SqlSession session = sf.openSession(ExecutorType.BATCH); return session; } SqlSession session = ConnectionBuilderAction.getSqlSession();
上面接受的答案实际上并没有为MyBatis提供批处理模式。 您需要通过ExecutorType.BATCH选择正确的Executor。 这可以作为参数传递给标准MyBatis API中的SqlSession.openSession,或者,如果使用MyBatis-Spring,则作为SqlSessionTemplate的选项传递。 通过以下方式完成:
没有别的事情需要做。
我不确定我完全理解这个问题,但我会尽力给你我的想法。
为了制作单一服务,我建议生成服务接口:
public void bulkUpload (@RequestBody List myRecords)
然后,您可以检查对象的类型并调用propper映射器存储库。
然后,您可以通过创建一个通用界面来更多地进一步通用:
public interface Creator { void create(T object); }
并通过mapper接口扩展它:
public interface MyService extends Creator{}
现在最复杂的一步是:获取特定类型的对象,查看确切的mapper实现此类的Creator接口(使用javareflectionAPI)并调用特定方法。
现在我给你在我的一个项目中使用的代码:
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 getSpecialMapper(Class specialClass, Object parameterObject) { Class parameterClass = parameterObject.getClass(); Class mapperClass = getSubInterfaceParametrizedWith(specialClass, parameterClass); return sqlSessionManager.getMapper(mapperClass); } private static Class extends T> getSubInterfaceParametrizedWith(Class superInterface, Class parameterType) { Set> 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映射接口。