鉴于上一篇博文一次修改mysql字段类型引发的技术探究提到的,要对foreach里面的collection相关的内容做一些介绍,今天就围绕foreach,做一些数据插入和查询相关的研究。

首先介绍一下我的环境:

1. linux redhat7

2. mysql 5.6

3. java7

4. mybatis 3.2.7 (后来遇到问题,更新到3.3.1)

第一步,在数据库中创建测试用的表 foreach_test。如下:

mysql> desc foreach_test;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | int() | NO | PRI | NULL | auto_increment |
| name | varchar() | YES | | NULL | |
| age | int() | YES | | NULL | |
| idx | int() | YES | | NULL | |
+-------+-------------+------+-----+---------+----------------+
rows in set (0.00 sec)

第二步,进行mybatis相关的mapper以及dao进行配置。今天研究和介绍的关于foreach的相关内容,将从insert以及select两个大类进行案例介绍,其中,insert是重点,因为批量数据插入,相对比较复杂点,涉及到键值的更新过程。对于mysql数据库而言,对于第一步中创建的数据表foreach_test,有一个主键id,是数字自增型的。这里,结合mybatis的官方文档介绍,将会有两种更新主键的方法:selectKey,以及useGeneratedKeys=“true” 下面将结合这两种方法,以及foreach的collection能够支持的三种集合类型list,array以及map进行案例分析。

1. selectKey方案的插入,数据采用list传入

mapper的sql语句:

