Java 用户双击按钮后在数据库中重复插入

Java 用户双击按钮后在数据库中重复插入,java,hibernate,spring-mvc,Java,Hibernate,Spring Mvc,我在一个网站上工作,人们可以通过点击触发AJAX POST请求的链接订阅锦标赛。 该应用程序是用SpringMVC和Hibernate构建的 有时,当用户双击时,可能会在数据库中注册两次。 我试着放置一些javascript安全设置,但似乎还不够 所以我猜,这两个请求几乎是同时播放的,第二个请求在第一个请求保存到数据库之前通过了isUserAlreadySubscribed测试 Hibernate有没有办法在这个特定的方法上放置一种令牌?也许也有与会议有关的事情 下面是控制器调用的服务方法 @O

我在一个网站上工作,人们可以通过点击触发AJAX POST请求的链接订阅锦标赛。 该应用程序是用SpringMVC和Hibernate构建的

有时,当用户双击时,可能会在数据库中注册两次。 我试着放置一些javascript安全设置,但似乎还不够

所以我猜,这两个请求几乎是同时播放的,第二个请求在第一个请求保存到数据库之前通过了isUserAlreadySubscribed测试

Hibernate有没有办法在这个特定的方法上放置一种令牌?也许也有与会议有关的事情

下面是控制器调用的服务方法

@Override
@Transactional
public boolean joinTournament(String username, Long eventId, String date, Long barId) {
        [... check if tournament exists ...] 
        if (!isUserAlreadySubscribed(tournament, username)) {
            //On enregistre le user comme inscrit
            TournamentPlayer tournamentPlayer = new TournamentPlayer();
            tournamentPlayer.setPresent(false);
            tournamentPlayer.setTournament(tournament);
            com.meltdown.users.domain.User user = hibernateUserDao.findByUsername(username);
            tournamentPlayer.setUser(user);
            java.util.Date today = new java.util.Date();
            tournamentPlayer.setCreatedAt(new Timestamp(today.getTime()));
            hibernateTournamentDao.createTournamentPlayer(tournamentPlayer);
            tournament.getPlayers().add(tournamentPlayer);

            hibernateTournamentDao.editTournament(tournament);

            [... send mail ...]
            return true;
        }
    return false;
}

看起来您已经在使用带有
Transactional
注释的声明性事务管理了。所以你可能想看看你想用什么。作为一个测试,看看它是否解决了您的问题,您可以将该方法更改为使用最严格的隔离:

@Transactional(isolation=Isolation.SERIALIZABLE)

如果成功,您可以降级到更高的性能级别,例如
READ\u COMMITTED

是否使用JPA实体类?如果是,那么您使用的是版本注释还是版本字段()?我使用的是JPA实体,但不是@version注释。我无法降低隔离级别tough@Labe-可能想修复您的javascript nextI开始时添加了javascript机制,但似乎无法完全修复问题$aSubscribeBtn.click(函数(e){this.disabled=true;e.preventDefault();[…]@Labe刚刚为javascript打开了一个新问题;这可能是一个非常简单的修复方法