16

I have a Spring Boot Application + JPA with MySQL. In my controller, when I post an entity I am able to call to repository.save, and I return the "created/updated" object.

But, when I look at the database, I see that the object is not updated.

Here is my application.yml:

spring:
  jpa:
    show-sql: true
    generate-ddl: false
    hibernate:
      ddl-auto: none
    properties:
      hibernate.dialect: org.hibernate.dialect.MySQLDialect
      org.hibernate.envers.store_data_at_delete: true
      org.hibernate.envers.global_with_modified_flag: true
      org.hibernate.envers.track_entities_changed_in_revision: true
  datasource:
    initialize: false
    url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:databaseName}?createDatabaseIfNotExist=true
    username: ${DB_USERNAME:root}
    password: ${DB_PASSWORD:root}
    driver-class-name: com.mysql.jdbc.Driver
    hikari:
      minimumIdle: 20
      maximumPoolSize: 30
      idleTimeout: 5000
      data-source-properties:
        cachePrepStmts: true
        prepStmtCacheSize: 250
        prepStmtCacheSqlLimit: 2048

Do you know what else do I have to do?

This is my controller:

@RequestMapping(method = RequestMethod.POST, produces = "application/json")
public MyEntity saveMyEntity(@Valid @RequestBody final MyEntity myEntity) {
    Assert.notNull(myEntity, "The entry cannot be null");
    return myEntityService.save(myEntity);
}

And MyEntityService:

@Override
@UserCanCud
public Entity save(final Entity entity) {
    Assert.notNull(entity);
    final Entity savedEntity = repository.save(entity);
    return savedEntity;
}
Manuelarte
  • 1,658
  • 2
  • 28
  • 47

5 Answers5

16

In my (limited) experience these types of problems are a tad more difficult to debug because of the magic happening behind the scenes with Spring, but I'll try to give some advice that has helped me troubleshoot similar problems - hopefully this gives you the nudge you need.

The @Transactional notation establishes a transactional scope that dictates when a transaction starts and ends, also called its boundary. If you operate outside of this boundary you'll either receive errors or things just won't work as expected.

First off, I found this bit of documentation the most helpful on Spring transactions: http://docs.spring.io/spring-framework/docs/4.2.x/spring-framework-reference/html/transaction.html specifically this section

Secondly, you may wish to enable trace level logs and potentially the SQL statements to help debug this. In order to do so I added the following to my application.properties - You'll be able to add the same into your application.yml with some minor adjustments

spring.jpa.properties.hibernate.show_sql=false
spring.jpa.properties.hibernate.use_sql_comments=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.type=trace
spring.jpa.show-sql=true
logging.level.org.hibernate=TRACE

There will be ALOT of output here, but you'll get a good idea of whats happening behind the scenes.

Third, and the most important part for me in learning how to use @Transactional is that every call to the DAO creates a new session -or- reuses the existing session if within the same transactional scope. Refer to the documentation above for examples of this.

Now, I suspect that your transaction is still considered open when you're reading back your updated object. Try doing a flush in your save method and see if that helps persist your changes back to the database.

Hopefully you'll be able to find the issue without too much hunting using the resources above, if not you should at the very least have some more complete information surrounding why the persistence isn't persisting.

