解决mybatis使用foreach批量insert异常的问题

异常

org.springframework.jdbc.BadSqlGrammarException:
### Error updating database. Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INSERT INTO t_user_role(userid,roleid)VALUES(1,3)
		 ;
			INSERT INTO t_user_ro' at line 3
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: INSERT INTO t_user_role(userid,roleid)VALUES(?,?) ;  INSERT INTO t_user_role(userid,roleid)VALUES(?,?) ;  INSERT INTO t_user_role(userid,roleid)VALUES(?,?)
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INSERT INTO t_user_role(userid,roleid)VALUES(1,3)
		 ;
			INSERT INTO t_user_ro' at line 3
; bad SQL grammar []; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INSERT INTO t_user_role(userid,roleid)VALUES(1,3)
		 ;
			INSERT INTO t_user_ro' at line 3
	at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:231)
	at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73)
	at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:73)
	at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:371)
	at com.sun.proxy.$Proxy13.insert(Unknown Source)
	at org.mybatis.spring.SqlSessionTemplate.insert(SqlSessionTemplate.java:240)
	at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:51)
	at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:52)
	at com.sun.proxy.$Proxy14.addRoles(Unknown Source)
	at com.atguigu.atcrowdfunding.manager.service.impl.UserServiceImpl.addRoles(UserServiceImpl.java:139)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
	at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
	at com.sun.proxy.$Proxy17.addRoles(Unknown Source)
	at com.atguigu.atcrowdfunding.manager.controller.UserController.doAddRoles(UserController.java:271)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:175)
	at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:446)
	at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:434)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:945)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:876)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:931)
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:833)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:807)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:673)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1526)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1482)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Unknown Source)
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INSERT INTO t_user_role(userid,roleid)VALUES(1,3)
		 ;
			INSERT INTO t_user_ro' at line 3
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
	at java.lang.reflect.Constructor.newInstance(Unknown Source)
	at com.mysql.jdbc.Util.handleNewInstance(Util.java:404)
	at com.mysql.jdbc.Util.getInstance(Util.java:387)
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:941)
	at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3870)
	at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3806)
	at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2470)
	at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2617)
	at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2550)
	at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1861)
	at com.mysql.jdbc.PreparedStatement.execute(PreparedStatement.java:1192)
	at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.execute(NewProxyPreparedStatement.java:823)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at org.apache.ibatis.logging.jdbc.PreparedStatementLogger.invoke(PreparedStatementLogger.java:62)
	at com.sun.proxy.$Proxy24.execute(Unknown Source)
	at org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:44)
	at org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:69)
	at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:48)
	at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:105)
	at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:71)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:152)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:141)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:358)
	... 65 more

异常分析

