jdbc 使用rewriteBatchedStatements=true后,报错

本文围绕jdbc使用rewriteBatchedStatements=true报错展开。介绍了该配置可让MySQL JDBC驱动重写SQL语句,减少与数据库通信次数,提高批量插入性能。但使用中添加超5条数据会报错,最终通过不使用该属性批量执行解决问题,不过具体原因未明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

jdbc 使用rewriteBatchedStatements=true后,报错了

rewriteBatchedStatements=true解释

    rewriteBatchedStatements=true是一个配置选项,它影响MySQL JDBC驱动程序的行为。JDBC是Java数据库连接的标准。当你使用Java程序连接MySQL数据库时,你需要使用这个驱动程序。

    rewriteBatchedStatements=true的意思是,当你在Java程序中使用批量插入(batching)时,MySQL JDBC驱动程序将尝试重新编写(rewrite)你的SQL语句,以便更有效地执行这些批量插入操作。

例如,假设你执行以下批量插入操作:

connection.addBatch("INSERT INTO table VALUES (1, 'a')");  
connection.addBatch("INSERT INTO table VALUES (2, 'b')");  
connection.addBatch("INSERT INTO table VALUES (3, 'c')");  
connection.executeBatch();

当rewriteBatchedStatements=true时,MySQL JDBC驱动程序将把你的SQL语句重新写成一个单一的批量插入语句,像这样:

INSERT INTO table (col1, col2) VALUES (1, 'a'), (2, 'b'), (3, 'c')

    这样做的好处是,你可以减少与数据库的通信次数,从而提高批量插入操作的性能。因为每次通信都会产生一些开销,所以通过将多个插入操作合并成一个单一的插入语句,你可以减少这些通信次数,从而提高性能。

使用场景

需要执行的sql

INSERT INTO 表名 (字段1, 字段2, 字段3, ..., 字段100)  
VALUES  
  (1,2,3, ...,100),  
  (11,12,13, ...,200),  
  ...  
  (55,992,993, ...,1000);
INSERT INTO 表名 (字段1, 字段2, 字段3, ..., 字段100)  
VALUES  
  (1,2,3, ...,100),  
  (11,12,13, ...,200),  
  ...  
  (55,992,993, ...,1000);
INSERT INTO 表名 (字段1, 字段2, 字段3, ..., 字段100)  
VALUES  
  (1,2,3, ...,100),  
  (11,12,13, ...,200),  
  ...  
  (55,992,993, ...,1000);
INSERT INTO 表名 (字段1, 字段2, 字段3, ..., 字段100)  
VALUES  
  (1,2,3, ...,100),  
  (11,12,13, ...,200),  
  ...  
  (55,992,993, ...,1000);
  ...

批处理代码

jdbcTemplate.batchUpdate(lines.toArray(new String[lines.size()]));

异常复现

当我向lines添加数据超过5条是,就会报异常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;降低到5个后就不报异常

问题解决

不再使用rewriteBatchedStatements属性,然后向lines添加多条,最后批量执行,我是添加了10000条,效率挺高。
不过具体原因还没有研究清楚。

### 后端运行时数据库表名大小写不兼容的解决方案 对于不同类型的数据库,在处理SQL语句以及对象名称(如表名、字段名)时存在显著差异。具体到MySQL、Oracle和PostgreSQL,这些数据库对待标识符大小写的策略有所不同。 #### MySQL中的表名大小写敏感性 在MySQL中,默认情况下,Linux上的表名是区分大小写的,而Windows上则不是[^1]。这意味着在同一操作系统环境下创建的两个仅大小写字母不同的表会被视为同一个实体;但在另一些环境中可能会被当作完全独立的对象来处理。因此当应用程序从一种环境迁移到另一种时就可能出现访问不到预期表格的情况。 为了确保跨平台的一致性和稳定性,建议采用统一的小写命名约定,并通过配置文件设置`lower_case_table_names=1`参数使得服务器忽略表名中的大写字母。 #### Oracle与PostgreSQL中的表名大小写规则 相比之下,Oracle默认会将未加双引号包裹的名字转换成全大写形式存储并识别它们。如果使用了双引号,则严格遵循所指定的形式保存下来,无论是小写还是混合大小写都会保持原样不变。 PostgreSQL也有类似的机制——无特殊字符修饰的情况下自动变为小写,一旦加上双引号就会按照输入的样子记录下来。 针对上述特性,在涉及多数据库支持的应用程序设计阶段就应该充分考虑到这一点: - **代码层面** - 使用ORM框架可以有效减少直接书写原始SQL带来的风险。例如JPA/Hibernate能够自动生成符合目标DBMS语法习惯的查询语句; ```java @Entity(name="users") // 将逻辑模型映射至物理结构时强制规定为特定格式 public class User { } ``` - **部署方面** - 如果无法更改现有架构或迁移数据源的话,那么可以在连接字符串里加入必要的选项让驱动程序帮助调整行为模式。比如某些版本的JDBC URL允许附加属性控制这一过程。 ```properties spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC&useInformationSchema=true&autoReconnect=true&failOverReadOnly=false&maxReconnects=10&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&useUnicode=yes&rewriteBatchedStatements=true&tinyInt1isBit=false&nullNamePatternMatchesAll=true&allowPublicKeyRetrieval=true&useLegacyDatetimeCode=false&cachePrepStmts=true&prepStmtCacheSize=250&prepStmtCacheSqlLimit=2048&elideSetAutoCommits=true&maintainTimeStats=false&sessionVariables=time_zone='+00:00'&useAffectedRows=true&noAccessToProcedureBodies=true&transformedBitIsBoolean=true&dontTrackOpenResources=true&defaultFetchSize=1000&alwaysSendSetIsolation=false&disableStatementPooling=true&reportMetricsIntervalMillis=-1&logger=com.mysql.cj.log.StandardLogger&profileSQL=false&enablePacketDebug=false&slowQueryThresholdNanos=0&traceProtocol=false&dumpQueriesOnException=false&loadBalanceBlacklistTimeout=5000&tcpKeepAlive=true&tcpRcvBuf=0&tcpSndBuf=0&socketTimeout=0&connectTimeout=0&interactiveClient=false&clientCertificateKeyStoreUrl=&clientCertificateKeyStorePassword=&trustServerCertificate=false&verifyServerCertificate=true&useSSL=true&requireSSL=false&useDefaultTimeZone=false&createDatabaseIfNotExist=false&includeInnodbStatusInDeadlockErrors=false&paranoid=false&pinGlobalTxToPhysicalConnection=false&retriesAllDown=false&roundRobinLoadBalance=false&secondsBeforeRetryMaster=30&initialTimeout=2&clearContextInfo=true&resetSession=false&overrideSupportsIntegrityEnhancementFacility=false&emulateUnsupportedPstmts=true&padCharsWithSpace=false&distinguishIdentifiersCase=false&ignoreNonTransactionTables=false&readOnlyPropagatesToServer=false&readFromPrimaryWhenFromSlaveFails=false&replicationEnableJMX=false&statementInterceptors=&queryInterceptors=&jdbcCompliantTruncation=true&yearIsDateType=true&noDatetimeStringSync=false&nullCatalogMeansCurrent=false&functionsNeverReturnStrings=false&tinyInt1isBit=true&strictFloatingPoint=false&emptyStringsConvertToZero=false&elideSetAutoCommits=false&useLocalTransactionState=false&rollbackOnPooledClose=false&netTimeoutForStreamingResults=0&getProceduresReturnsFunctions=false&metadataUseInfoSchema=false&metadataCapableOfDuplicateColumnName=false&includeInvisibleColumns=false&includeConfigurationProperties=false&includeThreadDumpInDeadlockExceptions=false&includeThreadNamesAsStatementComment=false&includeHostPortPairInToString=false&includeLastInsertIDInResultSet=false&includeRowIDInResultSet=false&includeTabledefsInMetadataSpooling=false&includeTimestampLabelInProfile=false&includeXidInCommitRollback=false&largeFileUploadBufferSize=0&localSocketAddress=&logSlowQueries=false&loginTimeout=0&lobBufferLength=1MB&lobStreamChunkSize=1KB&longStackTrace=true&manuallySpecifyMaxAllowedPacket=false&maxAllowedPacket=1GB&multiHostFailoverAttempts=0&numTriesBeforeBreak=3&packetDebugContents=FULL&passwordCharacterEncoding=UTF-8&pedantic=false&preferPrepare=false&processEscapeCodesForPrepStmts=true&propertyCycle=200&queriesBeforeRetryMaster=50&quickServerLossDetection=false&relaxAutoCommit=false&removeSTGfrom consideration=false&reportMetricsIntervalMillis=-1&resultSetSizeThreshold=0&sendFractionalSeconds=false&serverPreparedStatementCacheAccesses=0&serverPreparedStatementCacheMisses=0&serverPreparedStatementCacheSize=0&setCollationcharsetAtConnect=false&skipCheckForLatestVersion=false&smallResultSetsFirstFromSecondary=false&socketFactory=defaultSocketFactory&sslMode=PREFERRED&stripComments=false&tcpNoDelay=true&tinyInt1isBit=false&ultraDevHack=false&useAnsiQuotedIdentifier=false&useBlobToStoreUTF8OutsideBMP=false&useCompression=false&useCursorFetch=false&useDirectRowUnpack=false&useDynamicCharsetInfo=true&useFastIntParsing=true&useFastLongParsing=true&useFast prepared statement=true&useFullColumnNames=false&useHostsInPrivileges=false&useInformationSchema=false&useJDBCCompliantTimezoneShift=false&useJvmCharsetConverters=false&useLocalSessionState=false&useNanosForElapsedTime=false&useOldAliasMetadataBehavior=false&useOnlyServerErrorMessages=false&useReadAheadInput=false&useSSPSCompatibleTimezone=false&useServerPreparedStmts=false&useServerPreparedStmtsWithoutLimits=false&useSSL=false&useStreamLengthsInPrepStmts=true&useTimezone=false&useUltraDevWorkAround=false&useUnbufferedInputStream=false&useUsageAdvisor=false&verbose=false&waitTimeout=28800&writeTimeout=0 ``` 此URL片段展示了如何利用额外参数影响客户端的行为方式,其中部分选项可能有助于缓解由于大小写引起的兼容性难题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值