Oracle JDBC驱动, Tomcat连接池的坑
2017-04-25 21:16
417 查看
之前开发过程中遇到脏数据的问题.经过一段时间的分析,结果如下:
1. 应用通过Tomcat JDBC Pool获得一个数据库连接;
2. 通过这个连接执行了一些Insert, Update之类;
3. 之后的业务代码,执行了一个时间比较长的查询;
4. Tomcat JDBC Pool 认为这个连接使用的时间过长, 没有在配置的时间内(AbandonTimeout这个配置)把这个连接close, 所以自动回收并Close了这个连接.
其实到这里都是没有问题的. 问题在于, 这个连接被回收到连接池并Close之后, 在1和2步骤中插入更新的数据没有回滚.
继续分析,发现如下的结果:
JDBC标准没有规定一个Connection Close的时候(这里说的close, 是指程序正常调用close()方法, 而不是说因为网络等等原因这个connection被中断了),如果没有Commit的表现. 所以很多人,包括我, 理所当然认为, 如果没有手动Comit或者Rollback,
JDBC Driver应该主动回滚. 但是因为标准没有规定, 这个行为对于不同的驱动的实现是不一样的. 对于Oracle的驱动, 在close的时候会替你commit.
所以这个问题就出现了:
连接池的检测线程发现某个连接池的连接,在配置的时间内没有归还给连接池, 所以连接池主动close了这个连接. 但是对于Oracle, 因为JDBC Driver会替你
commit, 所以出现了尽管这个连接被关闭了, 这个连接的更新还是被提交到了数据库中.
解决方案:
没有找到现成的配置;所以自己写了一个Tomcat JDBC Connection Pool Intepto来做这件事情:
然后在配置连接池的地方加上就行了:
1. 应用通过Tomcat JDBC Pool获得一个数据库连接;
2. 通过这个连接执行了一些Insert, Update之类;
3. 之后的业务代码,执行了一个时间比较长的查询;
4. Tomcat JDBC Pool 认为这个连接使用的时间过长, 没有在配置的时间内(AbandonTimeout这个配置)把这个连接close, 所以自动回收并Close了这个连接.
其实到这里都是没有问题的. 问题在于, 这个连接被回收到连接池并Close之后, 在1和2步骤中插入更新的数据没有回滚.
继续分析,发现如下的结果:
JDBC标准没有规定一个Connection Close的时候(这里说的close, 是指程序正常调用close()方法, 而不是说因为网络等等原因这个connection被中断了),如果没有Commit的表现. 所以很多人,包括我, 理所当然认为, 如果没有手动Comit或者Rollback,
JDBC Driver应该主动回滚. 但是因为标准没有规定, 这个行为对于不同的驱动的实现是不一样的. 对于Oracle的驱动, 在close的时候会替你commit.
所以这个问题就出现了:
连接池的检测线程发现某个连接池的连接,在配置的时间内没有归还给连接池, 所以连接池主动close了这个连接. 但是对于Oracle, 因为JDBC Driver会替你
commit, 所以出现了尽管这个连接被关闭了, 这个连接的更新还是被提交到了数据库中.
解决方案:
没有找到现成的配置;所以自己写了一个Tomcat JDBC Connection Pool Intepto来做这件事情:
public class RollbackInterptor extends JdbcInterceptor { private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); @Override public void reset(ConnectionPool parent, PooledConnection con) { } @Override public void disconnected(ConnectionPool parent, PooledConnection con, boolean finalizing) { logger.info("Disconnected called for {} {}", con, parent); try { if (con != null && con.getConnection() != null) { con.getConnection().rollback(); logger.info("Connection {} has been rolled-back.", con); } } catch (Exception e) { } super.disconnected(parent, con, finalizing); } }
然后在配置连接池的地方加上就行了:
<property name="jdbcInterceptors"> <value>org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReport(threshold=5000);com.foo.bar.connection.RollbackInterptor</value> </property>
相关文章推荐
- oracle 11.02新版在win7下安装与Tomcatr的连接池以及jdbc驱动的问题
- Tomcat上配置连接池{ connect error=Name [jdbc/OracleDB] is not bound in this Context. Unable to find [jdbc]}
- JDBC在Tomcat中配置数据库(MSSQL和ORACLE)连接池的配置文件(server.xml)
- tomcat连接池(Oracle版)
- Oracle JDBC2.0 数据来源(Data Source)与连接池(Connection Pool)
- tomcat5.5.12 配置连接池(oracle)
- 使用tomcat连接池的时候的Cannot create JDBC driver of class '' for connect URL 'null'异常
- 数据源 jdbc tomcat oracle 配置
- JDBC驱动访问SQL Server2000数据库(JDK1.6+JSP+Tomcat 5.5.20)
- Oracle JDBC2.0 数据来源(Data Source)与连接池(Connection Pool)
- Tomcat+Oracle连接池的例子
- Tomcat4+Oracle的数据库连接池配置
- Tomcat5.0与SqlServer2000配置连接池(jtds驱动)
- Tomcat5.5连接池配置(oracle / mysql / sqlserver2000)
- Tomcat 6 通过 JDBC 连接池连接 SQL Server 2000 和 MySQL 5 的设置
- 在tomcat中设置数据源时jdbc驱动存放的位置
- 修改Tomcat的主配置文件,增加一个Postgre数据库JDBC连接池。
- Tomcat4+Oracle的数据库连接池配置
- JDBC连接Oracle驱动问题。
- 建立基于 JDBC 的 Tomcat 连接池