【问题标题】:jdbcTemplate hangs on long updatejdbcTemplate 在长时间更新时挂起
【发布时间】:2010-11-15 02:39:13
【问题描述】:

我最近切换到 Spring Framework 而不是手动处理 JDBC,这主要是一个很好的过渡。但是,一个程序开始遇到奇怪的问题:如果数据库很慢,那么在调用 getJdbcTemplate().update( ... ) 时它有时永远不会返回。

经过一番研究,我从Apache DBCP切换到C3PO,但问题仍然存在。

这是我正在使用的代码:

public class MyDao extends SimpleJdbcDaoSupport {
    private static Logger logger = Logger.getLogger(MyDao.class);

    public MyDao(Config config) {
        super();

        ComboPooledDataSource cpds = new ComboPooledDataSource();
        try {
            cpds.setDriverClass("com.mysql.jdbc.Driver");
        } catch (PropertyVetoException e) {
            throw new RuntimeException(e);
        }
        cpds.setUser("username");
        cpds.setPassword("password");
        cpds.setJdbcUrl("jdbc:mysql://localhost/schema" + 
                        "?useUnicode=true&characterEncoding=UTF-8");
        cpds.setMaxStatements( 180 );
        cpds.setPreferredTestQuery("SELECT 1");
        cpds.setTestConnectionOnCheckout(true);

        this.setDataSource(cpds);
    }

    public void addToWorkQueue(String item) {
        long[] ids = Utils.getItemIds(item);

        try {
            logger.debug("About to insert to work table");
            getJdbcTemplate().update(
                    "INSERT IGNORE INTO work " +
                    "SELECT * FROM queue WHERE id_1 = ? AND id_2 = ?",
                    new Object[] { ids[0], ids[1] }
            );
        } finally {
            logger.debug("Updated work table");
        }
    }
}

这是日志文件中的内容:

2009-07-29 17:37:13.570 com.mycomp.MyDao About to insert into work table
2009-07-29 17:37:13.570 com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool Testing PooledConnection [com.mchange.v2.c3p0.impl.NewPooledConnection@170984c] on CHECKOUT.
2009-07-29 17:37:13.571 com.mchange.v2.c3p0.stmt.GooGooStatementCache checkinAll(): com.mchange.v2.c3p0.stmt.GlobalMaxOnlyStatementCache stats -- total size: 1; checked out: 0; num connections: 1; num keys: 1
2009-07-29 17:37:13.571 com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool Test of PooledConnection [com.mchange.v2.c3p0.impl.NewPooledConnection@170984c] on CHECKOUT has SUCCEEDED.
2009-07-29 17:37:13.571 com.mchange.v2.resourcepool.BasicResourcePool trace com.mchange.v2.resourcepool.BasicResourcePool@d402dd [managed: 3, unused: 2, excluded: 0] (e.g. com.mchange.v2.c3p0.impl.NewPooledConnection@170984c)
2009-07-29 17:37:13.571 com.mchange.v2.c3p0.stmt.GooGooStatementCache com.mchange.v2.c3p0.stmt.GlobalMaxOnlyStatementCache ----> CACHE HIT
2009-07-29 17:37:13.571 com.mchange.v2.c3p0.stmt.GooGooStatementCache checkoutStatement: com.mchange.v2.c3p0.stmt.GlobalMaxOnlyStatementCache stats -- total size: 1; checked out: 1; num connections: 1; num keys: 1

这是代码挂起的地方。通常它只是这样继续:

2009-07-29 17:37:13.762 com.mchange.v2.c3p0.stmt.GooGooStatementCache checkinStatement(): com.mchange.v2.c3p0.stmt.GlobalMaxOnlyStatementCache stats -- total size: 1; checked out: 0; num connections: 1; num keys: 1
2009-07-29 17:37:13.763 com.mchange.v2.c3p0.stmt.GooGooStatementCache checkinAll(): com.mchange.v2.c3p0.stmt.GlobalMaxOnlyStatementCache stats -- total size: 1; checked out: 0; num connections: 1; num keys: 1
2009-07-29 17:37:13.763 com.mchange.v2.resourcepool.BasicResourcePool trace com.mchange.v2.resourcepool.BasicResourcePool@d402dd [managed: 3, unused: 2, excluded: 0] (e.g. com.mchange.v2.c3p0.impl.NewPooledConnection@170984c)
2009-07-29 17:37:13.763 com.mycomp.MyDao Updated work table

我不知道为什么我没有从 Spring Framework 本身收到任何日志消息。我在我的主代码中添加了这些行:

Logger springLogger = Logger.getLogger("org.springframework");
springLogger.setLevel(Level.TRACE);
springLogger.debug("testing spring logger");

测试消息显示,但没有其他内容。很抱歉分道扬镳。

在挂起之前我确实注意到速度变慢了。上次成功运行查询需要一分半钟才能完成,而不是通常的 200 毫秒。下一次,我让它运行 25 分钟,然后终止进程。

我知道我正在处理的数据库 (InnoDB) 存在一些问题,但这似乎是在超时之后,Spring Framework 只是“放弃”并挂起。

任何建议将不胜感激。

【问题讨论】:

  • 我怀疑这与 Spring 有什么关系,它是一个非常薄的层。不过,这可能与交易有关......?
  • 我同意,您是否可能不关闭交易?是否有可能另一个查询锁定了表?如果您使用的是 InnoDB,请运行“show innodb status”

标签: jdbc spring c3p0


【解决方案1】:

最终,通过修复底层数据库问题避免了该问题。

我使用 InnoDB 表作为工作队列,这意味着我向其中添加和删除了大量项目。该表在给定时间从未有太多行,但显然 InnoDB 无法处理此类工作,或者正如我的 DBA 朋友所说,“从表中删除行对性能没有任何作用”。

在切换到一个更疯狂的数据库策略后,包括一直创建和删除表,性能得到了很大改善,挂起也消失了。

所以我想我的意思是,skaffman 的评论可能是正确的。这与 Spring 无关。

【讨论】:

  • 也许你应该关闭问题或删除弹簧标签?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-12-13
  • 1970-01-01
  • 1970-01-01
  • 2022-08-20
  • 1970-01-01
  • 1970-01-01
  • 2015-07-05
相关资源
最近更新 更多