<insert id="foreachSelectKeyInsert" parameterType="java.util.List">
<selectKey resultType ="java.lang.Integer" keyProperty= "iid" order= "AFTER">
SELECT LAST_INSERT_ID()
</selectKey >
insert into foreach_test (name, age, idx) values
<foreach item="st" collection="list" index="idx" open="" separator="," close="">
(#{st.name, jdbcType=VARCHAR}, #{st.age, jdbcType=INTEGER}, #{idx})
</foreach>
</insert>

dao层的接口:

int foreachSelectKeyInsert(List<Du> dud);

java业务逻辑:

    @GET
@Path("/foreach/selectkey/insert")
public String foreachSelectKeyInsert(@Context HttpServletRequest req){ List<Du> dud = new ArrayList<Du>();
for(int i=; i < ; i++){
Du du1 = new Du();
du1.setName("SelectKey" + i);
du1.setAge(+i);
dud.add(du1);
} pes.foreachSelectKeyInsert(dud); return "SelectKey Insert OK";
}

在地址栏输入:

http://10.90.9.20:8080/ecs/demo/foreach/selectkey/insert

数据库中得到:

mysql> select * from foreach_test;
+----+------------+------+------+
| id | name | age | idx |
+----+------------+------+------+
| | SelectKey1 | | |
| | SelectKey2 | | |
| | SelectKey3 | | |
| | SelectKey4 | | |
+----+------------+------+------+
rows in set (0.00 sec)

2. useGeneratedKeys=”true“方案的插入,数据采用list传入

mapper的sql语句:

<insert id="foreachUseGeneratedKeysInsert1" keyProperty="id" useGeneratedKeys="true">
insert into foreach_test (name, age, idx) values
<foreach item="st" collection="list" index="idx" open="" separator="," close="">
(#{st.name, jdbcType=VARCHAR}, #{st.age, jdbcType=INTEGER}, #{idx})
</foreach>
</insert>

dao接口:

int foreachUseGeneratedKeysInsert1(List<Du> dud);

java业务逻辑:

   @GET
@Path("/foreach/usegeneratedkeys/insert1")
public String foreachUseGeneratedKeysInsert1(@Context HttpServletRequest req){ List<Du> dud = new ArrayList<Du>();
for(int i=; i < ; i++){
Du du1 = new Du();
du1.setName("UseGeneratedKeys1" + i);
du1.setAge(+i);
dud.add(du1);
}
pes.foreachUseGeneratedKeysInsert1(dud); return "UseGeneratedKeys1 Insert OK";
}

在地址栏输入:

http://10.90.9.20:8080/ecs/demo/foreach/usegeneratedkeys/insert1

结果爆出错误:

org.apache.ibatis.binding.BindingException: Parameter 'id' not found. Available parameters are [list]
at org.apache.ibatis.session.defaults.DefaultSqlSession$StrictMap.get(DefaultSqlSession.java:)
at org.apache.ibatis.reflection.wrapper.MapWrapper.getSetterType(MapWrapper.java:)
at org.apache.ibatis.reflection.MetaObject.getSetterType(MetaObject.java:)
at org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator.getTypeHandlers(Jdbc3KeyGenerator.java:)
at org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator.processBatch(Jdbc3KeyGenerator.java:)
at org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator.processAfter(Jdbc3KeyGenerator.java:)
at org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:)
at org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:)
at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:)
at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:)
at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:)
at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:)
at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:)
at java.lang.reflect.Method.invoke(Method.java:)
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:)
at com.sun.proxy.$Proxy11.insert(Unknown Source)
at org.mybatis.spring.SqlSessionTemplate.insert(SqlSessionTemplate.java:)
at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:)
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:)
at com.sun.proxy.$Proxy32.foreachUseGeneratedKeysInsert1(Unknown Source)
at com.tg.ecs.ucc.service.impl.PurchaseElementService.foreachUseGeneratedKeysInsert1(PurchaseElementService.java:)
at com.tg.ecs.ucc.service.impl.PurchaseElementService$$FastClassBySpringCGLIB$$4e94c14f.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:)
at org.springframework.transaction.interceptor.TransactionInterceptor$.proceedWithInvocation(TransactionInterceptor.java:)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:)
at com.tg.ecs.ucc.service.impl.PurchaseElementService$$EnhancerBySpringCGLIB$$d26e54fd.foreachUseGeneratedKeysInsert1(<generated>)
at com.tg.ecs.ucc.service.impl.PurchaseElementService$$FastClassBySpringCGLIB$$4e94c14f.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:)
at org.springframework.transaction.interceptor.TransactionInterceptor$.proceedWithInvocation(TransactionInterceptor.java:)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:)
at com.tg.ecs.ucc.service.impl.PurchaseElementService$$EnhancerBySpringCGLIB$$5a877984.foreachUseGeneratedKeysInsert1(<generated>)
at com.tg.ecs.test.DemoController.foreachUseGeneratedKeysInsert1(DemoController.java:)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:)
at java.lang.reflect.Method.invoke(Method.java:)
at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$.invoke(ResourceMethodInvocationHandlerFactory.java:)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$.run(AbstractJavaResourceMethodDispatcher.java:)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:)
at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$TypeOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:)
at org.glassfish.jersey.server.ServerRuntime$.run(ServerRuntime.java:)
at org.glassfish.jersey.internal.Errors$.call(Errors.java:)
at org.glassfish.jersey.internal.Errors$.call(Errors.java:)
at org.glassfish.jersey.internal.Errors.process(Errors.java:)
at org.glassfish.jersey.internal.Errors.process(Errors.java:)
at org.glassfish.jersey.internal.Errors.process(Errors.java:)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:)
at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:)
at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:)
at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:)
at org.glassfish.jersey.servlet.ServletContainer.serviceImpl(ServletContainer.java:)
at org.glassfish.jersey.servlet.ServletContainer.doFilter(ServletContainer.java:)
at org.glassfish.jersey.servlet.ServletContainer.doFilter(ServletContainer.java:)
at org.glassfish.jersey.servlet.ServletContainer.doFilter(ServletContainer.java:)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:)
at com.tg.ecs.core.xss.XssFilter.doFilter(XssFilter.java:)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:)
at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:)
at org.apache.shiro.web.servlet.AbstractShiroFilter$.call(AbstractShiroFilter.java:)
at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:)
at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:)
at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:)
at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:)
at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:)
at java.lang.Thread.run(Thread.java:)

这个错误,折腾了我好久,在stackoverflow网站找到了一个老外的类似问题,得到线索,说是mybatis的版本问题,3.3.1之后(我当前的研究环境是3.2.7),这个问题才得以解决。在没有验证是否正确之前,继续当前环境下的研究。前端报错了,依旧查看数据库,看是否有数据写入:

