JpaRepository not saving entity

18,082

Solution 1

You should add @Transactional annotation to your method, so spring will handle the transaction and commit your changes.
This usually comes on the @Service class, but I see in your example that you do not have one, so put it on the controller (or add service layer, I think it's better)

Solution 2

You are ignoring dependency injection which is the beauty of spring framework.

  1. Make a Repository class which implements JPARepository and annotate it with @Repository.
  2. Make a Service class and annotate it with @Service and @Transactional.
  3. In Service class autowire the Repository and make corresponding methods call like .save() .find() etc.
  4. In Controller Class autowire the service class and call service method which will call repository methods.

This is all you have to do. For making your application flow fast, better you create model for the entity class and pass the model between classes instead of entity as it contains a lot more information and thus much more heavy than normal model object.

Share:
18,082

Related videos on Youtube

devil0150
Author by

devil0150

Updated on October 02, 2022

Comments

  • devil0150
    devil0150 over 1 year

    I have a server using spring boot and spring data jpa.

    I have two classes annotated with @RestController in my server. One of them might change entities, while the other won't.

    @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
        }
    }
    

    Here are the two entities and the repository:

    @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> {
    }
    

    I make a call to ControllerA.changeEntity from the client, and once that returns, I make another call to ControllerB.getEntity. The changes I made in the first call aren't shown in the second call, (and they're not in the database either if I query directly with sql) the int property has an old value. Even though I do the save only on the Entity and not on the linkedEntity, the CascadeType.ALL should make the the linked entity update too, right?

    I tried adding an entityRepository.flush() after the save in ControllerA, but the issue still appears. What can I do? How can I make ControllerB get the correct value of intProperty?

    This is what I have in 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
    
  • devil0150
    devil0150 over 4 years
    I tried adding @Transactional, both to the class and to the method, both the one from javax.transaction, and the one from org.springframework.transaction.annotation. I still don't see the changes in the database after calling changeEntity
  • devil0150
    devil0150 over 4 years
    Do I need to add something in application.properties?
  • Nir Levy
    Nir Levy over 4 years
    try setting the auto-commit property to true
  • devil0150
    devil0150 over 4 years
    I don't really know this property, but I did some googling and tried these: spring.datasource.auto-commit,spring.jpa.hibernate.autocommi‌​t, spring.jpa.hibernate.auto-commit, spring.jpa.properties.hibernate.autocommit, spring.jpa.properties.hibernate.auto-commit, hibernate.connection.autocommit, hibernate.connection.auto-commit. None worked
  • Raphael
    Raphael over 4 years
    Repositories are automatically implemented by Spring Data JPA, so you don't have to implement them yourself.
  • devil0150
    devil0150 over 4 years
    You were right, just adding @Transactional was enough. I made some stupid mistakes while changing the code to test that and it didn't work at first.
  • Manish Bansal
    Manish Bansal over 4 years
    Yea, but to make more methods you need to make a interface and can add abstract method in it, rest its implementation will be given be spring.
  • judos
    judos over 2 years
    There are different @Transactional annotations. Which one do you mean? Please add your import to show what is actually needed.