【问题标题】:Spring oAuth2 Concurrent Request DeadlockSpring oAuth2 并发请求死锁
【发布时间】:2017-12-18 14:27:33
【问题描述】:

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

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

Handling error: DeadlockLoserDataAccessException, PreparedStatementCallback; SQL [delete from oauth_access_token where token_id = ?]; Deadlock found when trying to get lock; try restarting transaction; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction

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

谢谢

【问题讨论】:

  • 没有人吗?真的吗?
  • 我也遇到过同样的问题,但还不知道怎么解决。你解决了吗?

标签: java mysql spring spring-security-oauth2


【解决方案1】:

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

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

此外,我将 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;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    • 2019-10-18
    • 2012-07-23
    • 1970-01-01
    • 2018-11-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多