首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java MySQL死锁(多线程)

Java MySQL死锁(多线程)
EN

Stack Overflow用户
提问于 2014-06-06 23:07:22
回答 4查看 657关注 0票数 0

我遇到了奇怪的僵局,我不太明白为什么会这样

如果两个线程同时调用这个方法,我将得到以下异常:

代码语言:javascript
复制
java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction

这就是方法

代码语言:javascript
复制
public void saveItems(List<Pair<Item, MapleInventoryType>> items, int id) throws             SQLException {
    synchronized (this) {
        PreparedStatement ps = null;
        PreparedStatement pse = null;
        try {
            StringBuilder query = new StringBuilder();
            query.append("DELETE FROM `inventoryitems` WHERE `type` = ? AND `");
            query.append(account ? "accountid" : "characterid").append("` = ?");
            Connection con = DatabaseConnection.getConnection();
            ps = con.prepareStatement(query.toString());
            ps.setInt(1, value);
            ps.setInt(2, id);
            ps.executeUpdate(); //DEADLOCK OCCURS HERE
            ps.close();

            for (Pair<Item, MapleInventoryType> pair : items) {
                Item item = pair.getLeft();
                MapleInventoryType mit = pair.getRight();
                ps = con.prepareStatement("INSERT INTO `inventoryitems` VALUES (DEFAULT, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS);
                ps.setInt(1, value);
                ps.setString(2, account ? null : String.valueOf(id));
                ps.setString(3, account ? String.valueOf(id) : null);
                ps.setInt(4, item.getItemId());
                ps.setInt(5, mit.getType());
                ps.setInt(6, item.getPosition());
                ps.setInt(7, item.getQuantity());
                ps.setString(8, item.getOwner());
                ps.setInt(9, item.getPetId());
                ps.setInt(10, item.getFlag());
                ps.setLong(11, item.getExpiration());
                ps.setString(12, item.getGiftFrom());
                ps.executeUpdate();

                if (mit.equals(MapleInventoryType.EQUIP) || mit.equals(MapleInventoryType.EQUIPPED)) {
                    pse = con.prepareStatement("INSERT INTO `inventoryequipment` VALUES (DEFAULT, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
                    try (ResultSet rs = ps.getGeneratedKeys()) {

                        if (!rs.next()) {
                            throw new RuntimeException("Inserting item failed.");
                        }

                        pse.setInt(1, rs.getInt(1));
                    }
                    ps.close();

                    Equip equip = (Equip) item;
                    pse.setInt(2, equip.getUpgradeSlots());
                    pse.setInt(3, equip.getLevel());
                    pse.setInt(4, equip.getStr());
                    pse.setInt(5, equip.getDex());
                    pse.setInt(6, equip.getInt());
                    pse.setInt(7, equip.getLuk());
                    pse.setInt(8, equip.getHp());
                    pse.setInt(9, equip.getMp());
                    pse.setInt(10, equip.getWatk());
                    pse.setInt(11, equip.getMatk());
                    pse.setInt(12, equip.getWdef());
                    pse.setInt(13, equip.getMdef());
                    pse.setInt(14, equip.getAcc());
                    pse.setInt(15, equip.getAvoid());
                    pse.setInt(16, equip.getHands());
                    pse.setInt(17, equip.getSpeed());
                    pse.setInt(18, equip.getJump());
                    pse.setInt(19, 0);
                    pse.setInt(20, equip.getVicious());
                    pse.setInt(21, equip.getItemLevel());
                    pse.setInt(22, equip.getItemExp());
                    pse.setInt(23, equip.getRingId());
                    pse.executeUpdate();
                    pse.close();
                }
            }
        } finally {
            if (ps != null) {
                ps.close();
            }
            if (pse != null) {
                pse.close();
            }
        }
}

我不明白死锁是如何发生的,因为所有东西都封装在同步块中。

非常感谢您的帮助,谢谢。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2014-06-06 23:16:09

检查您的事务隔离级别。

您是否将autoCommit()设置为false?如果为true,那么当您在事务的上下文中运行时,您需要在工作后提交它,因为如果您的事务隔离级别与Repeatable Read一样强,那么锁在活动事务的上下文中,直到提交发生。

给我们更多你在做什么的细节。

票数 1
EN

Stack Overflow用户

发布于 2014-06-06 23:11:25

我不明白死锁是如何发生的,因为所有东西都封装在同步块中。

您可以让另一个进程/线程执行例如在同一表中插入。取决于您的DB是如何配置的,您可能会得到正在得到的异常。这里的同步块只意味着没有其他Java线程可以同时调用/进入同一代码块。这并不能阻止同一DB资源表/页/记录(在DB级别上)同时被另一个进程/线程访问。

票数 0
EN

Stack Overflow用户

发布于 2014-06-06 23:25:24

我注意到你没有在你的连接上打close()电话。试着用它来代替最后的{}块。希望这能有所帮助。

代码语言:javascript
复制
    finally {
        if (ps != null) ps.close();
        if (pse != null) pse.close();
        if (con != null) con.close();
    }
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24091897

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档