java spring中如何避免使用同一个会话并发访问控制器方法?

awe*_*ome 5 java concurrency spring spring-mvc

我想知道如何确保每个会话一次只访问服务中的某些方法一次。

我将通过一个小例子来说明:

假设我们有一个用户处于状态 A (user.state = A)。这个用户向我们的 java spring 控制器发送一个 HTTP GET 请求来获取一个页面,比如 /hello。根据他的状态,他将被发送到 A 或 B。在此之前,我们将他的状态更改为 B(见下面的代码)。

现在,再次假设调用 dao.doSomething(); 需要很多时间。如果用户发送另一个 GET(例如通过刷新浏览器),他将调用完全相同的方法 dao.doSomething(),导致 2 次调用。

你怎么能避免呢?

如果您同时发送 2 个 HTTP GET 会发生什么?

如何在控制器/服务/模型/数据库中保持一致?

注意 1:这里我们不会从不同的浏览器发出 2 个 HTTP GET。我们只是在同一个浏览器上同时创建它们(我知道最大并发会话解决方案,但这并不能解决我的问题。)。

注2:解决方案不应阻塞不同用户对控制器的并发访问。

我已经阅读了一些关于服务交易的内容,但我不确定这是否是解决方案。我也阅读了一些关于并发的内容,但我仍然不明白如何在这里使用它。

我将不胜感激您的帮助!谢谢!

代码示例:

@Controller
public class UserController {    

    @RequestMapping(value='/hello')
    public String viewHelloPage() {

        // we get the user from a session attribute
        if (user.getState() = A) {
            user.setStatus(B);
            return "pageA";
        }

        return "pageB";
    }


@Service
public class UserService {
    Dao dao;

    @Override
    public void setStatus(User user) {
        dao.doSomething();
        user.setStatus(B);
    }
}
Run Code Online (Sandbox Code Playgroud)

Flo*_*oky 0

如果dao.doSomething()您正在做的工作只想发生一次,则应该使用幂等方法,例如 PUT 或 DELETE。没有法律强制您使用正确的方法,但最坏的情况是,它是一种自我记录的方式,告诉世界应该如何使用您的 API。如果这对您来说还不够,大多数浏览器都会根据请求的类型尝试帮助您。例如,浏览器通常会使用缓存来避免多次 GET。

看来您真正想知道的是如何强制执行幂等性。这是非常特定于应用的。一种通用方法是在服务器端生成并存储一个伪唯一 ID,以便客户端附加到其请求。这样,第一个之后具有相同 id 的任何请求都可以被安全地忽略。显然,旧的 ID 应该被明智地驱逐。

正如我所说,解决方案通常是特定于应用程序的。在上面的例子中,看起来您正在尝试在两种状态之间切换,并且您的实现是服务器端切换。您可以利用客户端来确保多个请求不会出现问题。

@RequestMapping(value="/hello", method=RequestMethod.PUT)
public String test(@RequestParam("state") String state) {
    dao.setState(user, state)
    switch (state) {
        case "A":
            return "B";
        case "B":
            return "A";
        default:
            return "error";
    }
}
Run Code Online (Sandbox Code Playgroud)