为什么 JPA JDBC 在一个事务中相互锁定?

Why JPA JDBC lock each other in one transaction?

提问人:Xingbo Ye 提问时间:10/23/2023 最后编辑:Christophe QuintardXingbo Ye 更新时间:10/23/2023 访问量:42

问:

重命名表时@Transactional注释导致锁定冲突的问题

  1. 场景

    我在单个事务中执行两个操作:

    1. 使用 jpa 将数据保存到临时表。

    2. 使用 jdbcTemplate 重命名临时表。

    我发现临时表被第一个操作阻止,这意味着重命名无法获得完成所需的锁。这让我感到困惑。

    代码

    @HandlingTime
    @Transactional
    public void updateFromLocalFiles(@NotNull String materialFile, @NotNull String... statusFiles) {
        saveDataToTempTable(materialFile, statusFiles);
        checkDataIntegrity();
        backupAndDeleteOriginTable();
        replaceTemporaryToOriginTable();
        dropExpiredTable();
    }
    

    saveDataToTempTable 调用此 jpa 函数

    protected long saveAllToTempTable(List<AdwMaterialTemp> materialList) {
        List<AdwMaterialTemp> adwMaterialTemps = adwMaterialTempRepository.saveAllAndFlush(materialList);
        return adwMaterialTemps.size();
    }
    

    replaceTemporaryToOrigiinTable 调用此 jdbc 函数

    public void changeTableName(String originTableName, String targetTableName) throws DataAccessException {
        String RENAME_TABLE_NAME = "ALTER TABLE %s RENAME TO %s;";
        var sql = String.format(RENAME_TABLE_NAME, originTableName, targetTableName);
        jdbcTemplate.execute(sql);
        log.info(SQL_LOG, sql);
    }
    

我在数据库的processList中看到了这一点:

| 9289 | root            | 172.20.0.1:63024 | sephora-product-management | Query   |   1240 | Waiting for table metadata lock | ALTER TABLE adw_material_temp RENAME TO adw_material |

在 performance_schema.metadata_locks 中:

| OBJECT_TYPE       | OBJECT_SCHEMA              | OBJECT_NAME                                  | COLUMN_NAME           | OBJECT_INSTANCE_BEGIN | LOCK_TYPE           | LOCK_DURATION | LOCK_STATUS | SOURCE            | OWNER_THREAD_ID | OWNER_EVENT_ID |

| TABLE             | sephora-product-management | adw_material_temp                            | NULL                  |       140332151913120 | SHARED_WRITE        | TRANSACTION   | GRANTED     | sql_parse.cc:5737 |            9352 |          15429 |
| TABLE             | sephora-product-management | adw_material_temp                            | NULL                  |       140331681928000 | EXCLUSIVE           | TRANSACTION   | PENDING     | mdl.cc:3702       |            9353 |             19 |

我删除了跨肌注释。然后它起作用了。

Java JPA JDBC Spring-事务

评论

0赞 Chris 10/23/2023
您的数据库是什么,它如何处理事务中的 DDL 语句?DDL 通常不是事务性的;并非所有数据库都喜欢并支持数据使用表时的表操作。
0赞 Xingbo Ye 10/24/2023
我使用mysql:8.0.22。并且自动提交配置已打开。
0赞 Chris 10/24/2023
如果没有事务,那么 JPA 写入操作将根本不会转到数据库。尝试打开 SQL 日志记录,您将能够看到各种选项的情况。Mysql 自动提交 DDL 语句,所以它们不在事务中,也不能回滚,所以我不知道你希望完成什么,但你最好做一些不同的事情,比如在事务成功后发出 DDL(在标有事务注释的方法之外)或开始时。

答: 暂无答案