Пример грязного чтения с использованием УРОВНЕЙ ИЗОЛЯЦИИ - PullRequest
0 голосов
/ 30 января 2020

В учебных целях я хочу привести пример с грязным чтением. Использование уровня изоляции 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...