mysql> select * from foreach_test;
+----+--------------------+------+------+
| id | name | age | idx |
+----+--------------------+------+------+
| | UseGeneratedKeys16 | | |
| | UseGeneratedKeys17 | | |
| | UseGeneratedKeys18 | | |
| | UseGeneratedKeys19 | | |
+----+--------------------+------+------+
rows in set (0.00 sec)

说明,数据是写入了库,但是前端这个错误很不友好。

虽然报错,但是从插入数据库的结果得出结论:传入给mybatis的list(单独参数),collection的值,默认是list,此时,item的内容为list的元素,index的值为遍历list的序号,从0开始递增

3. useGeneratedKeys=”true“方案的插入,数据采用map传入

mapper的sql语句:

<insert id="foreachUseGeneratedKeysInsert2" keyProperty="id" useGeneratedKeys="true">
insert into foreach_test (name, age, idx) values
<foreach item="st" collection="dudkey" index="idx" open="(" separator="),(" close=")">
#{st.name, jdbcType=VARCHAR}, #{st.age, jdbcType=INTEGER}, #{idx}
</foreach>
</insert>

dao接口:

int foreachUseGeneratedKeysInsert2(HashMap<String, List<Du>> dumap);

java业务逻辑:

    @GET
@Path("/foreach/usegeneratedkeys/insert2")
public String foreachUseGeneratedKeysInsert2(@Context HttpServletRequest req){ List<Du> dud = new ArrayList<Du>();
for(int i=; i < ; i++){
Du du1 = new Du();
du1.setName("UseGeneratedKeys2" + i);
du1.setAge(+i);
dud.add(du1);
}
HashMap<String, List<Du>> dumap = new HashMap<String, List<Du>>();
dumap.put("dudkey", dud);
pes.foreachUseGeneratedKeysInsert2(dumap); return "UseGeneratedKeys2 Insert OK";
}

在地址栏输入:

http://10.90.9.20:8080/ecs/demo/foreach/usegeneratedkeys/insert2

查看数据库:

mysql> select * from foreach_test;
+----+--------------------+------+------+
| id | name | age | idx |
+----+--------------------+------+------+
| | UseGeneratedKeys26 | | |
| | UseGeneratedKeys27 | | |
| | UseGeneratedKeys28 | | |
| | UseGeneratedKeys29 | | |
+----+--------------------+------+------+
rows in set (0.00 sec)

奇怪吧,3.2.7的环境(mybatis-spring版本是1.2.4)下,传入map,批量插入不报前面出现的id找不到的错误。

从这个案例,可以看出:传入mybatis的map,若给collection的值是入参map中的key的话,那么item的值将是map的value,此时的index值,就是map中value遍历的序号,从0开始递增

到此,将mybatis的版本进行升级,升级到3.3.1,去maven仓库下载该版本:http://mvnrepository.com/artifact/org.mybatis/mybatis/3.3.1,更新到项目中,然后启动项目进行验证,哎,不幸运啊,又有新错误:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'shiroRealm': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sysMenuService': Invocation of init method failed; nested exception is java.lang.AbstractMethodError: org.mybatis.spring.transaction.SpringManagedTransaction.getTimeout()Ljava/lang/Integer;
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:)
at org.springframework.beans.factory.support.AbstractBeanFactory$.getObject(AbstractBeanFactory.java:)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:)
... more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sysMenuService': Invocation of init method failed; nested exception is java.lang.AbstractMethodError: org.mybatis.spring.transaction.SpringManagedTransaction.getTimeout()Ljava/lang/Integer;
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:)
at org.springframework.beans.factory.support.AbstractBeanFactory$.getObject(AbstractBeanFactory.java:)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.autowireResource(CommonAnnotationBeanPostProcessor.java:)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.getResource(CommonAnnotationBeanPostProcessor.java:)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.getResourceToInject(CommonAnnotationBeanPostProcessor.java:)
at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:)
... more
Caused by: java.lang.AbstractMethodError: org.mybatis.spring.transaction.SpringManagedTransaction.getTimeout()Ljava/lang/Integer;
at org.apache.ibatis.executor.SimpleExecutor.prepareStatement(SimpleExecutor.java:)
at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:)
at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:)
at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:)
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:)
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:)
at java.lang.reflect.Method.invoke(Method.java:)
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:)
at com.sun.proxy.$Proxy11.selectList(Unknown Source)
at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:)
at org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:)
at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:)
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:)
at com.sun.proxy.$Proxy17.getListWithUrlNotNull(Unknown Source)
at com.tg.ecs.system.service.impl.SysMenuService.getListWithUrlNotNull(SysMenuService.java:)
at com.tg.ecs.system.service.impl.SysMenuService.initFilterChain(SysMenuService.java:)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:)
at java.lang.reflect.Method.invoke(Method.java:)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:)
... more

