How to force commit transaction of EntityManager - java

I have the following case in a web app:
#Stateless
#LocalBean
public class AccountBean {
#PersistenceContext(unitName = "foreign-context")
private EntityManager fem;
#PersistenceContext(unitName = "own-context")
private EntityManager oem;
public void doCreate() {
Account account = createAccount();
SubAccount subAccount = createSubAccount(account);
}
private Account createAccount() {
Account account = new Account("This is a sample");
oem.persist(account);
oem.flush();
return oem;
}
private SubAccount createSubAccount(Account account) {
SubAccount subAccount = new SubAccount(account.getId()); // This field is only set after Account entity is persisted
fem.persist(subAccount);
fem.flush();
return subAccount;
}
}
The problem as I see it is that account.getId() returns the default value 0 (as is int) causing SQL exception when attempting to save SubAccount due to table constraints. The ID field on account is supposed to be set after the Account is persisted however I suspect that due to the uncommitted transactions the result is not persisted, therefore the ID field is not updated in code. I have tested both of the methods individually and they seem to work fine but when combined the issue arises.
I have to use two separate EntityManager(s) due to business requirements having the model objects in different project dependencies each with it's own descriptor.
I have tried creating a new container managed transaction using #TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) on createAccount() but to no avail.
The code runs on a Wildfly Server using Hibernate 5.2.4 if that's relevant. No other framework is used (except JPA)
How can I alleviate this issue?

Do not completely understand your code, method persist should return you object with id and you can use it.

Related

Disable DB Updates in Spring boot JPA when changing the value of a property after it is fetched from the repository using findall or other queries

I am having a service that gets the data from the database which has a column which is stored with encrypted value.
After fetching from the DAO, i will update the value of the property to decrypted value and then send it as response for the API.
I assume that the entity is having change tracking enabled for select queries also because after i get the data, the data is updated in the DB with the decrypted password. I have googled and found that the use of EntityManager solves the problem, but for this implementation I have to do a lot of code changes in many entities.
from this link, i see that we have to write custom stateless bean and inject to the code, but it looks like not right. Please suggest me the best approach to handle this problem.
My DAO:
#Repository
public interface EnvironmentDao extends JpaRepository<Environment, Long> {
//custom methods go here with native queries
}
My Service
#Override
public List<Environment> getEnvironmentsByIds(List<Long> environmentIds) throws Exception {
if (environmentIds == null || environmentIds.size() < 1) {
return null;
}
return decryptPassword(environmentDao.findAllById(environmentIds));
}
Inside the decryptPassword method, i am just looping through all the records and then setting the decrypted password like
e.setDB_Password(encryptionService.decrypt(e.getDB_Password()));
One case that i noticed yesterday is that for a similar entity on any error, there was a DB save and that time the values got updated, so after fixing the error, this change was not happening.
Please help me as I am not an expert in java and taking more time to analyze and could not understand. In the case of C#, i would use .AsNoTracking(), but i don't know java much and fiddling around.
Tried the following in the Service
#Autowired
EntityManager entityManager;
In the method,
Optional<Environment> environment = environmentDao.findById(id);
entityManager.detach(environment.get());
return managePassword(environment.get(), false);
I would suggest two options to overcome the entity being updated unintentionally:
Instead of returning the entity itself I would suggest creating a DTO class and creating an instance of that class and setting relevant properties on to the DTO instance so that no changes will be made to the entity itself. So the code will be sth like:
public List<EnvironmentDTO> getEnvironmentsByIds(List<Long> environmentIds) throws Exception {
if (environmentIds == null || environmentIds.size() < 1) {
return null;
}
return createEnvironmentDTOs(environmentDao.findAllById(environmentIds));
}
private LisT<EnvironmentDTO> createEnvironmentDTOs(List<Environment> environments) {
return environments.stream().map((env) -> {
EnvironmentDTO envDto = new EnvironmentDTO();
// Copy all relevant fields to DTO (you can even use some Mapper library for this, i.e. http://modelmapper.org/)
envDto.setDB_Password(encryptionService.decrypt(e.getDB_Password()));
})
}
If you want to return the entity no matter what instead of creating a DTO class and instance from it; you can detach the entity so that changes to the entity will not be reflected to database. So what you need to do is detaching entity after you are done with decrypting the password and setting it back to the entity: entityManager.detach(environment)

Save and Update operations in single Transaction of JPA not working as expected

