【问题标题】:Transactions fails due to "Lock wait timeout exceeded; try restarting transaction"由于“超过锁定等待超时;尝试重新启动事务”,事务失败
【发布时间】:2011-04-19 14:53:21
【问题描述】:

当尝试更新某个表时,它会失败,但会出现以下异常:“超过锁定等待超时;尝试重新启动事务”。 一些信息:我有两个表,profile 和 profile_units。 ID是profile表的主键,ID是profile_units中主键的一部分,也是profile中ID的外键。 当我调用 saveProfileChanges 时,updateAllFields 方法成功,但 addStmt.executeUpdate();在 handleActivityUnitsChanges 中失败并出现上述异常。 我使用 MySQL v5.0 作为数据库。我做错了什么?

我尝试执行以下代码:

    public static Profile saveProfileChanges(Profile profile, List unitsToAdd)
        throws Exception
{
    Connection con = null;
    try
    {
        con = ConnectionManager.getConnection();

        updateAllFields(con, profile);

        handleActivityUnitsChanges(con, profile, unitsToAdd);

        con.commit();
        return profile;
    }
    finally
    {
        ConnectionManager.closeConnection(con);
    }
}

private static void handleActivityUnitsChanges(Connection con, Profile profile, List<ActivityUnit> unitsToAdd) throws Exception
{
    PreparedStatement addStmt = null;

    try
    {
        for (ActivityUnit currentUnitToAdd : unitsToAdd)
        {
            String sqlStatement = "insert into profile_units (ID, ActivityUnit) values (?, ?)";
            addStmt = con.prepareStatement(sqlStatement);

            addStmt.setLong(1, profile.getId());
            addStmt.setLong(2, currentUnitToAdd.getId());

            System.out.println(sqlStatement);

            addStmt.executeUpdate();
            addStmt.close();
        }
    }
    catch (Exception e)
    {
        con.rollback();
        throw e;
    }
    finally
    {
        ConnectionManager.closeStatement(addStmt);
    }
}

public static Connection getConnection() throws Exception
{
    Class.forName("com.mysql.jdbc.Driver").newInstance();
    Connection con = DriverManager.getConnection("jdbc:mysql:///someproject", "a", "a");

    con.setAutoCommit(false);

    return con;
}

【问题讨论】:

  • insert into profile_units )ID, ActivityUnit) values (?, ?) - 这是真实的代码吗?
  • 不,应该是 (ID, ActivityUnit) 值 (?, ?)
  • 您的表是否被其他进程锁定?以sql工具为例?
  • 如何运行这段代码?你还有其他并发交易吗?
  • 我不认为有任何其他进程正在运行 - 为了确保我杀死了 MYSql 服务,重新启动它并再次运行它,结果相同(坏)。我从不同的类运行这段代码,并且只运行这段代码。我认为不存在任何其他并发事务。有没有办法检查? (我尝试在 MYSQL 中查看管理面板,但没有发现任何有用的信息)。

标签: java mysql


【解决方案1】:

好的,我发现了问题所在 - 在 updateAllFields 中(出于某种奇怪的原因,我没有在此处显示)我获得了一个新连接,因此两个事务混合在一起。 感谢任何人的帮助!

【讨论】:

    【解决方案2】:

    看一下 innodb_lock_wait_timeout 变量。它是 - InnoDB 事务在回滚之前可能等待锁定的超时秒数。默认值为 50 秒,您可以增加该值;但我认为最好重写循环插入代码或优化一些东西。

    作为一种变体 - 尝试在事务中运行更少的插入语句。 为了加快交易速度,您可以使用多个插入,例如- 'INSERT INTO table1(column1, column2) VALUES(1,'text1'),(2,'text2')...;'

    【讨论】:

    • 问题是,我只在表配置文件中运行 1 更新,到带有键 12 的信号记录(它是 only记录在该表中),并且在我在表 profile_units 中运行插入命令之后立即进行。将两条记录更新并插入到几乎空的数据库中应该不需要 50 秒...
    • 似乎其他进程已锁定表(行),您正在尝试运行其他失败的查询。尝试在失败后使用“SHOW INNODB STATUS”检查 innodb 状态,可能会有有用的信息或当前锁定行的查询。
    • 显示 INNODB 状态日志:mysql 表正在使用 1,锁定 1 LOCK WAIT 3 锁定结构,堆大小 376,1 行锁定 MySQL 线程 id 125,查询 id 1503 localhost 127.0.0.1 根更新插入 profile_units (ProfileId, ActivityId) 值 (1, 2) ------- TRX 已等待 13 秒以获得此锁定:记录锁定空间 id 0 页号 340 n 位 72表PRIMARY 的索引sadnaproject.profile trx id 3AA 锁定模式S 锁定rec 但不是间隙等待记录锁,堆没有2 物理记录:n_fields 10;紧凑的格式; info bits 0 - 这有意义吗?
    • 表示一行被另一个事务锁定。 ...我知道你发现了问题。
    猜你喜欢
    • 2018-10-09
    • 2019-06-02
    • 1970-01-01
    • 2013-09-22
    • 2015-09-27
    • 2019-03-11
    • 2013-06-29
    • 2020-04-18
    • 1970-01-01
    相关资源
    最近更新 更多