解决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>

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

以上是 解决mybatis使用foreach批量insert异常的问题 的全部内容, 来源链接: utcz.com/z/347676.html

回到顶部