看这个错误,应该是mybatis-spring的版本与mybatis不匹配的原因造成的。于是,我去maven上查看mybatis-spring支持的mybatis的版本,我选择mybatis-spring 1.2.5的版本:再次启动软件,上述mybatis-spring的错误解除。

到目前为止,我的研究环境,变成了mybatis 3.3.1,mybatis-spring 1.2.5. 继续后续研究!

在这个新的环境下,继续上述案例2的测试,在地址栏输入 http://10.90.9.20:8080/ecs/demo/foreach/usegeneratedkeys/insert1, 这次不再报错。所以,上面案例2的错误,还真是stackoverflow上人家描述的问题导致的。

4. useGeneratedKeys=”true“方案的插入,数据采用map传入,注意与案例3的不同,在于传入的数据,此处是纯map,collection就是一个注解指定名称了的map,而案例3中,foreach collection其实是map的key

mapper层的sql:

<insert id="foreachUseGeneratedKeysInsert3" useGeneratedKeys="true">
<!--
<selectKey resultType ="java.lang.Integer" keyProperty= "iid" order= "AFTER">
SELECT LAST_INSERT_ID()
</selectKey >
-->
insert into foreach_test (name, age, idx) values
<foreach item="dt" collection="map" index="key" open="(" separator="),(" close=")">
#{dt.name, jdbcType=VARCHAR}, #{dt.age, jdbcType=INTEGER}, #{key}
</foreach>
</insert>

dao层的接口:

int foreachUseGeneratedKeysInsert3(@Param("map") HashMap<Integer, Du> dumap);

java层的业务逻辑:

    @GET
@Path("/foreach/usegeneratedkeys/insert3")
public String foreachUseGeneratedKeysInsert3(@Context HttpServletRequest req){ List<Du> dud = new ArrayList<Du>();
HashMap<Integer, Du> dumap = new HashMap<Integer, Du>();
for(int i=; i < ; i++){
Du du = new Du();
du.setName("UseGeneratedKeys3" + i);
du.setAge(+i);
dud.add(du);
dumap.put(i, du);
}
int cnt = pes.foreachUseGeneratedKeysInsert3(dumap);
System.out.println(cnt); return "UseGeneratedKeys3 Insert OK";
}

在地址栏输入:

mysql> select * from foreach_test;
+----+---------------------+------+------+
| id | name | age | idx |
+----+---------------------+------+------+
| | UseGeneratedKeys332 | | |
| | UseGeneratedKeys331 | | |
| | UseGeneratedKeys330 | | |
+----+---------------------+------+------+
rows in set (0.00 sec)

这个案例:可以看出,传入map给mybatis时,foreach的collection,采用dao层接口注解指定的变量名,然后,index指的是map的key值,而item的内容,就是map中index所对应的key值指向的value,即du对象。

5. useGeneratedKeys=”true“方案的插入,数据采用array传入

mapper的sql:

<insert id="foreachUseGeneratedKeysInsert4" useGeneratedKeys="true">
insert into foreach_test (name, age, idx) values
<foreach item="dt" collection="array" index="seq" open="(" separator="),(" close=")">
#{dt.name, jdbcType=VARCHAR}, #{dt.age, jdbcType=INTEGER}, #{seq}
</foreach>
</insert>

dao接口:

 int foreachUseGeneratedKeysInsert4(Du[] duarray);

java应用层的逻辑:

    @GET
@Path("/foreach/usegeneratedkeys/insert4")
public String foreachUseGeneratedKeysInsert4(@Context HttpServletRequest req){ Du [] dud = new Du[];
for(int i=; i < dud.length ; i++){
Du du = new Du();
du.setName("UseGeneratedKeys4" + i);
du.setAge(+i);
dud[i] = du;
}
int cnt = pes.foreachUseGeneratedKeysInsert4(dud);
System.out.println(cnt); return "UseGeneratedKeys4 Insert OK";
}

