postgresql - 两个并发请求能够锁定 Postgres sql 中的同一行
问题描述
当对以下代码发出两个并发请求时,两个请求都能够同时获取锁,因此能够执行代码块
在生产中运行的示例代码:
示例代码供参考:
//Starting point for the request
@Override
public void receiveTransferItems(String argumet1, String refernceId, List<Item> items, long messageId)
throws Exception {
ParentDTO parent = DAO.lockByReferenceid(referenceId);
if (parent == null) {
throw new Exception(referenceId + "does not exist");
}
updateData(parent);
for (Item item : items) {
receiveItem(td, td.getWarehouseId(), item.getItemSKU(), item.getItemStatus(), item.getQtyReceived(), messageId);
}
}
private void updateData(ParentDTO td) throws DropShipException {
//perform some logical processing and then execute update
DAO.update(td);
}
private void receiveItem(ParentDTO td, String warehouseId, String asin, String itemStatus, int quantity, long messageId)
throws Exception {
/**
* perform some logical processing
*
**/
//call is being made to another class to do the rest of the processing
service.receive(td, asin, quantity, condition, container, messageId);
}
@Override
public void receive(
ParentDTO parentDTO,
String asin,
int quantity,
Condition condition,
Container container,
long messageId,
DataAccessor accessor) throws Exception {
List<ChildDTO> childDTOs =
DAO.lockChildDTOItems(parentDTO.getReferenceId(), asin, condition,
CostInfoSource.MANIFEST);
List<ChildDTO> filterItems = DAO
.loadChildDTOItems(parentDTO.getReferenceId(), asin, condition.name());
long totalExpectedQuantity = getTotalExpectedQuantity(filterItems);
long totalReceivedQuantity = getTotalReceivedQuantity(filterItems);
int quantityNormalReceived = 0;
for (ChildDTO tdi : childDTOs) {
int quantityReceived = 0;
if (asinDropShipMsgAction != null) {
quantity -= asinDropShipMsgAction.getInitialQuantity();
quantityNormalReceived += asinDropShipMsgAction.getInitialQuantity();
} else {
quantityReceived = new DBOperationRunner<Integer>(accessor.getSessionManager()) {
@Override
protected Integer doWorkAndReturn() throws Exception {
return normalReceive(tdi, quantityLeft, container, MessageActionType.TS_IN, messageId);
}
}.execute();
}
}
}
private int normalReceive(final ChildDTO childDTO,
int quantity,
final Container container,
final MessageActionType type,
long messageId)
throws Exception {
/**
* perform some business logic
*
* */
DAO.update(childDTO);
return someQuantity;
}
lockByReferenceId 函数的实现:
@Override
public ParentDTO lockByReferenceId(String referenceId) {
Criteria criteria = getCurrentSession().createCriteria(ParentDTO.class)
.add(Restrictions.eq("referenceId", referenceId)).setLockMode(LockMode.UPGRADE_NOWAIT);
return (ParentDTO) criteria.uniqueResult();
}
DBOperationRunner 类的实现:
public T execute() throws Exception {
T t = null;
Session originalSession = (Session) ThreadLocalContext.get(ThreadLocalContext.CURRENT_SESSION);
try {
ThreadLocalContext.put(ThreadLocalContext.CURRENT_SESSION, sessionManager.getCurrentSession());
sessionManager.beginTransaction();
t = doWorkAndReturn();
sessionManager.commit();
} catch (Exception e) {
try {
sessionManager.rollback();
} catch (Throwable t1) {
logger.error("failed to rollback", t1);
}
throw e;
} finally {
ThreadLocalContext.put(ThreadLocalContext.CURRENT_SESSION, originalSession);
}
return t;
}
最近我在生产代码中观察到一个问题,其中两个或多个同时请求能够同时获取相同数据的锁定。我使用休眠和标准作为数据库框架,使用 c3p0 作为连接池框架,使用 Postgres 作为数据库。注意:此问题是间歇性的,仅在一些难以调试的随机并发请求中观察到。
我无法理解两个并发请求如何能够同时锁定相同的行。您能帮我确定在这种情况下出了什么问题吗?
提前致谢!!!!
解决方案
推荐阅读
- html - 如何使用 Flexbox CSS 将每个元素放在一个角落?
- javascript - 等待 querySelectorAll
- bash - 如何从配置文件中匹配花括号 {} 中的字符串和打印行
- android - Android Studio 相对布局和线性布局不适合某些设备
- dropdown - HTA 中的多级下拉菜单未正确加载
- javascript - 如何使用 PHP 在全日历中显示事件
- javascript - 使用 Google Maps Geocoding API 确定位置的地址
- scala - 泛型函数中 T 的匿名推导
- datetime - 谷歌表格脚本编辑器的功能,在两个不同的列中有一个 TODAY() 和 NOW() 按钮,其中下一个不是该列中的空白
- c++ - 为什么这行代码会产生错误?