为什么我不能在没有LockTimeoutException的情况下合并()我的域对象?

时间:2015-07-27 05:23:27

标签: java hibernate orm concurrency transactions

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

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

对于CreateUpdate运行完全相同的代码 - 唯一的区别是对于Update我还设置了hibernate对象的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)。

1 个答案:

答案 0 :(得分:4)

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

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