鉴于上一篇博文一次修改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. python day09作业

  2. 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 ...

  3. calc() --- css3

    http://www.w3cplus.com/css3/how-to-use-css3-calc-function.html

  4. 大数据-03-Spark入门

    Spark 简介 行业广泛使用Hadoop来分析他们的数据集.原因是Hadoop框架基于一个简单的编程模型(MapReduce).这里,主要关注的是在处理大型数据集时在查询之间的等待时间和运行程序的等 ...

  5. ORACLE函数、连接查询、约束

    *ORDER BY 子句在SELECT语句的结尾. 使用外连接可以查询不满足连接条件的数据 with字句 字符函数lower upper initcap concat substr length in ...

  6. 2.3 xpath定位

    2.3 xpath定位 前言    在上一篇简单的介绍了用工具查看目标元素的xpath地址,工具查看比较死板,不够灵活,有时候直接复制粘贴会定位不到.这个时候就需要自己手动的去写xpath了,这一篇详 ...

  7. centos7 安装mysql--python模块出现EnvironmentError: mysql_config not found和error: command 'gcc' failed with exit status 1

    要想使python可以操作mysql 就需要MySQL-python驱动,它是python 操作mysql必不可少的模块. 下载地址:https://pypi.python.org/pypi/MySQ ...

  8. 增加临时表空间组Oracle11g单实例

    #需求,测试库与生产库,临时表空间同步一致 #经过查询生产环境,数据库默认临时表空间,为临时表空间组,有三个成员,三个临时表空间,每个临时表空间一个数据文件,自动扩展 #使用临时表空间组的优点,减少不 ...

  9. 求强连通分量Tarjan算法

    ]; // 时间戳 ; // 时间 ]; // 节点u所能访问到的最小时间戳 ]; // 节点u是否在栈中. ]; ; // 我们维护的信息. ]; // 给节点染色, 同一个连通块的节点应该是同一个 ...

  10. 苹果手机不兼容autoplay属性

    var audio=new Audio("music/music.mp3"); audio.preload="preload"; // 自动播放解决苹果不兼容a ...