java - Spring oAuth2并发请求死锁

标签 java mysql spring spring-security-oauth2

我正在使用 org.springframework.security.oauth2 库和 MySQL 5.5.58

大部分时间它都按预期工作,没有任何问题。 但是,似乎当 多个请求 对“/oauth/token”同时发生(每个请求在不同的服务器节点上)时,服务器正在争夺 db 记录并且出现死锁:

处理错误:DeadlockLoserDataAccessException,PreparedStatementCallback; SQL [从 oauth_access_token 中删除 token_id = ?];尝试获取锁时发现死锁;尝试重启交易;嵌套的异常是 com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock;尝试重启事务

还有其他人看到过这个问题吗?我怎样才能避免这种行为?

谢谢

最佳答案

此并发问题导致生成 2 个具有相同 token_id 的 oauth_access_token。 因此,稍后当 JdbcTokenStore 尝试通过其 key (token_id)获取 oauth_access_token 或删除它时,操作可能会因以下原因而失败 NonUniqueResultException 或 DeadlockLoserDataAccessException。

我的解决方案是更新 oauth_access_token 架构以对 token_id 具有唯一约束,以便首先避免不正确的重复。 请注意,这确实意味着第二个请求会失败(无论如何都是多余的),但至少该用户只有一个 token ,并且数据将保持有效且不会损坏。

此外,我扩展了 JdbcTokenStore 作为我的 CustomTokenStore,扩大了错误处理和清理的范围,以保持数据库处于稳定状态。

@Override
public OAuth2Authentication readAuthentication(OAuth2AccessToken token) {
    try{
        return super.readAuthentication(token.getValue());
    }
    catch (RuntimeException e){
        OAuth2RefreshToken refreshToken = token.getRefreshToken();
        removeRefreshToken(refreshToken);
        removeAccessToken(token);
        logger().error("readAuthentication", e);
        throw e;
    }
}

@Override
public OAuth2AccessToken getAccessToken(OAuth2Authentication authentication) {
    logger().info("getAccessToken begin");
    try{
        return super.getAccessToken(authentication);
    }
    catch (IncorrectResultSizeDataAccessException e){
        logger().error("getAccessToken", e);
        safeRemoveAllAccessToken(authentication);
    }
    catch (RuntimeException e){
        logger().error("getAccessToken", e);
    }
    return null;
}

@Override
public OAuth2Authentication readAuthentication(String token) {
    try{
        OAuth2Authentication oAuth2Authentication = super.readAuthentication(token);

        if(oAuth2Authentication == null){
            removeAccessToken(token);
            removeRefreshToken(token);
        }
        return oAuth2Authentication;
    }
    catch (RuntimeException e){
        logger().error("readAuthentication", e);
        throw e;
    }
}

关于java - Spring oAuth2并发请求死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47870548/

相关文章:

java - Android Studio : Discrepency between Gradle versions mentioned in Gradle file and File > Project Structure > Project

mysql - 将数据拆分到多个数据库的良好做法?

java - 如何使用 spring mongo data api 更新嵌入式 mongo 文档

java - 将自定义方法添加到 Spring Data JPA

java - 如何测试 vector 中找到的元素?

Java - 将返回 boolean 值和索引的 int 数组

mysql - 如何交换返回集中的行?

php - 全文搜索的正确方法

java - Spring Boot的@ConfigurationProperties不再起作用

java - 从规则 jess 或 drools(专家系统)返回一个值