我正在设计JAX-RS API。
POST /myentities
PUT /myentities/{myentityId}
我确实喜欢这个。
@PUT
@Path("/{myentityId: \\d+}")
@Consumes(...)
@Transactional
public Response updateMyentity(
@PathParam("myentityId") final long myentityId,
final Myentity myentity) {
if (!Objects.equal(myentitiyId, myentity.getId())) {
// throw bad request
}
entityManager.merge(myentity);
return Response.noContent().build();
}
我突然好奇并向自己提出质疑。
当客户调用以下请求时
PUT /myentities/101 HTTP/101
Host: ..
<myentity id=101>
</myentity>
即使没有101
标识的资源,是否可以处理请求?
acceptEntityManager(entityManager -> {
// persist
final Device device1 = mergeDevice(entityManager, null);
entityManager.flush();
logger.debug("device1: {}", device1);
assertNotNull(device1.getId());
// remove
entityManager.remove(device1);
entityManager.flush();
assertNull(entityManager.find(Device.class, device1.getId()));
// merge again, with non existing id
final Device device2 = entityManager.merge(device1);
entityManager.flush();
logger.debug("device2: {}", device2);
});
我发现第二次合并工作并分配了新的ID。
这是正常的吗?难道不会EntityManager#merge
否认这次行动吗?
是否意味着任何客户端都可以通过调用
来攻击APIPUT /myentities/<any number>
答案 0 :(得分:0)
如果我理解这一点,那么是的,这就是合并应该如何运作。
merge
创建实体类的新实例,复制您提供的实体的当前状态(在您的情况下为device1
),并将该新实例添加到事务中。
因此,管理NEW实例,并且您对旧实例所做的任何更改都不会在事务中更新,也不会通过flush
- 操作传播到数据库。
因此,当您使用device1
从数据库中删除entityManager.remove(device1);
时,呼叫为
final Device device2 = entityManager.merge(device1);
将新的副本(带有新ID)添加到数据库中。您对device1
所做的更改不会在事务中进行跟踪,因此一旦您flush
,它们就不会反映在数据库表中。另一方面,将在交易中跟踪对device2
的更改。