У вас все работает правильно и ожидаемо, и транзакции здесь вообще не при чем: фактическое изменение значения в БД у вас происходит спустя 10 секунд (save + commit). Запуская 2 процесса, они оба одновременно считают 0, изменят его на 1, и оба через 10 секунд сохранят эту единицу в БД - естественно, там будет 1.
Вы можете сохранять (save) изменения сразу после изменения на 1, но проблему это не решит, так как фактически другой транзакции изменения буду доступны только после коммита (Советую почитать про уровни изоляции транзакций
https://habrahabr.ru/post/135217/ чтоб понять почему так происходит)
БД с контролем версий могла бы помочь - при попытке перезаписать устаревшие данные такая БД вернула бы ошибку. Но MySQL - не такая БД (впрочем, это можно сделать самому).
То что тебе надо - это чтоб обновление шло последовательно, не параллельно. Это очередь. Можешь сделать ее подобие сам, можешь юзать кучу готовых инструментов, можешь юзать мьютексы (хотя, имхо, в контексте php это сомнительный совет).
Если речь идет чисто о счетчиках - я бы порекомендовал тебе Redis с его incr (он однопоточный и подобных проблем там нет в принципе).
Если же это просто пример и вопрос про то как не запароть важные данные при одновременном изменении - читай про уровни изоляции транзакций и делай версионность данных.