Robert H
  • 11,520
  • 18
  • 68
  • 110
  • Hi Robert, Thanks for your comment, I already tried before your comment to be more verbose to see what is going on under the hood, but still, I could not make it work. Just another comment, when the entity is created (id is null), then, the transaction is finished... I can see the insert into statements, but I can't when I try to update an entity. – Manuelarte May 26 '17 at 08:13
  • What happens if you search for the entity using `repository.find()`, and update the returned entity? – Robert H May 26 '17 at 12:24
  • Hi Robert, I tried what you said, doing this, repository.findOne(myEntity.getId), and then myEntity.setOneField(newValue); repository.save() and still did not save it.... – Manuelarte May 26 '17 at 13:01
  • Ok - is `repository` an instance of `EntityManager` or is it an instance of your `RepositoryImpl` which contains the `EntityManager`? Assuming its your `RepositoryImpl`, is `save()` calling `entityManager.merge(entity)` or is it calling `persist()`? – Robert H May 26 '17 at 13:06
  • well... I am using spring data, so Repository it is just an interface. – Manuelarte May 26 '17 at 13:21
  • heh, I'm used to providing my own custom implementations - Behind the scenes with the auto wiring Save calls either persist or merge (https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.entity-persistence.saving-entites). To be honest, I am not sure how much more help I can be here - I still suspect your transaction boundaries are at least partially to blame here, but I would suggest that you spin up a side project, implement spring data and a basic use case and see if you still have problems or if the problems are only in your current code base. Hope this has helped... – Robert H May 26 '17 at 13:32
  • Hi Robert, The complete code can be found here https://github.com/manuelarte/TeambuiltingPlayers, just in case you are bored and want to take a look :) – Manuelarte May 26 '17 at 14:18
  • Annotate `saveMyEntity` with `@Transactional` and check whether the entity is visibly update in the database after the method finished. – Kriegel May 31 '17 at 21:41
  • 1
    Since you already tried verbose output I'm guessing there is no SQL UPDATE after the save? If there isn't, you might really have to go deeper and debug the implementation to see what's going wrong. – N4zroth Jun 01 '17 at 08:07
7

I finally found the solution... the entity I was trying to update had the @Immutable annotation on it...

Manuelarte
  • 1,658
  • 2
  • 28
  • 47
1

I think your problem is in the interception that you do with the annotation @UserCanCud.

I just made a project with the same settings that you propose and it works correctly. Take a look at:

https://github.com/nitzap/spring-data-mysql

If I'm missing something, just let me know.

German
  • 1,449
  • 12
  • 13
  • Hi German, mmm, strange, because I tried by removing the annotation, and also the aspect and still does not update it. – Manuelarte Jun 01 '17 at 09:42
  • You could try the example I sent you. Able we can determine that the problem is outside your project. – German Jun 01 '17 at 11:46
0

To save your object you need to setup proper jpa configurations and the repository after that it will be save.

for example we have user entity and userRepository as below

User Enity Class

package com.sanjeev.domain;

import javax.persistence.*;

@Entity(name = "user")
@Table(name = "user")
public class User {

    @Id
    @Column(name = "id")
    private Long id;
    @Column(nullable = false)
    private String username;
    @Column(nullable = false)
    private String email;
    @Column(nullable = false)
    private String password;

 //getters and setters   
}

User Repository class

package com.sanjeev.repository;    
    import com.sanjeev.domain.User;
    import org.springframework.data.jpa.repository.JpaRepository;

    public interface UserRepository extends JpaRepository<User, Long> {

    }

User Service class

package com.sanjeev.service;

import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import com.sanjeev.repository.UserRepository;
import com.sanjeev.domain.User;

@Service
public class UserService{

  @Autowired
  private UserRepository userRepository;

  public void saveUser(User user){
    userRepository.save(user);
  }


}

If you will follow above steps then your object must me saved

for more click here

sanjeevjha
  • 1,439
  • 14
  • 18
  • Hi sanjeevha, I do not think that I am doing it wrong. I am following above steps and still not working. – Manuelarte Jun 01 '17 at 09:11
  • actually i did it recently on my machine and it working perfectly, if you follow the given link then it might be possible you will get more idea – sanjeevjha Jun 01 '17 at 09:48
0

Just in case, if it helps anyone, i have separate controllers for ReadRepos and WriteRepos and was using different databases(one as master, other as slave). Technically both repos extend CRUD repos directly or indirectly via JPA repository both can access save(Entity e) method.

So, while using the readRepo accidentally to save , it was silently ignoring the call, instead of throwing error.

So bottomline ,is make sure you are using writeRepo to save/update if you have the same situation

Sriharsha g.r.v
  • 456
  • 5
  • 13