
В приложении JPA весенней загрузки соответствующий класс Entity для этой таблицы определяется следующим образом:
Код: Выделить всё
import java.time.LocalDateTime;
import org.hibernate.annotations.UpdateTimestamp;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
@Data
@Entity
@Table(name = "counter", schema = "demo")
public class CounterRow {
@Id
private int row_id;
private int counter;
private String last_user;
@UpdateTimestamp
private LocalDateTime last_updated;
}
Код: Выделить всё
import org.ravi.entity.CounterRow;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
public interface CounterRepository extends JpaRepository {
}
Если каждый поток увеличивает счетчик в 5 раз (в цикле), я ожидаю, что окончательное значение счетчика увеличится на 10 по сравнению с нынешним значением. Однако я вижу, что оно увеличивается только в 5 раз, если предположить, что это может быть связано с неправильной синхронизацией БД.
Это класс, который запускает потоки обновления
Код: Выделить всё
package org.ravi;
import org.ravi.entity.CounterRow;
import org.ravi.repository.CounterRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
@Component
@Slf4j
public class DbSyncTester {
@Autowired
private CounterRepository repository;
@PostConstruct
public void start() {
final Thread thread1 = getThread("Updater_Thread_1");
final Thread thread2 = getThread("Updater_Thread_2");
thread1.start();
thread2.start();
}
private Thread getThread(String threadName) {
return new Thread(getDbTask(), threadName);
}
private Runnable getDbTask() {
return () -> {
int loopCounter = 0;
while (loopCounter++ < 5) {
updateDb();
}
};
}
@Transactional(readOnly = false, isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
private void updateDb() {
log.info("Fetching the counter from the DB");
CounterRow counterRow = repository.findById(1).get();
log.info("Counter value: {}", counterRow.getCounter());
counterRow.setCounter(counterRow.getCounter() + 1);
counterRow.setLast_user(Thread.currentThread().getName());
repository.save(counterRow);
log.info("Updated the counter in the DB to {}", counterRow.getCounter());
}
}
@Transactional(readOnly = false, изоляция = Isolation.READ_COMMITTED, распространение = Propagation.REQUIRED)
Я также пробовал использовать Isolation.SERIALIZABLE< /code>, по-прежнему не работает.
Пожалуйста, помогите мне разобраться в проблеме с блокировками на уровне БД с использованием приведенного выше кода.
Подробнее здесь: https://stackoverflow.com/questions/790 ... pa-applica