我正在使用mybatis连接到oracle。
我的mybatis配置为:
<settings>
<setting name="lazyLoadingEnabled" value="true" />
<setting name="aggressiveLazyLoading" value="false" />
<setting name="logImpl" value="${logImpl}" />
<setting name="defaultStatementTimeout" value="10" />
</settings>
<environments default="default">
<environment id="default">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="poolPingConnectionsNotUsedFor" value="290000"/>
<property name="poolPingQuery" value="SELECT COUNT(*) FROM RESORT"/>
<property name="poolPingEnabled" value="true"/>
</dataSource>
</environment>
</environments>
我公开会议的代码就像
SqlSession sqlSession = factory.openSession();
Object result = null;
try
{
QueryInfoMapper mapper = sqlSession.getMapper(QueryInfoMapper.class);
result = mapper.queryInfoFromOpera(mybatisMapping);
} finally
{
sqlSession.close();
}
由于应用程序的作用域为类,因此sqlSession不能在应用程序作用域中使用,因此我必须自己管理sqlSession。
日志是
2019-04-11 15:30:35,773信息[stdout](默认任务60)打开JDBC连接
2019-04-11 15:30:41,860信息[stdout](默认任务57)连接不良。无法回滚
2019-04-11 15:30:41,861信息[stdout](默认任务57)声明过期连接962608913。
2019-04-11 15:30:41,861信息[stdout](默认任务57)从池返回了错误的连接(962608913),获得了另一个连接。
2019-04-11 15:30:41,895 INFO [stdout](默认任务-57)已创建连接1812494479。
2019-04-11 15:30:41,895信息[stdout](默认任务57)在JDBC连接[oracle.jdbc.driver.T4CConnection@6c08788f]上将autocommit设置为false
2019-04-11 15:30:41,895 INFO [stdout](默认任务57)==>准备:从OPERA中选择TRAVEL_AGENT_NAME FROM(从OPERA中选择TRAVEL_AGENT_NAME RESERV_NAME_ID =吗?)WHERE行数= 1
2019-04-11 15:30:41,896信息[stdout](默认任务57)==>参数:288541(String)
2019-04-11 15:30:41,900信息[stdout](默认任务57)<==列:TRAVEL_AGENT_NAME
2019-04-11 15:30:41,900 INFO [stdout](默认任务57)<==行:null
2019-04-11 15:30:41,900信息[stdout](默认任务57)<==总数:1
2019-04-11 15:30:41,900信息[stdout](默认任务57)在JDBC连接[oracle.jdbc.driver.T4CConnection@6c08788f]上将自动提交重置为true
2019-04-11 15:30:41 ,900信息[stdout](默认任务57)关闭JDBC连接 [oracle.jdbc.driver.T4CConnection @ 6c08788f]
2019-04-11 15:31:00 ,788 INFO [stdout](默认任务60)连接不良。无法回滚
2019-04-11 15:31:00,788信息[stdout](默认任务60)声称过期连接1228464923。
2019-04-11 15:31:00,788信息[stdout](默认任务60)从池返回了错误的连接(1228464923),获得了另一个连接。
2019-04-11 15:31:00,820信息[stdout](默认任务60)创建了连接265625885。
2019-04-11 15:31:00,820信息[stdout](默认任务60)在JDBC连接[oracle.jdbc.driver.T4CConnection@fd5211d]上将自动提交设置为false
2019-04-11 15:31:00,820信息[stdout](默认任务57)将连接1812494479返回到池。
根据时间戳查看日志,似乎发生在关闭连接期间(此处是事务)
但是关闭它需要9或19秒钟。第二个日志是“连接不良。无法回滚”。我无法找到真正原因所在。哪种方法要花费很多时间。这个问题并非每次都会发生,而是随机发生的。
我想设置<property name="poolMaximumActiveConnections" value="40" />
以增加联系。我不确定是否有帮助。
关闭连接/事务失败的原因是什么?如何避免关闭连接/事务失败?
==========================
更新:我再次遇到此问题,并且日志有所不同:
2019-04-13 15:42:31,812信息[stdout](默认任务86)打开JDBC连接
2019-04-13 15:42:35,493信息[stdout](默认任务62)执行ping查询'SELECT COUNT(*)FROM RESORT'失败:IO错误:套接字读取超时
2019-04-13 15:42:35,493信息[stdout](默认任务62)连接1963609369不良:IO错误:套接字读取超时
2019-04-13 15:42:35,493信息[stdout](默认任务62)从池返回了错误的连接(1963609369),获得了另一个连接。
2019-04-13 15:42:35,493信息[stdout](默认任务62)从池中签出了连接195963529。
2019-04-13 15:42:35,493信息[stdout](默认任务62)测试连接195963529 ...
2019-04-13 15:42:54,448信息[stdout](默认任务62)执行ping查询'SELECT COUNT(*)FROM RESORT'失败:IO错误:套接字读取超时
2019-04-13 15:42:54,448信息[stdout](默认任务62)连接195963529错误:IO错误:套接字读取超时
2019-04-13 15:42:54,448信息[stdout](默认任务62)从池返回了错误的连接(195963529),获得了另一个连接。
2019-04-13 15:42:54,479信息[stdout](默认任务62)创建了连接741137137。
顺便说一句,我将ping sql更改为SELECT 1 FROM DUAL
。
是什么原因导致此套接字读取超时?
答案 0 :(得分:1)
我可以在这里看到几个问题:
您肯定需要使用SELECT 1 FROM DUAL
作为ping查询。否则,您会在每个打开的连接上执行一些不太便宜的操作。
长时间关闭和IO Error: Socket read timed out
表示存在某些网络连接问题或oracle服务器可用性问题,或同时存在。
在发生此问题时检查oracle健康状况是有意义的。当时它是否响应其他查询?什么是CPU / io /内存/交换使用率等。如果服务器负载很高,则可能是服务器没有及时响应。
检查网络连接问题是一个非常广泛的主题。我所知道的最可靠(也是最复杂)的方式是捕获两端的网络流量(使用tcpdump或WireShark之类的工具)并进行比较。
然后mybatis连接池出现问题。
首先,有关mybatis连接池如何工作的一些背景。
一件重要但不明显的事情是,如果mybatis连接池实现使用时间过长,则会强制将连接返回到该池。这是documentation的引文:
poolMaximumCheckoutTime –这是可以强制将连接从池中“检出”连接之前的时间。默认值:20000ms(即20秒)
这意味着,如果应用程序尝试打开新连接并且所有连接均处于繁忙状态,则mybatis将关闭最旧的连接(如果使用时间超过20秒(默认))。
如果您有一些长时间运行的查询,那么它本身可能是一个非常意外的行为。另一个可能更大的问题是如何在mybatis中实现这一点。为了获取连接request to rollback,该事务是从请求新连接的线程中完成的(在上面的示例中,线程default task-57
保持着连接,而线程default task-60
试图获取该连接)从游泳池)。
这是问题所在,因为从多个线程访问连接时,oracle jdbc驱动程序requires正确同步,而mybatis却无法做到这一点:
控制连接的串行访问(例如由连接缓存提供的访问)是必要的,也是鼓励使用的。但是,Oracle强烈建议不要在多个线程之间共享数据库连接。避免允许多个线程同时访问连接。如果必须共享多个线程,请使用严格的开始/结束使用协议。
因此,无法同步从多线程到共享资源(连接)的访问可能会导致各种一致性问题,并且我不排除关闭连接的问题是由于已获得连接这一事实引起的。由于缺少同步,因此早些时候进入了一些不一致的状态。
对于给定的负载,增加池大小可以解决此问题,因为不会发生(或发生频率较低)池耗尽的情况。
请注意,并发问题很难重现,积极的综合测试几乎不能保证。这是一个广泛的主题,因此建议您查看Goetz book以获得详细信息。
我将更改连接池的实现,即使用https://github.com/swaldman/c3p0或https://commons.apache.org/proper/commons-dbcp/或https://brettwooldridge.github.io/HikariCP/。