Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException——Mybatis批量处理错误处理

在进行批量处理的时候,在后台发现报错,日志部分如下:

bad SQL grammar []; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Syntax error:

出现了badSQlgrammar错误,在(某一个表中)出现了delete错误。
由于在批量操作的时候,我们是通过生成多条SQL语句,然后进行拼接,再用Mybatis进行处理,但是遇到了问题。

<update id="setWeiboEmotionByList" parameterType="java.util.List">
        <foreach collection="list" item="item" open="" close="" separator=";">
            UPDATE weibo_content
            SET
                EMOTION = #{item.emotion}
            WHERE
                WEIBO_ID = #{item.weibo_id}
        </foreach>
    </update>

类似上面的操作方式,使用foreach来对list中的语句进行拼接和遍历最后多条SQL语句进行执行
Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException——Mybatis批量处理错误处理
由上图所示,但是却触发了JDBC4 的MySQLSyntaxErrorException,经过资料查询,观察MySQLSyntaxErrorException实例:

public void create(Project project) throws IllegalArgumentException, DAOException {
	if (project.getProjectId() != 0) {
		throw new IllegalArgumentException("Project is already created, the project ID is not null.");
	}

	Object[] values = { project.getProjectNumber(), project.getProjectName(), 
			project.getActivity(), project.getPerNumber(),
			toSqlDate(project.getDate()), project.getTime()}; 
		
	try (Connection connection = daoFactory.getConnection();
		PreparedStatement statement = prepareStatement(connection, 
			SQL_INSERT_PROJECT, true, values);) {
		int affectedRows = statement.executeUpdate();
		if (affectedRows == 0) {
			throw new DAOException("Creating user failed, no rows affected.");
		}
		try (ResultSet generatedKeys = statement.getGeneratedKeys()) {
			if (generatedKeys.next()) {
				project.setProjectId(generatedKeys.getLong(1));
			} else {
				throw new DAOException("Creating user failed, no generated key obtained.");
			}
		}
	} catch (SQLException e) {
		throw new DAOException(e);
	}
}

可以看到,出错原因有大概如下原因:

  • 1、其中SQL语句有的出错导致。
  • 2、Mybatis中字段部分与SQl关键字冲突。
  • 3、由于是多条执行(delete xxx……;delete xxx……; delete xxx……;),可能Mybatis不能支持这种批量方式。
  • 4、对于参数传值的时候,使用"#{}“和使用”${}"传值时,会出现不同的问题。**

对这四种错误进行排查:

  • 通过在Navicat中执行每条SQL,发现并无报错,应该不是SQL语句有问题。
  • 在其他单条SQL语句处理和批量查找、批量更新都发现没有此问题。
  • Mybatis是默认不支持这种操作的,但是我们可以通过在mysql配置链接里加上allowMultiQueries参数并置为true。但是还是报同样的错误(也可能和服务器端的配置有关,需要进一步查看)。
  • 很明显全部使用的"#{}",当使用$时是默认无防注入的。其中#{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换。#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。
    sql{}表示拼接sql串,通过表示拼接sql串,通过{}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换,$ {}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,$ {}括号中只能是value。

究其原因(一般原因):

经过查找资料,发现大多数问题都是处在第三条上——对与adllowMultiQueries参数没有置为true,
但是,我们使用的是OceanBase的数据库,虽然理论上支持MySQL中的所有语句,但是在解决问题的两天后,我在阿里巴巴官方文档中看到了:

Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException——Mybatis批量处理错误处理
确实,这个问题解决了,但是下一个问题出现了:如何换一种方案呢

经过大佬们的商议,决定根据偏移量来进行Mybatis分段的批量操作,

后面继续谈。

上一篇:troubshooting-sqoop 导出 TiDB表数据报com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communicatio


下一篇:JDBC链接数据库MySQL 8.0 Public Key Retrieval is not allowed 错误的解决方法