В учебных целях я хочу привести пример с грязным чтением. Использование уровня изоляции READ_UNCOMMITED. Однако я не могу заставить этот пример работать. Я пробовал много разных вещей, но это все равно не работает. Поэтому я надеюсь, что вы сможете мне помочь.
Сценарий:
- Начать транзакцию «основная»
- Вставить человека в новую транзакцию («основная» транзакция приостановлена )
- Обновление имени человека в основной транзакции
- Грипп sh обновление
- Чтение человека в новой транзакции (уровень изоляции READ_UNCOMMITTED)
- Следует прочитать данные обновленного лица -> Это не работает!
- Восстановить основную транзакцию, выдав исключение RuntimeException
- Подтвердите, что это исходное имя человека находится в базе данных -> Это работает
См. код ниже для получения дополнительной информации.
Я также протестировал базу данных Postgres, но это не имело никакого значения. Также пытался делать все с шаблонами JDB C вместо ORM-картографа, но это тоже не имело никакого значения.
Заранее спасибо.
С наилучшими пожеланиями, Marinus
IsoliationLevelTest (src / test / java / test)
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SpringBootTestApplication.class})
public class IsoliationLevelTest {
@Autowired
private TestService testService;
@Autowired
private UtilService serviceUtil;
@After
public void tearDown() {
serviceUtil.deleteTestPersons();
}
@Test
public void testIsolationLevel() {
try {
testService.testIsolationLevel("Piet", "PietUpdated");
} catch (TestService.TestException e) {
List<PersonJPAEntity> persons = serviceUtil.retrieveTestPersons();
assertEquals(1, persons.size());
assertEquals("Piet", persons.get(0).getName());
assertEquals("PietUpdated", e.getPersonReadInNewTransaction().getName());
}
}
}
SpringBootTestApplication (src / main / java / test)
@SpringBootApplication
@EnableAspectJAutoProxy(exposeProxy = true)
public class SpringBootTestApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootTestApplication.class, args);
}
}
TestService
@Service
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
public class TestService {
Logger logger = LoggerFactory.getLogger(TestService.class);
@Autowired
private PersonRepository personRepository;
@Transactional(propagation = REQUIRES_NEW, isolation = Isolation.READ_UNCOMMITTED)
public void testIsolationLevel(String initialName, String newName) {
//Requires_new propagation so transaction is committed after person is save
TestService self = (TestService) AopContext.currentProxy();
self.insertPerson(new PersonJPAEntity(1, initialName));
//Required propagation so this update runs in current transaction (which is not committed yet)
self.updatePerson(newName);
PersonJPAEntity personReadInNewTransaction = self.findPersonInNewTransaction();
logger.info("Throw exception and thereby rollback transaction");
throw new TestException("Rollback transaction", personReadInNewTransaction);
}
@Transactional(propagation = REQUIRES_NEW)
public void insertPerson(PersonJPAEntity person) {
personRepository.save(person);
logger.info("Person inserted {}", person);
}
@Transactional(propagation = REQUIRED)
public void updatePerson(String newName) {
Optional<PersonJPAEntity> personToUpdate = personRepository.findById(1);
personToUpdate.get().setName(newName);
logger.info("Person updated {}", personToUpdate);
personRepository.flush();
logger.info("Repository flushed");
}
@Transactional(propagation = REQUIRES_NEW, isolation = Isolation.READ_UNCOMMITTED)
public PersonJPAEntity findPersonInNewTransaction() {
Optional<PersonJPAEntity> person = personRepository.findById(1);
logger.info("Person found in new transaction {}", person);
return person.get();
}
public class TestException extends RuntimeException {
private final PersonJPAEntity personReadInNewTransaction;
public TestException(String message, PersonJPAEntity personReadInNewTransaction) {
super(message);
this.personReadInNewTransaction = personReadInNewTransaction;
}
public PersonJPAEntity getPersonReadInNewTransaction() {
return personReadInNewTransaction;
}
}
}
PersonRepository
public interface PersonRepository extends JpaRepository<PersonJPAEntity, Integer> {
List<PersonJPAEntity> findByOrderByIdAsc();
}
UtilService
@Service
public class UtilService {
@Autowired
PersonRepository personRepository;
@Transactional(propagation = REQUIRES_NEW)
public List<PersonJPAEntity> retrieveTestPersons() {
return personRepository.findByOrderByIdAsc();
}
@Transactional(propagation = REQUIRES_NEW)
public void deleteTestPersons() {
personRepository.deleteAll();
}
}
PersonJPAEntity (src / main / java / test)
@Entity(name = "person")
public class PersonJPAEntity {
@Id
private int id;
private String name;
private PersonJPAEntity() {
}
PersonJPAEntity(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof PersonJPAEntity)) return false;
PersonJPAEntity person = (PersonJPAEntity) o;
return id == person.id &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name);
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
application.properties (src / main / ресурсы)
# spring.jpa.show-sql=true
logging.level.org.springframework.transaction=TRACE