在地址栏输入:

http://10.90.9.20:8080/ecs/demo/foreach/usegeneratedkeys/insert4

查看数据库得到下面的结果:

mysql> select * from foreach_test;
+----+--------------------+------+------+
| id | name | age | idx |
+----+--------------------+------+------+
| | UseGeneratedKeys40 | | |
| | UseGeneratedKeys41 | | |
| | UseGeneratedKeys42 | | |
| | UseGeneratedKeys43 | | |
+----+--------------------+------+------+
rows in set (0.00 sec)

上述运行一切正常,从结果来看:当传入mybatis的数据为Array时,collection的值默认就是array,除非在dao层通过注解@Param("xxx")指定其他名称。item的值为数组的元素,index的值为遍历数组的序号,从0开始,依次递增

6.foreach用于批量的查询

mapper的sql:

  <select id="foreachSelect" resultType="com.tg.ecs.ucc.model.Du">
select name, age from
foreach_test where idx in
<foreach item="st" collection="map" index="seq" open="(" separator="," close=")">
#{st, jdbcType=INTEGER}
</foreach>
</select>

dao接口:

List<Du> foreachSelect(@Param("map") HashMap<String, Integer> idxMap);

java的业务逻辑实现:

    @GET
@Path("/foreach/select")
public String foreachSelect(@Context HttpServletRequest req){ HashMap<String, Integer> idxMap = new HashMap<String, Integer>(); for(int i=; i<; i++){
idxMap.put("key" + i, i);
}
List<Du> res = pes.foreachSelect(idxMap);
for(Du du: res){
System.out.println(du.getName() + " -- " + du.getAge());
} return "Select OK";
}

运行web应用前,查看数据库内容:

mysql> select * from foreach_test;
+----+---------------------+------+------+
| id | name | age | idx |
+----+---------------------+------+------+
| | UseGeneratedKeys40 | | |
| | UseGeneratedKeys41 | | |
| | UseGeneratedKeys42 | | |
| | UseGeneratedKeys43 | | |
| | UseGeneratedKeys332 | | |
| | UseGeneratedKeys331 | | |
| | UseGeneratedKeys330 | | |
| | UseGeneratedKeys16 | | |
| | UseGeneratedKeys17 | | |
| | UseGeneratedKeys18 | | |
| | UseGeneratedKeys19 | | |
+----+---------------------+------+------+
rows in set (0.00 sec)

运行web应用,在地址栏输入:

http://10.90.9.20:8080/ecs/demo/foreach/select

eclipse控制台打印的结果:

UseGeneratedKeys40 --
UseGeneratedKeys41 --
UseGeneratedKeys42 --
UseGeneratedKeys43 --
UseGeneratedKeys16 --
UseGeneratedKeys17 --
UseGeneratedKeys18 --
UseGeneratedKeys19 --

结合上面的java代码和sql,输出结果是正确的。

最后,总结一下:

1. mybatis的insert操作,这里主要指批量插入操作,要注意键值的生成问题,对于mysql,有selectKey和useGeneratedKeys=“true”两种方案,例如本案例中,主键是auto_increment的,所以,用useGeneratedKeys=“true”相对简单(前提是数据库支持自动生成键值)。

2. foreach的使用,主要是搞清楚item,collection,index,open,separator,close几个属性的使用。其中,最最重要的是collection和index的含义。本博文中,针对collection支持的三种类型:list,array以及map都做了介绍,而map相对复杂点,原则上map支持任何参数的传入。要结合map的构造方式,以及dao层给map参数指定的参数名。对于map,collection的值若是map的key,则index是个序号,遍历map的次序编号;若collection的值给的是map,那么,index的值就是map的key,item的值就是key对于的value。

3. foreach中的open,separator以及close,配合使用,用于构造SQL语句。例如in指令的语句中,in后面是一个序列,所以习惯用open=“(”,separator=“,”,close=“)”。当然也不一定,这个的值,还和foreach标签体内的SQL的写法有关系。例如本博文案例2和案例3的这open,separator和close的值,就可以看出门道。

