Одновременная согласованность дебета, проблемы с идемпотентностью, эта тема еще не закрыта! ! !

Java база данных

«Параллельный вывод, как обеспечить согласованность данных? 》, когда один и тот же пользователь одновременно списывает средства, существует определенная вероятность несогласованности данных.Вы можете использовать метод оптимистической блокировки CAS, чтобы обеспечить согласованность данных без снижения пропускной способности и с небольшими изменениями.

Менее чем через 24 часа после публикации статьи было почти 200 комментариев.

Среди них наиболее часто задаваемые вопросыАВА-проблема, эта проблема обсуждалась в разделе "Оптимизация согласованности параллельного вывода, проблема ABA в CAS, эта тема еще не закончена! ! ! "Расширенный.

Во-вторых, большинство задаваемых вопросов являются домашними заданиями, почемуиспользовать select&setспособ сделатьбаланс отпишитесь:

UPDATE t_yue SET money=newmoneyWHEREuid=new_money WHERE uid=uid AND money=$old_money;

Почемунельзя использоватьМетод прямого вывода:

UPDATE t_yue SET money=money-diffWHEREuid=diff WHERE uid=uid;

Многие говорят, что в случае параллелизма деньги будут вычитаться в отрицательное число.

Чтобы сохранить балансне тарифицироваться как отрицательное число, плюс условие where:

UPDATE t_yue SET money=money-diffWHEREuid=diff WHERE uid=uid AND money-$diff>0_;_

Это возможно?

_Голос за кадром: _Ну, кроме бизнеса, этот SQL, использующий столбцы для операций, на самом деле не годится.Рекомендуется использовать:

UPDATE t_yue SET money=money-diffWHEREuid=diff WHERE uid=uid AND money>$diff_;_

Извините, все еще не работает. Причина вКак обеспечить согласованность данных для параллельных выводов?"Самый популярный комментарий в статье,не идемпотент.

_Голос за кадром: _Объясните, что большинство учащихся могут правильно ответить на домашнее задание.

Прежде чем говорить об идемпотентности, давайте рассмотрим еще один тестовый пример.

Предположим, что есть сервисный интерфейс,Зарегистрировать нового пользователя:

bool RegisterUser(uid,uid, name){

// Проверить, существует ли уже uid

select uid from t_user where uid=$uid;

// Не новый пользователь, ошибка возврата

if(rows>0)return false;

else{

// вставить нового пользователя в таблицу пользователей

insert into t_user values(uid,uid, name);

// вернуть успех

return true;

}

}

Есть инженер-испытатель, который написалпрецедент:

bool TestCase_RegisterUser(){

// сделать некоторые поддельные данные

long uid=123;

String name='shenjian';

// вызвать тестируемый интерфейс

bool result= RegisterUser(uid,name);

// Ожидается успешная регистрация,Делайте утверждения о результатах

Assert(result,true);

// вернуть результат теста

return result;

}

Это хороший тест?
Что не так с этим вариантом использования?

Вы обнаружите, что при одних и тех же условиях этот тестовый пример выполняется дважды, и результаты разные:

(1) первое выполнение, первое создание данных, вызывающий интерфейс и успешная регистрация;

(2) При втором выполнении снова создаются те же данные, вызывается интерфейс, и регистрация завершается ошибкой;

Это не хороший тестовый пример, несколько запусков дают разные результаты.

Что такое идемпотентность?

При тех же условиях выполняется тот же запрос и тот же результат, то есть идемпотент.

Голос за кадром: Погуглите, объясните лучше, чем я могу, но должно быть понятно.

Как изменить приведенный выше тестовый пример на «идемпотентный» тестовый пример?

Просто добавьте одну строку кода:

bool TestCase_RegisterUser(){

// создаем поддельные данные

long uid=123;

строка then = 'Экскалибур';

// Сначала удалите этого фальшивого пользователя

DeleteUser(uid);

// вызов тестируемого интерфейса

bool result= RegisterUser(uid,name);

// Ожидаем, что регистрация будет успешной, и делаем вывод о результате

Assert(result,true);

// возвращаем результат теста

return result;

}

так,на тех же условиях, независимо от того, сколько раз выполняется этот вариант использования, результат теста одинаков.

Вы немного относитесь к идемпотентности?

Запросы на чтение, как правило, идемпотентны.

Пишите запросы по мере необходимости:

  • вставка x, вообще говоря, не является идемпотентной, и результаты, полученные повторной вставкой, не обязательно будут одинаковыми.

  • delete x, вообще говоря, является идемпотентным, и результат многократного удаления все тот же

  • установить a=x идемпотентно

  • set a=a-x не является идемпотентным

Итак, вычитаем остаток следующим образом:

UPDATE t_yue SET money=newmoneyWHEREuid=new_money WHERE uid=uid AND money=$old_money;

является идемпотентной операцией.

Если вычесть остаток следующим образом:

UPDATE t_yue SET money=money-diffWHEREuid=diff WHERE uid=uid AND money-$diff>0;

не является идемпотентной операцией.

Говоря здесь, может быть, некоторые друзья собираются поднять планку,Тестовый пример будет выполняться повторно, как можно повторно выполнять вывод?

Повторить.

Retry — очень распространенный метод обработки исключений.

Вы когда-нибудь писали такой код, когда писали свой бизнес:

result = DoSomething();

if(false==result || TIMEOUT){

// ошибка или тайм-аут, попробуйте еще раз

result= DoSomething();

}

return result;

Конечно, найдутся друзья, которые снова поднимут планку, и я больше никогда не буду пробовать! ! !

Голос за кадром: А, это успех или провал?

Вы сами решаете, как писать бизнес-код.Не могу решить, как написать базовый код фреймворка:

(1) Платформа сайта автоматически повторяет попытку?

(2) Платформа службы автоматически повторяет попытку?

(3) Автоматически ли повторяются попытки пула соединений службы и пула соединений базы данных?

Голос за кадром:

(1) В многоуровневой архитектуре на основе служб рекомендуется, чтобы повторные попытки выполнялись только на уровне входа, а уровень служб не должен повторять попытки для предотвращения лавин;

(2) Нижний уровень dubbo, время ожидания вызова повторяется по умолчанию, этот дизайн не очень хорош;

следовательно,В архитектурах с повторными попытками необходимо учитывать идемпотентность..

Теперь пришло время понять, почему бизнес удержания и пополнения обычно используется:

  • выберите и установите, с решением CAS

Вместо того, чтобы использовать:

  • установить схему деньги-=Х

Голос за кадром: Я оплатил 100 телефонных счетов, зачем еще 200 юаней?

знай это, знай это, я надеюсь, что у каждого есть что-то получить.

Путь архитектора- Делитесь техническими идеями

Также есть много комментариев от друзей: номер версии, CAS можно использовать только при низком параллелизме, а при высоком параллелизме будет много сбоев модификации. Может быть, все неправильно поняли «высокий параллелизм». Давайте поговорим о связанных с этим вопросах в следующей статье.