对于经典Servlet的同步,我有一个非常基本的疑问 - >服务 - > DAO模式。
假设我有一个由多个并发用户访问的票务预订应用程序。没有两个用户应该最终预订同一张票。当两个不同的用户尝试访问机票预订时,我认为会发生以下情况 -
现在,为了避免两个用户预订相同的机票,必须在哪里进行同步?
是在BookingService还是在BookingDAO?
但是,这是我的疑问,对于每个请求,我们实际上创建了一个单独的BookingService和BookingDAO对象 - 这不会破坏将同步放在那里的目的吗?
答案 0 :(得分:1)
有多种方法可以解决您的问题。
BookingService
和/或BookingDAO
单身人士。通常不需要有更多实例。然后你可以做同步。或者您可以在课堂上进行同步。例如。 synchronized(BookingService.class)
。仅当您只运行一个应用程序实例时,此方法才有效。因此,我建议使用第二个选项(假设您使用的是关系数据库)
update ticket set reserved_by = 'CustomerA' where ticket_id = 23 and reserved_by = null
更新后,您需要检查更新行的数量。如果是1
,那么一切都很好,如果是0
,则意味着其他人保留了中间票,客户需要进行新的预订。答案 1 :(得分:0)
唯一标识符
一个相对简单的解决方案可以使用Java UUID。我们在项目中使用此方法,以确保人们无法同时创建相同的lobby
。
import java.util.UUID;
public class GenerateUUID {
public static final void main(String... aArgs){
//generate random UUIDs
UUID idOne = UUID.randomUUID();
UUID idTwo = UUID.randomUUID();
log("UUID One: " + idOne);
log("UUID Two: " + idTwo);
}
private static void log(Object aObject){
System.out.println( String.valueOf(aObject) );
}
}
此外,如果您希望降低一个用户与另一个用户获得相同UUID
的可能性。您可以将用户的Primary Key
连接到 UUID 的末尾。
例如067e6162-3b6f-4ae2-a171-2470b63dff00
变为067e6162-3b6f-4ae2-a171-2470b63dff00-23
,如果每个用户包含不同Primary Key
概率,则两个用户点击相同Token
的概率非常低。
- 创建唯一的会话ID,例如
UUID sessionID = UUID.randomUUID();
- 开始交易
- 从DB中删除与请求中的任何令牌匹配的任何令牌,例如
DELETE FROM Tokens WHERE TokenID = < requested-token>- 获取受影响的行数
- 如果受影响的行数正好为1,则令牌有效。创建一个会话,例如
插入会话VALUES(sessionUUID,userID,loginTime,...)- 提交交易
醇>
source: finnw,java: race conditions - is there a way to make sure several lines of code will be executed together?
相互排斥
否则我相信,您需要开发一些互相排斥的东西,以便双方(预订机票的人不能同时预订同一张机票)。看Lamport's bakery algorithm
Lamport在其入口处设想了一家带有编号机的面包店,因此每个客户都会得到一个唯一的号码。当顾客进入商店时,数字会增加一。全局计数器显示当前正在服务的客户的编号。所有其他客户必须排队等待,直到面包师完成为当前客户提供服务并显示下一个号码。当顾客完成购物并且已经处理了他或她的号码时,店员递增号码,允许下一个顾客被送达。该客户必须从编号机中抽取另一个号码才能再次购物。
例如,使用static LinkedList
来跟踪今天订购的每个票号。