← Назад к вопросам

В чем разница между грязным чтением и фантомным чтением?

1.0 Junior🔥 121 комментариев
#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Грязное чтение vs Фантомное чтение

Это два различных типа проблем конкурентности, которые возникают при работе с базами данных. Важно понимать их различия для правильной работы с транзакциями.

Грязное чтение (Dirty Read)

Грязное чтение происходит, когда транзакция читает данные, которые были изменены другой транзакцией, но еще не зафиксированы (не выполнен COMMIT). Если вторая транзакция откатится, то первая получит некорректные данные.

// Транзакция 1
Transaction tx1 = session.beginTransaction();
User user = session.get(User.class, userId);
int balance = user.getBalance(); // Чтение значения
tx1.commit();

// Одновременно Транзакция 2
Transaction tx2 = session.beginTransaction();
User user2 = session.get(User.class, userId);
user2.setBalance(user2.getBalance() - 100);
// Если здесь произойдет откат, то tx1 получила грязные данные
tx2.rollback();

Фантомное чтение (Phantom Read)

Фантомное чтение возникает, когда при повторном выполнении запроса с одинаковыми условиями появляются новые строки, которых не было при первом запросе. Это происходит, когда другая транзакция добавила или удалила строки, удовлетворяющие условию WHERE.

// Транзакция 1
Transaction tx1 = session.beginTransaction();
List<User> users = session.createQuery(
    "FROM User WHERE age > :age"
)
.setParameter("age", 18)
.list(); // Получено 5 пользователей

// Одновременно Транзакция 2 добавляет нового пользователя
Transaction tx2 = session.beginTransaction();
User newUser = new User();
newUser.setAge(25);
session.save(newUser);
tx2.commit();

// Повтор запроса в tx1
users = session.createQuery(
    "FROM User WHERE age > :age"
)
.setParameter("age", 18)
.list(); // Теперь 6 пользователей - фантомное чтение

tx1.commit();

Основные отличия

ХарактеристикаГрязное чтениеФантомное чтение
Тип проблемыЧтение незафиксированных измененийПоявление новых строк в результате
ВызваноИзменением одной строкиДобавлением/удалением строк
ОткатДелает данные некорректнымиИзменяет размер результата
Уровень изоляцииПредотвращается READ_COMMITTED и вышеПредотвращается SERIALIZABLE

Уровни изоляции транзакций

Для предотвращения этих проблем используются уровни изоляции:

  1. READ_UNCOMMITTED — грязное чтение возможно
  2. READ_COMMITTED — грязное чтение исключено
  3. REPEATABLE_READ — грязное и неповторяющееся чтение исключены (но фантомные возможны)
  4. SERIALIZABLE — все проблемы исключены
// В Hibernate/JPA
@Transactional(isolation = Isolation.SERIALIZABLE)
public void safeDatabaseOperation() {
    // Максимальная защита, но снижение производительности
}

Практический пример на Java

@Service
public class TransactionService {
    
    @Autowired
    private UserRepository userRepository;
    
    // REPEATABLE_READ - защита от грязного и фантомного чтения
    @Transactional(isolation = Isolation.REPEATABLE_READ)
    public void processUsers() {
        // Первое выполнение запроса
        List<User> users = userRepository.findByAgeGreaterThan(18);
        
        // Если другой процесс добавит пользователя age > 18,
        // при повторе запроса они будут видны (фантом)
        users = userRepository.findByAgeGreaterThan(18);
    }
}

Понимание этих различий критично при проектировании надежных приложений, где необходимо обеспечить целостность данных и предотвратить возможные race conditions.

В чем разница между грязным чтением и фантомным чтением? | PrepBro