好了,本博文就到这里吧,若有什么需要探讨的,可以给我留言或者加好友讨论!

基于mysql对mybatis中的foreach进行深入研究的更多相关文章

  1. “mybatis 中使用foreach 传

    为了帮助网友解决“mybatis 中使用foreach 传”相关的问题,中国学网通过互联网对“mybatis 中使用foreach 传”相关的解决方案进行了整理,用户详细问题包括:mybatismap ...

  2. mybatis中的foreach条件参数过多时,#和$效率比较

    在客户端查询都小于1秒. 测试: mybatis中in条件12.3万数据$ : 6051 ms# : 27045 ms 1.2万数据$ : 1154 ms# : 24387 ms 5 万数据$ : 2 ...

  3. Mybatis中的foreach

    <delete id="deleteByParam"> DELETE FROM YZ_SECURITIES_CURRENCY WHERE ID IN <forea ...

  4. MySQL与MyBatis中的查询记录

    1.时间段查询 MySQL:select * from table where ctime >= CURDATE() and ctime <DATE_SUB(CURDATE(),INTER ...

  5. mybatis中的foreach方法

    select  t.service_id, t.prod_id, t.prod_name, t.prod_type, t.buss_type, t.pricing_fee, t.detail from ...

  6. Mybatis中的in查询和foreach标签

    Mybatis中的foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合. foreach元素的属性主要有 item,index,collection,open,separato ...

  7. mybatis中foreach使用

    mybatis中的<foreach collection="list" item="item" index="index" open= ...

  8. mybatis 中 foreach 的性能问题及调优

    1.mybatis中最初的sql语句 SELECT 参数1, 参数2, 参数3 FROM 表 WHERE 条件参数1 in <foreach item="item" inde ...

  9. mybatis中mysql和oracle的差异

    1.applicationContext.xml中的配置差异: 在applicationContext.xml的数据源dataSource的配置中,mysql数据库需要心跳包的配置,而oracle中不 ...

随机推荐

  1. HDU 6077 17多校4 Time To Get Up 水题

    Problem Description Little Q's clock is alarming! It's time to get up now! However, after reading th ...

  2. 【c++基础】c++提升速度的方法总结

    参考 1. C++程序提高运行速度的方法; 2. 提高C++程序运行效率的10个简单方法; 3. C++编程中提高程序运行效率的方式(不断更新); 完

  3. NOI-1.8-17-最好的草-矩阵找最大连接井号-【递归】

    17:最好的草 查看 提交 统计 提问 总时间限制:  10000ms 单个测试点时间限制:  1000ms 内存限制:  65536kB 描述 奶牛Bessie计划好好享受柔软的春季新草.新草分布在 ...

  4. Git忽略文件权限

    有时 git diff 执行显示文件内容没变化,但是git status却是一片姨妈红: 原因是文件的权限,被chmod变化了,这种变化也被 diff 识别出来了,git diff某个文件类似如下: ...

  5. Flask中的Templates

    1.什么是模板 模板 , 在Flask 中就是允许响应给用户看的网页 在模板中,允许包含"占位变量"来表示动态的内容 模板最终也会被解析成字符串再响应给客户端,这一过程通常称为&q ...

  6. [Algorithm] Good Fibonacci

    def good_fibonacci(n): if n<=1: return (n,0) else: (a,b)=good_fibonacci(n-1) return (a+b,a)

  7. day04之流程控制

    if语句: if 条件1: pass elif 条件2: pass elif 条件3: pass else: pass if 条件语句中,先判断条件1,如果满足条件1,则执行第二行代码,第二行执行完后 ...

  8. (11)线程池(最新的concurrent.futures包去开启)

    '''concurrent.futures是最新的开启线程池的包'''import timefrom concurrent.futures import ThreadPoolExecutor #开启线 ...

  9. 实验吧—隐写术——WP之 我喜欢培根

    打开解题链接: 有一点点基础的同学大概都知道这是摩尔斯电码,那么我们对他进行解密: 解密后得到: MORSEnullISnullCOOLnullBUTnullBACONnullISnullCOOLER ...

  10. 《DSP using MATLAB》Problem 5.37

    证明过程: 代码: %% +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ...