PostgreSQL插入失败报‘信息中剩下的数据不够’问题求助
问题排查:PostgreSQL插入时"信息中剩下的数据不够"错误
错误原因分析
SQL字符串拼接的致命问题
你当前直接通过字符串拼接生成SQL语句,当plcQRCode包含特殊字符(比如单引号'、换行符、转义字符)时,会直接破坏SQL语句的语法结构。比如如果plcQRCode的值是O'Neil,拼接后会变成'O'Neil',这会导致SQL解析时出现语法错误,PostgreSQL会因无法正确解析完整语句而抛出"信息中剩下的数据不够"的错误。
虽然日志中显示的是空格,但偶尔出现的问题大概率是某些边缘场景下的特殊字符未被处理导致的。数据库连接的并发安全问题
从DB对象的实现来看,conn是全局共享的单例连接。如果多个线程同时调用executeSql方法,共享同一个Connection对象创建Statement,会导致并发冲突,发送给PostgreSQL的SQL指令可能被截断、混乱,从而引发解析错误。
解决方案
1. 立即改用PreparedStatement替代字符串拼接
这是解决问题的核心,同时能彻底避免SQL注入风险:
class PlcMeasure(val position:Int, val plcFlow:Int, val plcLong:Int, val plcShort:Int, val plcThickness:Int, val plcQRCode: String, val enterTime: Date ) { init { if (!DB.loading) { DB.executePreparedSql( "INSERT INTO plc_measure (position, plcFlow, plcQrcode, plcLong, plcShort, plcThickness, enterTime) " + "VALUES (?, ?, ?, ?, ?, ?, ?)", position, plcFlow, plcQRCode, plcLong, plcShort, plcThickness, enterTime.time ) Publisher.publish("NEW PlcMeasure $position $plcFlow") } } } object DB { fun executePreparedSql(sql: String, vararg params: Any, logit: Boolean = true) { if (logit) { Logger.I("SQL $sql | Params: ${params.joinToString(", ")}") } try { conn.use { connection -> connection.prepareStatement(sql).use { stmt -> stmt.queryTimeout = 10 params.forEachIndexed { index, param -> when (param) { is Int -> stmt.setInt(index + 1, param) is Long -> stmt.setLong(index + 1, param) is String -> stmt.setString(index + 1, param) // 按需添加其他类型的处理 } } stmt.execute() } } } catch (e: Exception) { Logger.E("SQL error:${e.message}: ${sql} | Params: ${params.joinToString(", ")}") } } }
2. 确保数据库连接的线程安全
- 不要使用全局单例
Connection,改用数据库连接池(比如HikariCP)管理连接,每次操作从连接池获取独立连接,使用后归还。 - 如果必须使用单例连接,要添加同步锁,避免多线程并发调用:
fun executePreparedSql(sql: String, vararg params: Any, logit: Boolean = true) { synchronized(conn) { // 原有逻辑 } }
关于PostgreSQL的可靠性
PostgreSQL是经过数十年验证的工业级关系型数据库,广泛应用于金融、电商、政务等核心业务场景,可靠性完全有保障。你遇到的错误完全是应用代码的问题,和数据库本身无关。
内容的提问来源于stack exchange,提问作者AIMIN PAN
相关产品推荐
相关产品推荐

