java.sql.BatchUpdateException: 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 '('1512144017', 'quqiang01' at line 1
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)
at com.mysql.jdbc.Util.getInstance(Util.java:408)
at com.mysql.jdbc.SQLError.createBatchUpdateException(SQLError.java:1162)
at com.mysql.jdbc.PreparedStatement.executeBatchedInserts(PreparedStatement.java:1587)
at com.mysql.jdbc.PreparedStatement.executeBatchInternal(PreparedStatement.java:1253)
at com.mysql.jdbc.StatementImpl.executeBatch(StatementImpl.java:970)
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 '('1512144017', 'quqiang01' at line 1
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)
at com.mysql.jdbc.Util.getInstance(Util.java:408)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:943)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3973)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3909)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2527)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2680)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2487)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1858)
at com.mysql.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2079)
at com.mysql.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2013)
at com.mysql.jdbc.PreparedStatement.executeLargeUpdate(PreparedStatement.java:5104)
at com.mysql.jdbc.PreparedStatement.executeBatchedInserts(PreparedStatement.java:1548)
... 5 more

最近在使用JDBC的时候,一个比较坑的细节,就是关于他里面使用PreparedStatement或者Statement 的 addBatch()/executeBatch()的具体实现问题;

不要手贱在你传入的sql语句没末尾加上分号;

具体是这样:

 //以一个批量提交的实现工具举例
// List<List<Object>> lists: 所有数据的list
// List<Object>:单条数据"值"的list public void batchExecutePstamt(String sql, List < List < Object >> lists) {
try {
connection.setAutoCommit(false);
pstmt = connection.prepareStatement(sql);
if (lists != null && !lists.isEmpty()) {
for (List < Object > cList: lists) {
if (cList == null || cList.isEmpty())
continue; for (int i = 0; i < cList.size(); i++) {
pstmt.setObject(i + 1, cList.get(i));
}
pstmt.addBatch();
}
log.info(pstmt.toString());
pstmt.executeBatch();
connection.commit();
}
} catch (SQLException e) {
e.printStackTrace();
}
}

在这里,我们传入大量的需要插入的对象的List<List<Object>>,里面的 List<Object> 就是某一条具体的记录的值;

如果你调用的时候, 在传入sql的时候, 传入了类似于  insert into `tablename` (name,age) values (?,?); 的sql语句
那么他每次addBatch的时候就会在
com.mysql.jdbc.PreparedStatement.addBatch()的创建com.mysql.jdbc.PreparedStatement.BatchParams 然后放进batchedArgs 静态列表里面

  public void addBatch() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
if (this.batchedArgs == null) {
this.batchedArgs = new ArrayList<Object>();
} for (int i = 0; i < this.parameterValues.length; i++) {
checkAllParametersSet(this.parameterValues[i], this.parameterStreams[i], i);
} this.batchedArgs.add(new BatchParams(this.parameterValues, this.parameterStreams, this.isStream, this.streamLengths, this.isNull));
}
}

addBatch()

  public class BatchParams {
public boolean[] isNull = null; public boolean[] isStream = null; public InputStream[] parameterStreams = null; public byte[][] parameterStrings = null; public int[] streamLengths = null; BatchParams(byte[][] strings, InputStream[] streams, boolean[] isStreamFlags, int[] lengths, boolean[] isNullFlags) {
//
// Make copies
//
this.parameterStrings = new byte[strings.length][];
this.parameterStreams = new InputStream[streams.length];
this.isStream = new boolean[isStreamFlags.length];
this.streamLengths = new int[lengths.length];
this.isNull = new boolean[isNullFlags.length];
System.arraycopy(strings, 0, this.parameterStrings, 0, strings.length);
System.arraycopy(streams, 0, this.parameterStreams, 0, streams.length);
System.arraycopy(isStreamFlags, 0, this.isStream, 0, isStreamFlags.length);
System.arraycopy(lengths, 0, this.streamLengths, 0, lengths.length);
System.arraycopy(isNullFlags, 0, this.isNull, 0, isNullFlags.length);
}
} PreparedStatement batchedStatement = null;

BatchParams

然后会在最后使用executeBatch()的时候处理 batchedArgs中的 数据

处理的步骤为:
>> com.mysql.jdbc.StatementImpl.executeBatch()
>> com.mysql.jdbc.PreparedStatement.executeBatchInternal()
这里回去判断你设置的一些参数, 比如connection.getRewriteBatchedStatements(), 这个有助于批量数据处理的参数, 需要在jdbc.url连接中设置 rewriteBatchedStatements = true, 不过好像只针对于某个版本(5.2 ?不确定 )以后的数据操作性能有帮助.
在这里会进入一个将多个PreparedStatement转化为 BLUK 模式的一条语句;(bluk模式不知道的请自行百度)