consider entity as user, it having some fields. here i am using jpa callback functions to update user information of last update information. in test class I want to write junit method to evaluate whether these call back methods are working or not/ not only for functionality testing and code coverage purpose also. but if I follow below approach i am getting same time everytime, can anyone help on this.
#Entity
public class User {
// user setter and getter methods
#preUpdate
public void preUpdateFunction() {
this.lastUpdateDate = new Date();
}
#prePersist
public void prePersistFunction() {
// setting some user properties
preUpdateFunction();
}
}
// please ignore this configuration and annotations setup, I tested my class spring configuration working perfectly there is no issue with spring configuration.
#SpringConfiguration
#JpaTransactional
public class TestClass {
#Autowired
UserDao userDao; // userDao implements JPA Repository
// I am worrying about this functionality only
#Test
public void saveUpdateTest() {
User user = userDao.save(new User(constructor arguments));
user = userDao.findOne(user.getId());
user.setName("Hello"); // here updating user object with existing property
User updatedUser = userDao.save(user);
assertEquals(user.getLastUpdateDate().getTime(), updatedUser.getLastUpdateDate().getTime());
// assertion is failing, everytime i am getting same Time for two values. even I added //Thread.sleep(1000) between save and update operations, still i am getting same values.
}
}
Short answer
You need to call saveAndFlush
User updatedUser = userDao.saveAndFlush(user);
Long answer
From JPA spec (JSR 338 JPA 2.1):
The PrePersist and PreRemove callback methods are invoked for a given entity before the
respective EntityManager persist and remove operations for that entity are executed.
The PreUpdate and PostUpdate callbacks occur before and after the database update operations to entity data respectively. These database operations may occur at the time the entity state is updated or
they may occur at the time state is flushed to the database (which may be at the end of the transaction).
#PrePersist is invoked when entityManager persist operation is executed. Tricky part is the execution is usually delayed until next flush operation or transaction commit (hibernate default config). Generally, it depends on flush configuration and on jpa implementation.
Same also applies to #PreUpdate. In addition, JPA spec says it more specifically, it might occur when entity state is updated or when flushed to DB.
Related links
https://download.oracle.com/otn-pub/jcp/persistence-2_1-fr-eval-spec/JavaPersistence.pdf
https://thorben-janssen.com/spring-data-jpa-save-saveandflush-and-saveall

How to work with "long living entities" or "longer living persistence context"?

