触发器异常导致的druid问题
来源:互联网 发布:希捷数据恢复要多少钱 编辑:程序博客网 时间:2024/06/05 20:46
距离上一次写博客,时间已经非常久远了。经历了一段觉得没有东西可以写的时间,本质上应该是失去了监管后的自我放松吧。期间,复写的念头来来走走,都因为懒而作罢。学习这件事情,不能等到用时方恨少……否则变得被动,自我改造中!!!入正题。
关于什么是druid,这里不做介绍了,有兴趣了解的朋友先自行找些资料哈,sorry。这里我打算只是记录一下我遇到的问题。如果你不曾使用过这个东西,那这里的内容可能看着也没啥意思哈。
异常现象
近期的一个用户中心的项目提供对外的登录认证、用户基本信息的调取等接口,给公司的其他平台使用。因此在性能上要求支持300并发,平均响应时间在1s左右。我们采用了druid连接池,为了提高响应速度我们开启了PreparedStatement(pscache)缓存,缓存数量设置在100。在压力测试的时候没有发现什么问题,但是上线后在某种特定情况下,不定期出现服务器卡死的现象。监控了数据库连接数、带宽、cpu、内存、服务器之间的网络连接数等等,均为发现异常情况。
发现问题
经过很多次猜测,并实验。发现我们的问题在于启用了pscache,我们关闭了缓存以后响应速度下来了。但是服务器不会再出现卡死现象。因此,基本上锁定问题出在这个pscache上。进一步测试实验发现,卡死状态下,出现问题的仅有两个功能登录和机构添加。这两个功能都涉及到数据库的触发器。查询数据库操作日志发现卡死时触发器报错,因此锁定在触发器报错时pscache对该错误的处理上。
查看druid的源码
跟踪druid连接池的代码,类DruidDataSource和OracleExceptionSorter。
DruidDataSource类中的该方法决定是否还将使用过的连接归还给连接池,或者作废出错的连接。
public void handleConnectionException(DruidPooledConnection pooledConnection, Throwable t) throws SQLException { DruidConnectionHolder holder = pooledConnection.getConnectionHolder(); this.errorCount.incrementAndGet(); this.lastError = t; this.lastErrorTimeMillis = System.currentTimeMillis(); if(!(t instanceof SQLException)) { throw new SQLException("Error", t); } else { SQLException sqlEx = (SQLException)t; ConnectionEvent event = new ConnectionEvent(pooledConnection, sqlEx); Iterator requireDiscard = holder.getConnectionEventListeners().iterator(); while(requireDiscard.hasNext()) { ConnectionEventListener eventListener = (ConnectionEventListener)requireDiscard.next(); eventListener.connectionErrorOccurred(event); } if(this.exceptionSorter != null && this.exceptionSorter.isExceptionFatal(sqlEx)) { if(pooledConnection.isTraceEnable()) { Map requireDiscard1 = this.activeConnections; synchronized(this.activeConnections) { if(pooledConnection.isTraceEnable()) { this.activeConnections.remove(pooledConnection); pooledConnection.setTraceEnable(false); } } } boolean requireDiscard2 = false; synchronized(pooledConnection) { if(!pooledConnection.isClosed() || !pooledConnection.isDisable()) { holder.setDiscard(true); pooledConnection.disable(t); requireDiscard2 = true; } } if(requireDiscard2) { this.discardConnection(holder.getConnection()); holder.setDiscard(true); } LOG.error("discard connection", sqlEx); } throw sqlEx; } }
OracleExceptionSorter类中的该方法对数据库返回的错误进行处理,标识连接是否作废:
public boolean isExceptionFatal(SQLException e) { int error_code = Math.abs(e.getErrorCode()); switch(error_code) { case 28: case 600: case 1012: case 1014: case 1033: case 1034: case 1035: case 1089: case 1090: case 1092: case 1094: case 2396: case 3106: case 3111: case 3113: case 3114: case 3134: case 3135: case 3136: case 3138: case 3142: case 3143: case 3144: case 3145: case 3149: case 6801: case 6802: case 6805: case 9918: case 9920: case 9921: case 17001: case 17002: case 17008: case 17024: case 17089: case 17401: case 17409: case 17410: case 17416: case 17438: case 17442: case 25407: case 25408: case 25409: case 25425: case 29276: case 30676: return true; default: if(error_code >= 12100 && error_code <= 12299) { return true; } else { String error_text = e.getMessage().toUpperCase(); return error_code >= 20000 && error_code < 21000 || !error_text.contains("SOCKET") && !error_text.contains("套接字") && !error_text.contains("CONNECTION HAS ALREADY BEEN CLOSED") && !error_text.contains("BROKEN PIPE") && !error_text.contains("管道已结束")?this.fatalErrorCodes.contains(Integer.valueOf(error_code)):true; } } }}
触发器抛出的错误的错误为:java.sql.SQLException:internal error,对应的错误码我不记得了,但是不在上面这个类的所有case项里。druid认为oracle数据库内部错误不数据应用程序的数据库连接有问题,因此该连接被连接池保持了。但实际上该连接在开始pscache的情况下是有问题的,不能复用。具体为啥没有看懂,汗。
解决办法
触发器发生错误时,手动抛出错误,抛出一个druid能够识别的错误。在触发器END之前添加如下内容:
EXCEPTION WHEN OTHERS THEN RAISE NOT_LOGGED_ON;问题解决,曲线救国,不是正经路子。
总结:这种错误实在是不容易发现,得多做实验。
- 触发器异常导致的druid问题
- CString导致程序异常的问题
- 异常的错误使用导致性能问题
- 项目中异常退出导致的问题。
- hibernate自动添加永真1=1,导致Druid sql防火墙报错的问题
- druid数据源监控配置和异常问题
- android异常问题笔记----导入依赖库导致的异常
- 解决时区导致druid任务构建失败的问题:No buckets?? seems there is no data to index.
- spring 继承的baseDao无法注入导致异常的问题
- 防止编译器过度优化导致的并发异常问题
- lsof命令导致CPU负载异常的问题总结
- Response.End导致“正在中止线程”异常的问题
- hive partition字段异常字符导致的问题
- 经常因为殊字符的问题导致查询异常
- Eclipse异常关闭导致下次无法打开的问题
- 突然断电导致mysql启动异常的问题
- Response.End导致“正在中止线程”异常的问题
- hdfs块丢失导致的异常问题排查解决
- 设置全局结果视图(Struts框架)
- 数据结构与算法分析---第一章--练习1.3
- laravel连接数据库可能出现的小问题
- Oracle 导入、导出 本地&远程 数据
- ThinkPHP3.2.3如何实现系统登录日志?
- 触发器异常导致的druid问题
- Canvas
- dcm4che2-Java Library for DICOM
- Android系统底层启动源码分析(开机启动)
- 安卓中使用SharedPreferences保存javaBean类对象
- comet4j 主动向客户端推送信息 简单例子
- 【题目整理】
- OpenJudge百炼-2745-显示器-C语言-模拟
- Lua教程(5):C/C++操作Lua数组和字符串