>> com.mysql.jdbc.PreparedStatement.executeBatchedInserts(int)

这里面有一段源码:

 PreparedStatement batchedStatement = null;

 int batchedParamIndex = 1;
long updateCountRunningTotal = 0;
int numberToExecuteAsMultiValue = 0;
int batchCounter = 0;
CancelTask timeoutTask = null;
SQLException sqlEx = null; long[]updateCounts = new long[numBatchedArgs];
//上面不多说 try {
//这句会把初始化我们传进来的sql
//我们传进来的是类似于 insert into tablename (columns…) values (?,?...)这种
//到这里相当于初始化成 INSERT INTO tablename` (`name`, `age`) values (** NOT SPECIFIED **, ** NOT SPECIFIED **);
//然后他会根据顺序传进我们上面所传进的多个已经赋值的PreparedStatement,
batchedStatement = /* FIXME -if we ever care about folks proxying our MySQLConnection */
prepareBatchedInsertSQL(locallyScopedConn, numValuesPerBatch); if (locallyScopedConn.getEnableQueryTimeouts() && batchTimeout != 0 && locallyScopedConn.versionMeetsMinimum(5, 0, 0)) {
timeoutTask = new CancelTask(batchedStatement);
locallyScopedConn.getCancelTimer().schedule(timeoutTask, batchTimeout);
} if (numBatchedArgs < numValuesPerBatch) {
numberToExecuteAsMultiValue = numBatchedArgs;
} else {
numberToExecuteAsMultiValue = numBatchedArgs / numValuesPerBatch;
} int numberArgsToExecute = numberToExecuteAsMultiValue * numValuesPerBatch; for (int i = 0; i < numberArgsToExecute; i++) {
if (i != 0 && i % numValuesPerBatch == 0) {
try {
updateCountRunningTotal += batchedStatement.executeLargeUpdate();
} catch (SQLException ex) {
sqlEx = handleExceptionForBatch(batchCounter - 1, numValuesPerBatch, updateCounts, ex);
} getBatchedGeneratedKeys(batchedStatement);
batchedStatement.clearParameters();
batchedParamIndex = 1; }
//@see 这里是关键
//@see 如果还有后续的PreparedStatement,根据后面的一个参数,那么他就会将batchedStatement设置为:
// INSERT INTO tablename` (`name`, `age`) values("名字1",'23'), (** NOT SPECIFIED **, ** NOT SPECIFIED **); //@see 问题就在这里
//@see 如果你传入的sql :" insert into tablename (columns…) values (?,?...);"是这样的,那么生成的单条语句以及单个PreparedStatement没有任何问题,你拿到数据库执行去也OK
//@see 但是他现在要给你转为BLUK模式的,如果你结尾带了分号,语句就会变成:
// INSERT INTO tablename` (`name`, `age`) values("名字1",'23');, (** NOT SPECIFIED **, ** NOT SPECIFIED **);然后等待下一次填充参数
//@see 多的这个分号就是导致sql语句错误的原因 //@see 有兴趣可以进源码的这个方法看看
batchedParamIndex = setOneBatchedParameterSet(batchedStatement, batchedParamIndex, this.batchedArgs.get(batchCounter++));
} try {
updateCountRunningTotal += batchedStatement.executeLargeUpdate();
} catch (SQLException ex) {
sqlEx = handleExceptionForBatch(batchCounter - 1, numValuesPerBatch, updateCounts, ex);
} getBatchedGeneratedKeys(batchedStatement); numValuesPerBatch = numBatchedArgs - batchCounter;
}
finally {
if (batchedStatement != null) {
batchedStatement.close();
batchedStatement = null;
}
}