I am currently working on a medium sized, desktop-based administration and configuration tool implemented in Java using JavaFx, google-guice, and hibernate for its jpa implementation.
Until now i got away with a single EntityManager injected as a #Singleton. Meaning that i had this EntityManager "open" from start to shutdown. All loaded entites were permanently known in the context and I barely had any problems with this approach. Although i know/believe it is not the best solution (but easy and a I had no time to redesign the application).
Now the application gets extended and I have to use multiple persistence units simultaneously.
I could try to get my current singleton-approach working with using something like:
#Inject
#PersistenceContext(name="JPA-Unit1")
#Singleton
private EntityManager em;
It never felt perfect, but that feels "ugly". And since I had severe problems getting multiple persistence contexts working with guice, I had to do a lot of reasearch on this topic.
And i came across several blogs SO-questions either mentioning that an instance of the EntityManager should only live as long it is needed or some extended persistence contexts.
Since I useJavaFx in place I use the *Property classes to bind the data directly into the UI.
Simplified user entity (property-based access):
#Entity
#Table(name = "USERS")
#NamedQuery(name = "User.findAll", query = "SELECT u FROM User u")
public class User implements Serializable {
[...]
private final SimpleStringProperty loginProperty = new SimpleStringProperty();
public User() {
}
public String getLogin() {
return this.loginProperty.get();
}
public void setLogin(String login) {
this.loginProperty.set(login);
}
public SimpleStringProperty loginProperty() {
return this.loginProperty;
}
[...]
}
If i start editing the user data in the UI it gets directly updated in the entity:
this.login.textProperty().bindBidirectional(user.loginProperty());
There is no need for extensive "business logic". It gets all handled via (input) validation. If all input is valid i simply save the data via
userService.update(user);
Parts of the UserService (exactly: its abstract super-class):
public abstract class AbstractService<PK extends Serializable, Type> implements GenericService<PK, Type> {
protected Class<Type> clazz;
#PersistenceContext(name = "JPA-Unit1")
#Inject
protected Provider<EntityManager> emProvider;
public AbstractService(Class<Type> clazz) {
this.clazz = clazz;
}
#Transactional
#Override
public Type create(Type entity) {
this.emProvider.get().persist(entity);
return entity;
}
#Transactional
#Override
public Type update(Type entity) {
this.emProvider.get().persist(entity);
return entity;
}
}
As you can see: the service class is pretty straightforward. I could even delete all this "service"-classes and directly use the entitymanager directly in my UI controller.
In this service you can see the "problem" the user i edit got loaded earlier by its named query and put into a list. The loading is also done in a #Transactional method.
But everytime i call this.emProvider.get() I get a new instance with an empty context. And if I want to save the previously edited user I have the problem that persist actually performs an insert (I assume because it is not known in the context [detached]) which leads to an PK-constraint violation or if I delete (null) its ID-property there is a new user row inserted.
My actual questions are:
1. Is this approach "OK"? If yes what do I do with this "always" new persistence context? Call contains and merge every single time?
Should I get rid of my service class and implement the persistence operations directly in my UI-controller?
Can I do an this.emProvider.get() once the User-UI-controller got loaded and use it the entire life time of the application?
Something totally different?
My understanding is that your app uses Guice Persist.
The answer to this question depends on your use cases; however, you absolutely need to realize one thing:
For as long as an EntityManager is open, its underlying persistence context tracks every single change to each persistent entity.
This means that if you keep an entity manager open for the duration of the application, whenever you call e.g. User.setLogin(), the change you just made is already regarded as persistent. Now, moving to your update method, calling persist on an entity that is already managed has no effect; however, since you're calling it from a #Transactional method, Guice wraps the call in a transaction, and consequently, all the changes are are being flushed to the database once the method ends.
This means that if you modify multiple entities at once within your app, and then call AbstractService.update on one of them, you will actually be saving all the changes your app has done to other entities in the meantime, even if AbstractService.update has not been called on them explicitly.
Using the entity manager-per-transaction approach is indeed much safer. Between transactions, there will be no open persistence context, and as a result all the entities will become detached, which will prevent any updates on them from accidentally being flushed to the database.
However, for the same reason, your update method will need to call em.merge on the entity you want to update in the database. merge is basically telling the entity manager 'please put this entity back into the persistence context, and make it have the exact state that the provided entity has'. Calling persist makes it look as though it was a new entity, and PK-constraint violations will indeed follow.

Java entity manager does not load changes when I manually update row

I have a simple service injected by guice. It uses Hibernate, EntityManager.
class BrillantPaulaServiceImpl implements BrillantPaulaService {
#Inject
EntityManager em;
#Override
public Status EnqueueStatusCheck(Integer statusId) {
Status status = em.find(Status.class, statusId);
EntityTransaction transaction = em.getTransaction();
try {
//..... do some work
} finally {
if (transaction.isActive()) {
transaction.rollback();
}
}
}
return status;
}
When I manually update row from pgsql, the "Status status = em.find(Status.class, statusId);" does not view changes. It returns old entity. What is the possible issue?
What em.find(...) does is that it first checks persistence context and because there is cached entity it returns it instead of getting it from database. Here is some quote from here:
Find by primary key, using the specified properties. Search for an
entity of the specified class and primary key. If the entity instance
is contained in the persistence context, it is returned from there. If
a vendor-specific property or hint is not recognized, it is silently
ignored.
In the case that cache is used, JPA will get the entities from there. It will track changes to those entities only if they are modified via JPA. If you update the underlying data yourself, either directly or via some other external system, JPA will not be aware of those changes.

subsequent save in JPA transaction

I have a service class the injects two JpaRepository classes: organizationRepository and stateRepository. In the service method I need to perform two transactions:
#Override
#Transactional
public Status createOrganization(#ResponseBody Organization organization) throws Exception {
Organization savedOrg = organizationRepository.save(organization);
int id = savedOrg.getOrgId();
State state = new State();
state.setOrgId(id);
state.setCode("MD");
State savedState = stateRepository.save(state);
.
.
.
This code isn't working and throwing a transaction error on my server. I also tried a saveAndFlush on the organizationRepository before trying to call the subsequent save for stateRepository. I realize I could also set the propagation properties but that didn't fix it either. The first save transaction always executes, but the second keeps failing. What can I do to solve?

Categories

Resources