The saveAndFlush() Method Unlike save(), the saveAndFlush() method flushes the data immediately during the execution. This method belongs to the JpaRepository interface of Spring Data JPA.
The way you can configure a query-specific flush mode depends on the FlushModeType you want to set. If you want to use the FlushModeTypes AUTO or COMMIT, which are defined by the JPA specification, you can call the setFlushMode method on your Query or TypedQuery interface. Query q = em.
On saveAndFlush , changes will be flushed to DB immediately in this command. With save , this is not necessarily true, and might stay just in memory, until flush or commit commands are issued.
Instead of defining EntityManager
in each of your resource, you can define it once by creating a Custom JpaRepository. Reference
Then use the refresh
of your EntityManager
in each of your repository directly.
Refer the below example:
CustomRepository Interface
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.NoRepositoryBean;
import java.io.Serializable;
@NoRepositoryBean
public interface CustomRepository<T, ID extends Serializable> extends JpaRepository<T, ID> {
void refresh(T t);
}
CustomRepository Implementation
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityManager;
import java.io.Serializable;
public class CustomRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID>
implements CustomRepository<T, ID> {
private final EntityManager entityManager;
public CustomRepositoryImpl(JpaEntityInformation entityInformation, EntityManager entityManager) {
super(entityInformation, entityManager);
this.entityManager = entityManager;
}
@Override
@Transactional
public void refresh(T t) {
entityManager.refresh(t);
}
}
Enable Custom JPARepository in Spring Boot Application Class
@SpringBootApplication
@EnableJpaRepositories (repositoryBaseClass = CustomRepositoryImpl.class)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Your Something Repository
public interface SomethingRepository extends CustomRepository<Something, Long> {
}
Use Refresh directly in SomethingResource (Assuming Something is an Entity)
@RestController
@RequestMapping("/api")
@Transactional
public class SomethingResource {
private final SomethingRepository somethingRepository;
public SomethingResource(SomethingRepository somethingRepository) {
this.somethingRepository = somethingRepository;
}
@PostMapping("/somethings")
public Something createSomething(@RequestBody Something something) throws URISyntaxException {
Something result = somethingRepository.save(something);
somethingRepository.refresh(result);
return result;
}
}
That's not enough:
Something result = somethingRepository.save(something);
You need to manually merge the incoming entity:
Something dbSomething = somethingRepository.findOne(
Something.class, something.getId()
);
dbSomething.setName(something.getName());
dbSomething.setOwner(something.getOwner());
somethingRepository.save(dbSomething);
Since the property
attribute is using the default FetchType.EAGER
, the entity should have the property
attribute initialized.
But, that's strange to call the Repository twice from the REST controller. You should have a Service layer that does all that in a @Transactional
service method. That way, you don't need to resave the entity since it's already managed.
@Transactional
public Something mergeSomething(Something something) {
Something dbSomething = somethingRepository.findOne(
Something.class, something.getId()
);
dbSomething.setName(something.getName());
dbSomething.setOwner(something.getOwner());
return dbSomething;
}
Now, you need to carefully merge every property you sent. In your case, if you send null
for property
you should decide whether you should nullify the @ManyToOne
reference or not. So, it depends on your current application business logic requirements.
If you make sure you always send back the same entity you previously fetched, you could just use merge
.
em.merge(result);
But your property
attribute is just an id, and not an actual child entity, so you have to resolve that yourself in the Service layer.
In Spring Boot JpaRepository:
If our modifying query changes entities contained in the persistence context, then this context becomes outdated.
In order to fetch the entities from the database with latest record.
Use @Modifying(clearAutomatically = true)
@Modifying annotation has clearAutomatically attribute which defines whether it should clear the underlying persistence context after executing the modifying query.
Example:
@Modifying(clearAutomatically = true)
@Query("UPDATE NetworkEntity n SET n.network_status = :network_status WHERE n.network_id = :network_id")
int expireNetwork(@Param("network_id") Integer network_id, @Param("network_status") String network_status);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With