mapper.xml导致的错误地方

 <insert id="addRoles">
 <foreach collection="data.ids" item="id" separator=";">
 INSERT INTO t_user_role(userid,roleid)VALUES(#{userId},#{id})
 </foreach>
 </insert>

异常中说

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INSERT INTO t_user_role(userid,roleid)VALUES(1,3)

首先觉得是 sql语句的问题,但是用sqlyog测试发现没有问题

后来发现是数据库对多个语句拼在一起的操作不支持问题

解决办法

在jdbcUrl中加入allowMultiQueries=true即可解决

jdbc.url=jdbc:mysql://localhost:3306/atcrowdfunding?allowMultiQueries=true&rewriteBatchedStatements=true&useUnicode=true&characterEncoding=utf8

补充:Mybatis foreach嵌套 批量insert map list数据

方式一:

以Teacher和Students为例 ,两者为一对多关系:**

Teacher 实体类

private String tid;
private String tName;
private List<Student> studentList;
public String getTid() {
 return tid;
}

public void setTid(String tid) {
 this.tid = tid;
}

public String gettName() {
 return tName;
}

public void settName(String tName) {
 this.tName = tName;
}

public List<Student> getStudentList() {
 return studentList;
}

public void setStudentList(List<Student> studentList) {
 this.studentList = studentList;
}

Student实体类

private String sid;
private String sName;
public String getSid() {
 return sid;
}

public void setSid(String sid) {
 this.sid = sid;
}

public String getsName() {
 return sName;
}

public void setsName(String sName) {
 this.sName = sName;
}

应用场景 :在老师的service层批量插入老师数据

int nums=1000;

 //定义teacher list
 List<Teacher> teaList=new ArrayList<Teacher>();
 //数据是通过excel读取的 此处模拟循环读取excel row数据
 for(int rowi=0;rowi<nums;rowi++){
  Teacher teacher=new Teacher();
  teacher.settName("xxx");

  List<Student> stuList=new ArrayList<Student>();
  Student student=new Student();
  //此处获取Students集合
  for(xxx){
   stuList.add(student);
  }
  //把student集合和teacher绑定
  teacher.setStudentList(stuList);

  //把teacher放入list
  teaList.add(teacher);
 }
 // 批量插入老师数据
 teacherMapper.batchInsertTeacher(teaList);
 //此时每个teacher对象都有返回的主键id值
 //老师主键 对应一个list(学生信息) map
 Map<String,List<Student>> stuMap=new HashMap<>();
 //填入数据 老师主键一对多学生信息
 for(Teacher tea:teaList){
  //非空判断 避免老师没有对应学生的情况(此处只进行逻辑处理 不考虑现实中老师没有学生)
  if(tea.getStudentList()!=null&&tea.getStudentList().size()>0){
   stuMap.put(tea.getTid(),tea.getStudentList());
  }
 }
 //调用学生service的批量保存学生方法
 studentService.batchInsertStudent(stuMap);

student Mapper接口文件

int batchInsertStudent(@Param("stuMap") Map<String,List<Student>> stuMap);

student mapper.xml文件(写法一:)

<insert id="batchInsertStudent" parameterType="java.util.Map">
 INSERT INTO bs_student (sid,sName,tid)
 values
 <foreach collection="stuMap.keys" index="key" item="itemKey" separator=",">
   <foreach collection="stuMap[itemKey]" index="index_list" item="list" separator="," >
    ( (select REPLACE(UUID(),'-','') AS sid) ,#{list.sName},#{itemKey} )
   </foreach>
 </foreach>
</insert>

student mapper.xml文件(写法二:)

<insert id="batchInsertStudent" >
  INSERT INTO bs_student (sid,sName,tid)
  <foreach collection="stuMap.keys" index="index" item="itemKey" separator="UNION ALL">
  <foreach collection="stuMap[itemKey]" index="index_list" item="list" separator="UNION ALL">
      (
      SELECT
      (select REPLACE(UUID(),'-','') AS sid)
      ,#{list.sName}
      ,#{itemKey}
      FROM DUAL
      )
  </foreach>
  </foreach>
</insert>

stuMap:就是在接口中使用@Param(“stuMap”)标注了变量;

使用stuMap.keys可以取到所有的key,遍历。

内层循环中使用stuMap[itemKey]类似stuMap.get(“key”)取当前key对应的value值。由于value是list所以还需要遍历。

结果保存成功。再次膜拜强大的Mybatis。

至此 成功插入student数据。

方式二(推荐):

自定义类

class EnclosingType{
 private String uuid;
 private List<ElementType> elements;
}
class ElementType{
 String a;
 String b;
 (...)
}

Mapper.xml(方法一)

<mapper namespace="my.example.ElementType">
 <insert id="insertElements" parameterType="EnclosingType">
  INSERT INTO table1(enclosingTypeId,column_a,column_b)
  VALUES
  <foreach collection="elements" index="index" item="list" separator=",">
   (
   #{uuid,jdbcType=VARCHAR}
   ,#{list.a,jdbcType=VARCHAR}
   ,#{list.b,jdbcType=VARCHAR}
   )
  </foreach>
 </insert>
</mapper>

Mapper.xml(方法二)

<mapper namespace="my.example.ElementType">
 <insert id="insertElements" parameterType="EnclosingType">
  INSERT INTO table1(enclosingTypeId,column_a,column_b)
  <foreach collection="elements" index="index" item="list" separator="union all">
   (
   select #{uuid,jdbcType=VARCHAR}
   ,#{list.a,jdbcType=VARCHAR}
   ,#{list.b,jdbcType=VARCHAR}
   from dual
   )
  </foreach>
 </insert>
</mapper>

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。如有错误或未考虑完全的地方,望不吝赐教。

(0)

相关推荐

  • Mybatis动态SQL foreach标签用法实例

    需求:传入多个 id 查询用户信息,用下边两个 sql 实现: SELECT * FROM USERS WHERE username LIKE '%张%' AND (id =10 OR id =89 OR id=16) SELECT * FROM USERS WHERE username LIKE '%张%' AND id IN (10,89,16) 这样我们在进行范围查询时,就要将一个集合中的值,作为参数动态添加进来. 这样我们将如何进行参数的传递? 1.实体类 public class Qu

  • mybatis3.4.6 批量更新 foreach 遍历map 的正确姿势详解

    好久没编码了!最近开始编码遇到一个问题 !一个批量修改的问题,就是mybatis foreach 的使用. 当时使用的场景 ,前端 传逗号拼接的字符串id, 修改id对应数据的数据顺序 ,顺序 就是id 的顺序. 就是一个条件(单个id值) 修改一个值(传入的id的顺序) , 1. 把条件作为Map 的key 修改值是value,用map入参 2.用List<Object> 或者数组 ,把条件和值封装成对象放进list集合或者array数组 3.代码使用for循环调用mapper方法 穿两个参

  • mybatis使用foreach语句实现IN查询(三种)

    foreach语句中, collection属性的参数类型可以使:List.数组.map集合 collection: 必须跟mapper.java中@Param标签指定的元素名一样 item : 表示在迭代过程中每一个元素的别名,可以随便起名,但是必须跟元素中的#{}里面的名称一样. index :表示在迭代过程中每次迭代到的位置(下标) open :前缀, sql语句中集合都必须用小括号()括起来 close :后缀 separator :分隔符,表示迭代时每个元素之间以什么分隔 Mybati

  • Oracle+Mybatis的foreach insert批量插入报错的快速解决办法

    最近做一个批量导入的需求,将多条记录批量插入数据库中. 解决思路:在程序中封装一个List集合对象,然后把该集合中的实体插入到数据库中,因为项目使用了MyBatis,所以打算使用MyBatis的foreach功能进行批量插入.期间遇到了"SQL 命令未正确结束 "的错误,最终解决,记录下来供以后查阅和学习. 首先,在网上参考了有关Mybatis的foreach insert的资料,具体如下: foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合. foreach

  • mybatis-plus  mapper中foreach循环操作代码详解(新增或修改)

    .循环添加 接口处: 分别是 void 无返回类型 :有的话是(resultType)返回类型,参数类型(parameterType) list , 如: 在mapper文件中分别对应ID,参数类型和返回类型. 循环处理,如下: <insert id="insertPack" parameterType="java.util.List"> insert into t_ev_bu_pack ( PACK_CODE, BIN, PACK_PROD_TIME,

  • 解决mybatis批量更新(update foreach)失败的问题

    如下所示: <!--批量更新报表 --> <update id="updateIssueByBatch" parameterType="java.util.List"> <foreach collection="issueList" item="item" index="index" separator=";"> update sys_issue &l

  • 解决mybatis使用foreach批量insert异常的问题

    异常 org.springframework.jdbc.BadSqlGrammarException: ### Error updating database. Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version fo

  • 解决Mybatis中foreach嵌套使用if标签对象取值的问题

    目录 foreach嵌套使用if标签对象取值问题 大体格式 解决办法 代码如下 Mybatis if 语句嵌套 要求 foreach嵌套使用if标签对象取值问题 最近做项目过程中,涉及到需要在 Mybatis 中 使用 foreach 进行循环读取传入的查询条件,动态拼接SQL语句,接口传入的查询条件格式:{"advanceSearchList":[{"searchType":10,"searchText":"12"}]} ,

  • 解决Mybatis 大数据量的批量insert问题

    前言 通过Mybatis做7000+数据量的批量插入的时候报错了,error log如下: , ('G61010352', '610103199208291214', '学生52', 'G61010350', '610103199109920192', '学生50', '07', '01', '0104', ' ', , ' ', ' ', current_timestamp, current_timestamp ) 被中止,呼叫 getNextException 以取得原因. at org.p

  • mybatis foreach批量插入数据:Oracle与MySQL区别介绍

    下面给大家介绍mybatis foreach批量插入数据:Oracle与MySQL不同点: •主要不同点在于foreach标签内separator属性的设置问题: •separator设置为","分割时,最终拼接的代码形式为:insert into table_name (a,b,c) values (v1,v2,v3) ,(v4,v5,v6) ,... •separator设置为"union all"分割时,最终拼接的代码形式为:insert into table

  • oracle+mybatis 使用动态Sql当插入字段不确定的情况下实现批量insert

    最近做项目遇到一个挺纠结的问题,由于业务的关系,DB的数据表无法确定,在使用过程中字段可能会增加,这样在insert时给我造成了很大的困扰. 先来看一下最终我是怎么实现的: <insert id="batchInsertLine" parameterType="HashMap"> <![CDATA[ INSERT INTO tg_fcst_lines(${lineColumn}) select result.*,sq_fcst_lines.next

  • Mybatis动态SQL foreach批量操作方法

    目录 动态SQL Foreach批量操作 前言 前置必要知识 MySQL批量插入 MySQL批量查询 MySQL批量修改 MySQL批量删除 使用mybatis中的foreach进行批量操作 foreach标签的各个属性 批量插入 批量查询 批量修改 批量删除 总结 动态SQL Foreach批量操作 前言 最近正在研究Mybatis的动态SQL,正好学习到了foreach元素.之前也是在项目开发中经常会使用到Mybatis的foreach元素进行批量操作.但是有时候就会使用出错,所以整理和总结

  • 解决Mybatis中mapper.xml文件update,delete及insert返回值问题

    最近写了几个非常简单的接口(CRUD),在单元测试的时候却出了问题,报错如下: Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'messageListener': Unsatisfied dependency expressed through field 'reviewCheckInfoService'; nested exce

  • mybatis报Query was Empty异常的问题

    目录 mybatis报QuerywasEmpty异常 mybatis批量更新出现QuerywasEmpty mybatis报Query was Empty异常 mybatis中的<foreach>标签在批处理的时候经常要使用到,而使用<foreach>避免不了的就是要对list进行非空判断,否则很容易出错. 今天我在批量插入时,我的代码是这样的 <if test="list!=null and list.size>0>    insert into ta

随机推荐