JpaRepository не сохраняет объект

У меня есть сервер, использующий весеннюю загрузку и весенние данные jpa.

У меня есть два класса с аннотацией @RestController на моем сервере. Один из них может изменить сущности, а другой нет.

@RestController
@Slf4j
public class ControllerA {
    private EntityRepository entityRepository;

    public ControllerA(EntityRepository entityRepository) {
        this.entityRepository = entityRepository;
    }

    @PostMapping("/pathStr")
    public void changeEntity(@RequestParam("entityId") Long entityId) {
        // init
        Entity entity = entityRepository.findById(entityId);
        // make changes to entity
        entity.getOneToOneLinkedEntity().setIntProperty(0);
        // save entity
        entityRepository.save(entity);
    }
}

@RestController
@Slf4j
public class ControllerB {

    private Entity cachedEntity;
    private EntityRepository entityRepository;

    public ControllerB(EntityRepository entityRepository) {
        this.entityRepository = entityRepository;
    }

    @MessageMapping("/otherPath")
    public void getEntity(ArgumentType argument) {
        if (cachedEntity == null) {
            cachedEntity = entityRepository.save(new Entity());
        }
        Entity entity = entityRepository.findById(cachedEntity.getId()).orElse(null);
        int properyValue = entity.getOneToOneLinkedEntity().getIntProperty(); // this is not zero
    }
}

Вот две сущности и репозиторий:

@Entity
public class Entity implements Serializable {

    @Id
    @GeneratedValue private Long id;

    @NotNull
    @OneToOne(cascade=CascadeType.ALL)
    private OneToOneLinkedEntity linkedEntity;
}

@Entity
public class OneToOneLinkedEntity implements Serializable {

    @Id
    @GeneratedValue private Long id;

    @NotNull
    private int intProperty = 0;
}

public interface EntityRepository extends JpaRepository<Entity, Long> {
}

Я вызываю ControllerA.changeEntity из клиента, и как только он возвращается, я делаю еще один вызов ControllerB.getEntity. Изменения, которые я сделал в первом вызове, не отображаются во втором вызове (и их также нет в базе данных, если я делаю запрос непосредственно с помощью sql), свойство int имеет старое значение. Несмотря на то, что я сохраняю только объект, а не связанный объект, CascadeType.ALL также должен обновлять связанный объект, верно?

Я попытался добавить entityRepository.flush() после сохранения в ControllerA, но проблема все еще появляется. Что я могу сделать? Как я могу заставить ControllerB получить правильное значение intProperty?

Это то, что у меня есть в application.properties:

spring.jpa.hibernate.ddl-auto=create
spring.datasource.url=jdbc:mysql://localhost:3306/db_name
spring.datasource.username=user
spring.datasource.password=pass
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.DefaultComponentSafeNamingStrategy

person devil0150    schedule 12.10.2019    source источник
comment
Аннотации OneToOne с каскадом должно быть достаточно, чтобы это сработало. Не могли бы вы объяснить, откуда берется значение cachedEntity?   -  person Raphael    schedule 13.10.2019
comment
@Raphael Создается при первом вызове ControllerB.getEntity(). Что-то вроде: if (cachedEntity == null) {cachedEntity = entityRepository.save(new Entity());}. добавлю код в вопрос   -  person devil0150    schedule 13.10.2019


Ответы (2)


Вы должны добавить аннотацию @Transactional к своему методу, чтобы Spring обработал транзакцию и зафиксировал ваши изменения.
Обычно это происходит в классе @Service, но я вижу в вашем примере, что у вас его нет, поэтому поместите его в контроллер (или добавьте сервисный слой, я думаю, что это лучше)

person Nir Levy    schedule 12.10.2019
comment
Я попытался добавить @Transactional как в класс, так и в метод, как из javax.transaction, так и из org.springframework.transaction.annotation. Я все еще не вижу изменений в базе данных после вызова changeEntity - person devil0150; 12.10.2019
comment
Мне нужно что-то добавить в application.properties? - person devil0150; 12.10.2019
comment
попробуйте установить для свойства автоматической фиксации значение true - person Nir Levy; 12.10.2019
comment
Я действительно не знаю этого свойства, но я немного погуглил и попробовал следующее: spring.datasource.auto-commit, spring.jpa.hibernate.autocommit, spring.jpa.hibernate.auto-commit, spring.jpa.properties. hibernate.autocommit, spring.jpa.properties.hibernate.auto-commit, hibernate.connection.autocommit, hibernate.connection.auto-commit. Ни один не работал - person devil0150; 12.10.2019
comment
Вы были правы, достаточно было просто добавить @Transactional. Я сделал несколько глупых ошибок, изменяя код, чтобы проверить это, и сначала это не сработало. - person devil0150; 13.10.2019

Вы игнорируете инъекцию зависимостей, которая является красотой Spring Framework.

  1. Создайте класс репозитория, который реализует JPARepository, и аннотируйте его с помощью @Repository.
  2. Создайте класс службы и аннотируйте его с помощью @Service и @Transactional.
  3. В классе Service автоматически подключайте репозиторий и вызывайте соответствующие методы, такие как .save() .find() и т. д.
  4. В классе контроллера автоматически подключается класс службы и вызывается метод службы, который будет вызывать методы репозитория.

Это все, что вам нужно сделать. Чтобы ваше приложение работало быстро, лучше создать модель для класса сущностей и передавать модель между классами вместо сущности, поскольку она содержит гораздо больше информации и, следовательно, намного тяжелее, чем обычный объект модели.

person Manish Bansal    schedule 13.10.2019
comment
Репозитории автоматически реализуются Spring Data JPA, поэтому вам не нужно реализовывать их самостоятельно. - person Raphael; 13.10.2019
comment
Да, но чтобы сделать больше методов, вам нужно создать интерфейс и добавить в него абстрактный метод, остальное его реализация будет дана spring. - person Manish Bansal; 13.10.2019