关于JDBC的批量操作executeBatch()所引发sql语句异常的更多相关文章

  1. 10.1(java学习笔记)JDBC基本操作(连接,执行SQL语句,获取结果集)

    一.JDBC JDBC的全称是java database connection java数据库连接. 在java中需要对数据库进行一系列的操作,这时就需要使用JDBC. sun公司制定了关于数据库操作 ...

  2. executeBatch()批量执行Sql语句

    executeBatch()方法:用于成批地执行SQL语句,但不能执行返回值是ResultSet结果集的SQL语句,而是直接执行stmt.executeBatch(); addBatch():向批处理 ...

  3. jmert jdbc request支持执行多条sql语句并设置jdbc字符集

    1.jdbc request支持执行多条sql语句 在JDBC Connection Configuration中的sql连接字串中添加如下内容 allowMultiQueries=true 如下图: ...

  4. [疯狂Java]JDBC:PreparedStatement预编译执行SQL语句

    1. SQL语句的执行过程——Statement直接执行的弊病: 1) SQL语句和编程语言一样,仅仅就会普通的文本字符串,首先数据库引擎无法识别这种文本字符串,而底层的CPU更不理解这些文本字符串( ...

  5. 关于No Dialect mapping for JDBC type :-9 hibernate执行原生sql语句问题

    转自博客http://blog.csdn.net/xd195666916/article/details/5419316,同时感谢博主 今天做了个用hibernate直接执行原生sql的查询,报错No ...

  6. 执行sql语句异常...需要的参数与提供的值个数不匹配

    执行mysql语句时,出现以下错误时. 看错误提示,提示说你的sql语句只需要5个参数,而你提供了8个值value,你确定你确实需要8个参数,而你的sql语句却提示说只需要5个参数 这时,请仔细检查一 ...

  7. sql语句异常向数据库插入数据报错

    在php编程向数据库插入数据时报如下错误: [Err] 1064 - You have an error in your SQL syntax; check the manual that corre ...

  8. sql语句 异常 Err] 1064 - You have an error in your SQL syntax;

    在我们开发的工程中,有时候会报[Err] 1064 - You have an error in your SQL syntax; check the manual that corresponds ...

  9. jdbc获取PreparedStatement最终执行的sql语句

    //直接打印PreparedStatement对象 System.out.println(ps); 输出结果: com.mysql.jdbc.JDBC42PreparedStatement@5f205 ...

随机推荐

  1. 【原创】Java基础之Freemarker(1)模板加载及清空机制

    一 freemarker加载模版机制 freemarker中的配置项template_update_delay表明模版的缓存时间,单位是s,超过缓存时间则从磁盘加载最新的模版,具体细节如下: 1)fr ...

  2. 【原创】大叔经验分享(44)hdfs副本数量

    当hdfs空间不足时,除了删除临时数据或垃圾数据之外,还可以适当调整部分大目录的副本数量,多管齐下: 1 查看 $ hdfs dfs -ls /user/hive/warehouse/temp.db/ ...

  3. Python--map()函数

    map()是 Python 内置的高阶函数,它接收一个函数 f 和一个 list,并通过把函数 f 依次作用在 list 的每个元素上,得到一个新的 list 并返回. 例如,对于list [1, 2 ...

  4. 第二章:Linux 基础篇章

    一.shell 在系统中,人所输入到系统内部的命令,以字符类型的形式输入刡系统当中,然而系统 只识别2进制码,就如以前 doc 界面为例,输入的都是字符类的英文字母作为输入的命令代 码,然 而明显二进 ...

  5. 绑定bindchange事件的微信小程序swiper闪烁,抖动问题解决,(将微信小程序切换到后台一段时间,再打开微信小程序,会出现疯狂循环轮播,造成抖动现象)

    微信小程序开发文档-组件-swiper后面追加的新闻如上图所示: 如果在bindchange事件给swiper的current属性对应的值{{current}}赋值,就会造成抖动现象. bindcha ...

  6. Java_数据类型

    变量就是申请内存来存储值. java的两大数据类型:内置数据类型和引用数据类型 数据类型 6种数据类型(4种整数型,2种浮点型),一种字符类型,一种布尔类型 数据类型 位数 描述 byte 8位 -1 ...

  7. 爬虫请求库之selenium模块

    一 安装 #安装:selenium+chromedriver pip3 install selenium 下载chromdriver.exe放到python安装路径的scripts目录中即可,注意最新 ...

  8. 2018秋季C语言学习总结

    2018秋季开始学习c语言 1.printf格式化输出函数 2.基本数据类型,int整型,float浮点型,double双精度浮点型,char字符型 3.算数运算符 +加法,-减法,*乘法,/除法,% ...

  9. 寻找符合条件的最短子字符串——SLIDING WINDOW

    简介 用一个可伸缩的窗口遍历字符串,时间复杂度大致为O(n).适用于“寻找符合某条件的最小子字符串”题型. 题目 链接 求某字符串T中含有某字符串S的所有字符的最小子字符串.如果不存在则返回" ...

  10. 解决使用maven的java web项目导入后出现的有关问题 -cannot be read or is not a valid ZIP file

    解决使用maven的java web项目导入后出现的有关问题 -cannot be read or is not a valid ZIP file   错误问题:虽然查找repository目录下是有 ...