gpt4 book ai didi

Java:在多线程和事务环境中运行 DAO 类

转载 作者:行者123 更新时间:2023-12-01 23:10:44 25 4
gpt4 key购买 nike

我从多线程环境调用 DAO 类,该类触发选择查询以从表中获取行(获取 TicketId),然后更新同一行(使用 customerId)。这发生在同一笔交易中。我的数据库是SQL Server。当我触发选择查询时,我尝试放置行级锁(WITH ROWLOCK),以便其他线程不会获得同一行。我的DAO类如下(这里只显示重要的代码):

public void saveCustomerTicketUsingJDBC(String customerId) {
Session session = getSession();
//Session session = SessionFactoryUtils.getSession(getSessionFactory(), true);// Have tried this too
try {
session.getTransaction().begin();



Query query1 = session.createSQLQuery("select TOP 1 * from CustomerTicket WITH (ROWLOCK) where customerId is null");
Object[] customerTicket = (Object[])query1.uniqueResult();

Integer id = (Integer)customerTicket[0];
ticketId = (String)customerTicket[1];
logger.debug("Got ticket id -->"+ticketId);



Query query2 = session.createSQLQuery("update CustomerTicket " +
"set customerId = :customerId " +
"where ticketId = :ticketId");
query2.setParameter("customerId", customerId);
query2.setParameter("ticketId", ticketId);
logger.debug("QUery 2 executeUpdate : customerId : "+customerId+", ticketId :"+ticketId);
int result = query2.executeUpdate();
logger.debug("result >"+result +", customerTicketId ----------->"+customerId+", ticketId ------------>"+ticketId);
//session.flush();
//session.clear();
session.getTransaction().commit();
} catch (Exception e) {
logger.error("Exception while saving customer ticket-->"+e,e);
} finally {
if (session != null) {
session.close();
}
}
}

我生成了 4 个线程。我在日志文件中看到的是,所有四个线程都访问数据库表中的同一记录。

2014-02-26 22:41:29.183 DEBUG [pool-3-thread-2] CustomerTicketDAO.java:83 Got ticket id -->4
2014-02-26 22:41:29.183 DEBUG [pool-3-thread-4] CustomerTicketDAO.java:83 Got ticket id -->4
2014-02-26 22:41:29.184 DEBUG [pool-3-thread-3] CustomerTicketDAO.java:83 Got ticket id -->4
2014-02-26 22:41:29.184 DEBUG [pool-3-thread-1] CustomerTicketDAO.java:83 Got ticket id -->4

首先这不应该发生,对吗?我希望看到每个线程应该获得不同的行。

然后我看到只有一个线程能够成功更新数据库。

2014-02-26 22:41:29.408 DEBUG [pool-3-thread-1] CustomerTicketDAO.java:93 result >1, customerTicketId ----------->CustomerId_0, ticketId ------------>4

其他三个线程在该行死亡:

int result = query2.executeUpdate();

我不明白其他三个线程发生了什么,因为我在日志文件中没有看到任何内容。

请有人帮助我。

谢谢拉杰

最佳答案

目前还不清楚(至少对我来说),在 3 次失败的 tx 情况下,Sql Server 和 hibernate 究竟返回了什么错误。但他们失败并不奇怪。

(行)锁不是队列,也不是过滤器。四个选择查询将返回同一行并不奇怪,因为锁的存在不会更改数据,因此也不会更改查询结果 - 它只是保护对数据的访问 。我怀疑,但不知道, hibernate 可能会通过缓存查询来绕过锁。

根本问题是有四个进程都在争夺单个资源(第一个未分配的票证)。虽然正确实现的行锁定方案可行,但它是一个糟糕的选择,因为它的扩展性不如其他方案。

你最好用同步块(synchronized block)来编写你的 dao。这将处理应用程序服务器中的多个线程同时争用资源的情况。最简单的方法是这样做:

public synchronized void saveCustomerTicketUsingJDBC(String customerId) {
Session session = getSession();
...
}

这可以很好地处理单个应用程序服务器的情况,尽管您需要注意不能保证线程的执行顺序。根据您的变量名称,我怀疑这对您来说可能是个问题,但即使是这样,这个解决方案也不会让问题变得更糟。

如果您有多个应用程序服务器,那么您仍然可以有多个进程争夺同一资源。同样,这可以通过(悲观)行锁来解决,但我怀疑您最好使用乐观锁定解决方案。乐观锁看起来像这样:

while (true) {
session.getTransaction().begin();

try {
Query query1 = session.createSQLQuery("select TOP 1 * from CustomerTicket where customerId is null");
Object[] customerTicket = (Object[])query1.uniqueResult();

Integer id = (Integer)customerTicket[0];
ticketId = (String)customerTicket[1];
logger.debug("Got ticket id -->"+ticketId);

Query query2 = session.createSQLQuery("update CustomerTicket " +
"set customerId = :customerId " +
"where ticketId = :ticketId AND customerId is NULL");
// Notice the AND clause!!!
query2.setParameter("customerId", customerId);
query2.setParameter("ticketId", ticketId);
logger.debug("QUery 2 executeUpdate : customerId : "+customerId+", ticketId :"+ticketId);
int updateCount = query2.executeUpdate();
logger.debug("updateCount >"+updateCount +", customerTicketId ----------->"+customerId+", ticketId ------------>"+ticketId);

// Did someone beat us to it?
if (updateCount == 0) {
session.getTransaction().rollback();
continue;
}

// Nope - we're winning so far, but the race isn't over yet...
session.getTransaction().commit();
} catch (OptimisticLockException ex) {
logger.debug("Darn, someone DID beat us to it");
session.getTransaction().rollback();
continue;
} catch (Exception ex) {
...
}

break;
}

关于Java:在多线程和事务环境中运行 DAO 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22058662/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com