【问题标题】:Mixing JdbcTemplate and raw JDBC混合 JdbcTemplate 和原始 JDBC
【发布时间】:2015-05-31 15:07:40
【问题描述】:

我遇到了一些我无法轻易解释的奇怪行为。以下代码运行良好:

    try (Connection connection = dataSource.getConnection();
         Statement statement = connection.createStatement()) {
        statement.executeUpdate("DELETE FROM product");

    } catch (Exception ex) {
        throw new RuntimeException(ex);
    }

    try (Connection connection = dataSource.getConnection();
         Statement statement = connection.createStatement()) {
         statement.executeUpdate("INSERT INTO product ...");

    } catch (SQLException ex) {
        throw new RuntimeException(ex);
    }

但是这段代码会导致死锁:

    jdbcTemplate.update("DELETE FROM product");

    try (Connection connection = dataSource.getConnection();
         Statement statement = connection.createStatement()) {
         statement.executeUpdate("INSERT INTO product ...");

    } catch (SQLException ex) {
        throw new RuntimeException(ex);
    }

例外是

java.sql.SQLException: 超过锁定等待超时;尝试重启事务

jdbcTemplate 和 dataSource 都是由 Spring boot 创建并自动装配的

@Autowired
private DataSource dataSource;

@Autowired
private JdbcTemplate jdbcTemplate;

语句构成服务中方法的一部分(带有@Transactional 注释)

谁能解释为什么会这样?

【问题讨论】:

  • 你为什么要这样?只需使用 JdbcTemplate 进行所有 JDBC 访问。问题是每次您执行getConnection 时,您都在使用与数据库的新连接,如果它们在同一个连接上操作,可能会导致死锁。要修复它,请不要这样做,而是使用JdbcTemplate 进行所有访问。
  • 我不能对所有事情都使用 JdbcTemplate - 我们执行 mysql upserts“在重复密钥更新时插入..”并且 KeyHolder 在生成的 id 上阻塞,而 vanilla JDBC 可以适应这一点。我仍然不明白如果我有单线程顺序调用来获取和释放连接,我将如何陷入死锁?
  • 你能显示使用事务边界(@transaction),你使用哪个存储引擎?
  • 默认情况下,每次调用 getConnection 都会创建一个新连接,除非您将数据源包装在 TransactionAwareDataSourceProxy 中,但我怀疑您是这样的。您仍然可以(并且应该)使用JdbcTemplate,为此使用ConnectionCallback,这样您就可以确定您使用相同的连接进行所有访问。
  • 非常感谢,这是有道理的。

标签: spring spring-boot spring-data spring-jdbc


【解决方案1】:

如果您想使用自己的 JDBC 代码与 Spring 的事务管理管理的连接配合得很好,您应该使用 DataSourceUtils 来获取连接——请参阅http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/jdbc/datasource/DataSourceUtils.html#getConnection-javax.sql.DataSource-

在您的示例中,根据事务配置,使用 JdbcTemplate 的第一条语句可能尚未提交,因此它会阻止来自不同连接的下一条 JDBC 语句。使用 DataSourceUtils,两个语句将使用相同的连接。

【讨论】:

  • 谢谢。我正在使用数据源实用程序及其工作。我可能会按照 M Deinum 的建议使用 jdbc 模板,但我认为回调模式现在我们 Java 7 并没有增加太多资源并尝试使用资源。
猜你喜欢
  • 2012-12-12
  • 2016-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-24
  • 2011-05-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多