Hibernate: could not execute query using sroll问题解析

最近的一个项目在Hibernate使用C3P0的连接池,数据库为Mysql。开发测试没有问题,在运行中每个一段长的空闲时间就出现异常:
org.hibernate.exception.JDBCConnectionException: could not execute query 
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:74)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
.
Caused by: com.mysql.jdbc.exceptions.MySQLNonTransientConnectionException: No operations allowed after connection closed.Connection was implicitly closed due to underlying exception/error:


** BEGIN NESTED EXCEPTION **

com.mysql.jdbc.CommunicationsException
MESSAGE: Communications link failure due to underlying exception:

** BEGIN NESTED EXCEPTION **

java.net.SocketException
MESSAGE: Broken pipe

STACKTRACE:

java.net.SocketException: Broken pipe
at java.net.SocketOutputStream.socketWrite0(Native Method)

** END NESTED EXCEPTION **



查看了Mysql的文档,以及Connector/J的文档以及在线说明发现,出现这种异常的原因是:

Mysql服务器默认的“wait_timeout”是8小时,也就是说一个connection空闲超过8个小时,Mysql将自动断开该connection。这就是问题的所在,在C3P0 pools中的connections如果空闲超过8小时,Mysql将其断开,而C3P0并不知道该connection已经失效,如果这时有Client请求connection,C3P0将该失效的Connection提供给Client,将会造成上面的异常。

解决的方法有3种:

增加wait_timeout的时间。
减少Connection pools中connection的lifetime。
测试Connection pools中connection的有效性。

当然最好的办法是同时综合使用上述3种方法,下面就DBCP和C3P0分别做一说明,假设wait_timeout为默认的8小时

DBCP增加以下配置信息:

//set to 'SELECT 1'
validationQuery = "SELECT 1"
//set to 'true'
testWhileIdle = "true"
//some positive integer
timeBetweenEvictionRunsMillis = 3600000
//set to something smaller than 'wait_timeout'
minEvictableIdleTimeMillis = 18000000
//if you don't mind a hit for every getConnection(), set to "true"
testOnBorrow = "true"


C3P0增加以下配置信息:

//获取connnection时测试是否有效
testConnectionOnCheckin = true
//自动测试的table名称

automaticTestTable=C3P0TestTable

//set to something much less than wait_timeout, prevents connections from going stale
idleConnectionTestPeriod = 18000
//set to something slightly less than wait_timeout, preventing 'stale' connections from being handed out
maxIdleTime = 25000
//if you can take the performance 'hit', set to "true"
testConnectionOnCheckout = true


更多的配置信息参照看C3P0文档,Connector/J文档,以及DBCP的文档。
你遇到的错误是: ``` PersistenceException: org.hibernate.exception.SQLGrammarException: could not execute query ``` 这个错误表示 **Hibernate 在执行 SQL 查询时遇到了语法错误**,可能是由以下几种原因导致的。 --- ## ✅ 错误分析 ### 原始错误链: ``` PersistenceException └── SQLGrammarException └── could not execute query ``` 这意味着 Hibernate 在执行查询时,底层数据库抛出了 SQL 语法错误。 --- ## ✅ 常见原因及解决方案 ### 1. SQL 语法错误(最常见) **可能原因:** - 拼写错误(如 `SELEC` 而不是 `SELECT`) - 表名或字段名错误(如 `xx_stroe` 而不是 `xx_store`) - 缺少逗号、括号不匹配 - 使用了数据库不支持的函数或语法 **解决方案:** - 打印出最终生成的 SQL 语句,直接在数据库客户端中执行,查看是否报错。 - 开启 Hibernate 的 SQL 输出日志: ```properties # application.properties spring.jpa.show-sql=true spring.jpa.properties.hibernate.format_sql=true ``` 或者在 `log4j` / `logback` 中设置日志级别为 `DEBUG`。 --- ### 2. 表或字段不存在 **错误示例:** ```sql select * from xx_stroe -- 表名拼写错误 ``` **解决方案:** - 检查 SQL 中所有表名和字段名是否正确 - 使用数据库客户端验证 SQL 语句是否能执行 --- ### 3. 别名冲突(如你之前提到的 `so`) **错误示例:** ```sql left join xx_store so on oi.invoice_store = so.id left join b1_sale_org so on oi.sale_org = so.id ``` **解决方案:** 使用不同的别名,避免重复: ```sql left join xx_store invoice_store on oi.invoice_store = invoice_store.id left join b1_sale_org sale_org on oi.sale_org = sale_org.id ``` --- ### 4. 参数绑定错误(如字段类型不匹配) **错误示例:** ```java sql.append("... where oi.status = ?"); list.add("1"); // 但 status 是 INT 类型 ``` **解决方案:** 确保参数类型与数据库字段匹配,例如: ```java list.add(1); // 如果 status 是 INT ``` --- ### 5. Hibernate 查询中使用了原生 SQL,但未正确配置 如果你使用的是 `createNativeQuery()`,但没有正确映射返回字段或实体类,也会导致错误。 #### 示例: ```java List<YourEntity> result = entityManager.createNativeQuery("SELECT * FROM your_table", YourEntity.class).getResultList(); ``` **注意:** - 原生 SQL 查询返回实体类时,字段名必须与实体类属性名匹配 - 或者使用 `@SqlResultSetMapping` 显式映射 --- ## ✅ 如何定位问题 ### ✅ 步骤一:打印 SQL 语句 在代码中打印出最终构造的 SQL: ```java System.out.println(sql.toString()); System.out.println(list); // 参数列表 ``` ### ✅ 步骤二:手动执行 SQL 将 SQL 和参数复制到数据库客户端中执行,确认是否报错。 ### ✅ 步骤三:查看完整异常栈信息 确保你看到完整的异常栈,例如: ``` Caused by: java.sql.SQLSyntaxErrorException: Unknown column 'xx_store.nam' in 'field list' ``` 这类信息能直接指出错误点。 --- ## ✅ 示例修复 ### 错误 SQL: ```sql SELECT oi.*, s.nam store_name, so.nam invoice_store_name ... ``` ### 正确 SQL: ```sql SELECT oi.*, s.name store_name, so.name invoice_store_name ... ``` --- ## ✅ 总结对比表 | 问题类型 | 原因 | 解决方案 | |----------|------|----------| | SQL 语法错误 | 拼写、语法错误 | 检查 SQL,使用客户端执行 | | 字段或表不存在 | 表名或字段名错误 | 验证数据库结构 | | 别名冲突 | 同一个别名用于多个表 | 使用不同别名 | | 参数类型不匹配 | 参数类型与字段类型不符 | 检查参数类型 | | Hibernate 映射错误 | 原生 SQL 与实体类字段不匹配 | 使用 `@SqlResultSetMapping` | --- ##
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值