【问题标题】:Why can't I merge() my domain object without a LockTimeoutException?为什么我不能在没有 LockTimeoutException 的情况下合并()我的域对象?
【发布时间】:2015-10-17 04:30:39
【问题描述】:

我正在创建一个使用 hibernate 作为持久层的 CRUD API。

API 采用 JSON 并将其序列化为 POJO。然后管理层将 POJO 转换为新的 Hibernate Domain 对象。

CreateUpdate 运行完全相同的代码 - 唯一的区别是,对于 Update,我还设置了休眠对象的 ID 字段。

创建工作正常,但更新失败并显示org.hibernate.exception.LockTimeoutException。经过几个小时的窥探,我将挥舞白旗,希望有人能解释我是白痴的所有原因。

ClientManager 代码

public class ClientManager {

    private static final ClientDAO clientDAO = new ClientDAO();

    ...

    public Client updateClient(ClientVO inputVO) {

        // Generate a Client from the input
        Client client = ClientManager.generateClient(inputVO);
        client.setClientKey(Integer.parseInt(inputVO.getPersonalId()));
        client.setUpdateDate(new Date());
        client.setUpdateTimestamp(new Date());

        // Update the client
        clientDAO.update(client);

    }

    ...

    public static Client generateClient(ClientVO clientVO) {
        Client client = new Client();

        client.setFirstName(clientVO.getFirstName());
        client.setMiddleName(clientVO.getMiddleName());
        client.setLastName(clientVO.getLastName());

        return client;
    }
}

BaseDAO 代码(ClientDAO 扩展 BaseDAO)

public class BaseDAO {
    public Boolean save(Object object) {
        Session session = getSession();
        Transaction tx = session.beginTransaction();
        session.save(object);
        tx.commit();
        session.close();
        return Boolean.TRUE;
    }

    public Boolean update(Object object) {
        Session session = getSession();
        Transaction tx = session.beginTransaction();
        session.merge(object);
        tx.commit();
        session.close();
        return Boolean.TRUE;
    }

    public Session getSession() 
    {
        return HibernateSessionFactory.getSession();
    }   
}

入口点代码

@PUT
@Path("clients/{personalId}")
@Produces({MediaType.APPLICATION_JSON})
public String updateClient(@PathParam("personalId") String personalId, String data) throws JsonParseException, JsonMappingException, IOException {
    ClientVO inputVO = om.readValue(data, ClientVO.class);
    inputVO.setPersonalId(personalId);

    ClientVO outputVO = clientManager.updateClient(inputVO);
    return om.writeValueAsString(outputVO);
}

注意clientKey是主键。

超时发生在 BaseDAO 的 update() 方法中的 .commit() 处。

如果有用的话,我很乐意提供更多代码(例如 ClientVO)。

【问题讨论】:

    标签: java hibernate orm concurrency transactions


    【解决方案1】:

    发生这种情况的唯一方法是您有两个数据库连接都试图修改同一个实体。

    如果这种情况发生在单用户身上,那是因为您没有为整个请求使用同一个 Session,而是创建了多个请求。我会说您在某个外部级别打开了一个 Hibernate Session 和一个事务,当调用 update 方法时,您打开另一个 Session 和一个与可能已经获取的外部冲突的新事务锁定同一个实体(因为您加载了实体并更改了它)。

    【讨论】:

    • 这是一个非常有用的思路——我刚刚收紧了我的会话,以确保我 .close() 他们适当但遗憾的是,问题仍然存在。我会继续挖掘以防我遗漏了什么,我正在更新问题以显示入口点。
    • 我有理由相信我此时没有包装事务 - Hibernate 是否有可能做奇怪的事情,因为我手动设置原始域对象的主键而不是“查找”对象?
    • 我也曾经通过手动设置实体标识符以及来自 DTO 的其他属性来更新实体。这是导致您出现问题的数据库锁。您是否使用了一些触发器来获取其他表中某些其他数据库行的锁?
    • 没有触发器,模式很简单,在这里定义:github.com/PCNI/OpenHMIS/tree/feature-compass_schema/src/main/… ||我会继续挖掘,当我知道更多时会报告。很高兴了解我所做的并不是天生就违反了有关休眠的某些内容。
    猜你喜欢
    • 2021-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多