confused about the jpa entitymanager and lazyload - java

I created a user management service based on springboot.
The user will have a list of attachments, so the relationship of the user and attachment is OneToMany.
I ignored the insert logic here since my question is about the lazyload and when the entitymanager is opened and closed. Below is the entity, controller, service, dao, repository related code.
Entity
#Entity
#Table(name="User")
public class UserInfoEntity {
private long id;
private String mail;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "userInfoEntity", cascade = CascadeType.ALL)
private List<UserAttachmentEntity> attachmentList = new ArrayList<>();
}
#Entity
#Table(name = "ATTACHMENT")
public class UserAttachmentEntity {
private long id;
private String name;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="userRequestId")
private UserInfoEntity userInfoEntity;
}
Service
#Service
public class UserServiceImpl implements UserService {
#Autowired
private UserDao userDao;
#Override
#Transactional
public void save(UserInfoEntity userInfoEntity) throws RestException {
userDao.save(userInfoEntity);
}
#Override
// I did set #Transactional here
public UserInfoEntity findByMail(String mail) {
UserInfoEntity userInfoEntity = userDao.findByMail(mail);
return userInfoEntity;
}
}
DAO
#Service
public class UserDaoImpl implements UserDao {
#PersistenceContext
private EntityManager entityManager;
#Autowired
private UserInfoEntityRepository userInfoRepository;
#Override
public UserInfoEntity findByMail(String mail) {
return userInfoRepository.findFirstByMailOrderByIdDesc(mail);
}
}
Repository
#Repository
public interface UserInfoEntityRepository extends JpaRepository<UserInfoEntity, Integer> {
UserInfoEntity findFirstByMailOrderByIdDesc(String mail);
}
Controller
#Controller
#RequestMapping(value = "/user")
public class UserController {
#RequestMapping(value = "load", method = RequestMethod.POST)
#ResponseBody
public UserInfoEntity load(UserInfoEntity userInfoEntityInput, HttpServletRequest request) throws Exception {
UserInfoEntity userInfoEntity = userService.findByMail(userInfoEntityInput.getMail());
System.out.println(userInfoEntity.getAttachmentList());
return userInfoEntity;
}
}
After I test the load method in controller, I found that even I set the
#OneToMany(fetch = FetchType.LAZY,...) in
UserInfoEntity.
I can still call userInfoEntity.getAttachmentList() in controller.
(I can see the select * from attachment query was printed there)
The answer of the post lazyinitializationexception-in-spring-data-jpa said that you need to fetch the lazy data while you are inside of a transaction.
But I did not set the #Transaction in the findByMail method in service.
And I remember that I also met this exception a couple of days ago. But now I can load the lazy data successfully in controller.
I mainly have below questions.
When the entitymanager is opened and closed? (is it opened in service or dao?)
Why the lazy data can be loaded in controller?
Is the entity manager thread-safe? (I googled, but not find useful answer)
Is the entity manager singleton? ( in above code, I inject the entity manager into dao, although I did not use it, I used spring data, I can inject the entity manager to service, controller, find the hashcode is different)
Thanks in advance. I wrote this question in company, I was not allowed to push any code to github in company. If I can, I think it will be more convenient for you since the spring boot project with h2 database is very easy to setup locally.

Spring Boot JPA Opens Session in View by default
If you go along the Appendix A. Common application properties, you will find by default Spring boot defines
spring.jpa.open-in-view=true
That actually register OpenEntityManagerInViewInterceptor. Binds a JPA EntityManager to the thread for the entire processing of the request.
This actually leads to confusion, See this issue reported by the community.
When the EntityManager is opened and closed?
Basically, an EntityManager opens a transaction where #Transaction annotation is declared or in your case it is opened by the OpenEntityManagerViewInterceptor on every request and that stays open before the response is made.
Is the entity manager thread-safe?
NO. Its not threadsafe, but the EntityManagerFactory is. And EntityManager is obtained from EntityManagerFatory. Hence an EntityManager is inexpensive and expected to be used once for a single unit of work. Where An EntityManagerFactory is typically created at application initialization time and closed at the application end. See Hibernate doc for details about Obtaining an EntityManager in a Java SE environment
Is the entity manager singleton?
No. EntityManager is an interface, and what gets injected in the spring bean when you autowire, is not the entity manager itself but a context-aware proxy that will delegate to a concrete entity manager at runtime. Usually, the concrete class used for the proxy is SharedEntityManagerInvocationHandler
For more detail explanation about how the whole JPA transaction go around. I recommend reading this How Does Spring #Transactional Really Work?

In Spring Boot the Open Session In View is enabled by default which means that you don't have to use #Transaction in your code unless it is required by your app's logic.
However, note that the enabled OSIV is considered as bad practice - the detailed debate about this topic can be found at https://stackoverflow.com/a/37526397/3750108

Related

Is javax.persistence.EntityManager thread safe

I’m using EntityManager in may Dao layer without #PersistenceContext but Dao method is calling service method which is marked as #Transactional. My question is should I use EntityManagerFactory in dao layer and every time get EntityManager to keep thread safety or it’s handled already?
Dao layer:
#RequiredArgsConstructor
public class UserDaoImpl {
private final EntityManager em;
public void save(User user){
em.persist(user);
}
}
Service layer:
#RequiredArgsConstructor
public class UserService {
private final UserDao userDao;
#Transactional
public void save(User user) {
userDao.save(user);
}
}
Tnx!
just add #PersistenceContext to your Entity Manager and the container will handle it for you, but if you are not in JEE environment so create your own entity manager factory, but I think in your current case the entity manager will still null. Also you must create you persistence unit XML file, and take attention in transaction-type, it must be JTA if you use #PersistenceContext and it should be RESSOURCE_LOCAL if you will create your own Entity Manager Factory.
This stackoverflow question Is EntityManager really thread-safe? already got answer to your question.
And this one "Future-Proofing Java Data Access - DAO Pattern Done Right" shows how to design DAO layer.
But if you are using Spring and Spring Data repository then I would suggest defining repository using CrusRepository or JpaRepository interface.
That would offload your concerns regarding EntityManager handling to Spring.

Create new Entity Object in Spring Boot

I'm hoping someone could shed some more light on my confusion with JPA entities in a Spring Boot project. I've heard that one should never call new in a Spring project. I understand that this is to allow Spring to manage all of the beans, and getting a bean can be done through injection or through the application context explicitly.
However, it's not clear to me how to get a new JPA Entity. If I have a class annotated with #Entity and a repository class that handles my data access, how do I obtain a new entity object in my service layer?
I've included #EntityScan in my application's main class so I would assume that Spring is aware of the entity. But when I try to get it through the ApplicationContext an exception is raised. This makes sense because I don't believe the #Entity annotated classes are Spring Beans, and I don't think it would be correct to also annotate it with #Component. Any clarification would be greatly appreciated.
I'm currently using the new keyword and creating the entity objects myself in the service layer. A very simple example is below:
entities/User.java
#Entity
#Table(name = "users")
public class User {
#Id
private Long id;
private String username;
// Getters & Setters ...
}
repositories/UserRepository.java
#Repository
public interface UserRepository extends CrudRepository<User, Long> {
User findByUsername(String username);
}
services/UserServiceImpl.java
#Service
public class UserServiceImpl implements UserService {
UserRepository userRepository;
#Autowired
public UserServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
public void createAndSaveUser(String username) {
User user = new User();
user.setUsername(username);
userRepository.save(user);
}
}
And we could assume that there was some other controller classes that would utilize the service layer.
In this example I am explicitly calling the new keyword in the service class method createAndSaveUser. Is this the correct way to do it or should I be getting some prototype bean from Spring that maps to my JPA entity?
In spring you can autowire/inject your beans, components or services. However the entity should not be autowired since these interactions are done through your repository. Your repository can be autowired.
When you want to create a new instance of your entity you are allowed to call new, because this does not need to be managed by spring. You can simply use the autowired repository to save it in the database. This also works the other way around because obviously you would need the autowired repository to retrieve your entity.
So yes, your method is correct.
I hope this makes it clearer for you, if you have any questions feel free to ask :)
Whatever you are doing is completely valid in spring. In example you have provided above I could figure out that you want your entity class object itself to store the values. Its absolutely correct.
You have to use new keyword to achieve that.
If you still wish to not create a new object for your Entity you have another option to do it through Bean/POJO/VO classes and mapping your entity object with these classes.
But Still i will tell that whatever you have done is completely fine.
Actually the object you are creating is for storing value purpose not just because you have some method is there in your class and so you are bound to create new Object to be able to call that method(As we do in normal java project).In spring that is handle by #Autowired annotation to create object.
Simple example is you will be auto-wiring your repositories in your service classes.
I hope this help.
It sounds good to me: you create your entity and then ask the repository to store it.. no problem with Spring.
have you checked this out? :
http://spring.io/guides/gs/accessing-data-jpa/
have fun

Dependency injection conflict when more than one user uses the system

I made a single Java Application using Tomcat(Prod) and Jetty(Dev) + Hibernate + Spring + Spring MVC + Fremarker
I have a issue to solve, 'cause the users are reporting that only one user can do login without conflict. If a user does login and tries to create a new entity Payment, he have a successfull transaction. But when another user does login, since then, nobody can create a new Payment.
There is no exception, a POST is executed, but seems like the Controller is not able for delivery the form to services classes.
#MappedSuperclass
#Getter
#Setter
public abstract class AbstractEntity implements Persistable, Cloneable {
//code...
}
#Entity
#Getter
#Setter
public class Pagamento extends AbstractEntity{
//code...
}
#Component
#Transactional
public class PagamentoService {
//code...
}
#Controller
#RequestMapping("/payments")
public class PagamentosController {
//code...
}
Is everything okay about Annotations and CDI? What could to be happening?
A common use case for that is using attributes of controller (or service, dao, etc.) classes. All those beans are singleton beans and are shared between all requests and sessions. You should only use local variables in all those singleton beans - except of course for attributes that are common for the whole application ...
Can it be because you are using a single-connection DataSource, so once a request takes a connection then no other requests can access it until the first one releases the one-and-only database connection.

Spring-Data Calling Save on Entity from Controller

I am using Spring Data within Spring Boot. I have a simple controller method that accepts an instance of an entity I'd like to update in my database. However, after calling repository.save() the object isn't persisted, however, if I query for the object (from the Id of the incoming entity) I have no problem, and the update persists.
Also the HTTP response is a 405 that the method doesn't work?
Controller:
#Transactional
public class AccountController {
#Autowired
private AccountService accountService;
#RequestMapping(value = "/account/{id}", method = RequestMethod.PUT)
#ResponseStatus(value = HttpStatus.OK)
public #ResponseBody Account updateAccount(#PathVariable("id") String id, #RequestBody Account account) {
return accountService.updateAndValidateAccountProfile(account);
}
}
Service:
#Override
public Account updateAndValidateAccountProfile(Account account) {
// calling findOne() returns the object ... and the save() works fine
//Account currentAccount = accountRepository.findOne(account.getId());
return accountRepository.save(account);
}
Repository:
interface AccountRepository extends CrudRepository<Account, Long> {
}
Is there something about the way I need to identify the object to Spring Data. I see the select statements fire out of hibernate, and I know the merge should happened on the primary key (id) within the Spring Data call to .save() - so I shouldn't need to query the object and manually assign the updated values correct??
Have you enabled transaction management? You need to use #EnableTransactionManagement on your config class otherwise #Transactional has no effect.
A spring tutorial on Managing Transactions
As a side note: making the controller layer transactional is usually not a good idea, especially when you have a proper separation of controller, service and repository layers. Consider moving #Transactional into the service layer.
Since you are using JPA, also make sure you have a JpaTransactionManager configured:
#Bean
public PlatformTransactionManager transactionManager() {
return new JpaTransactionManager();
}
You might try extending the JpaRepository interface instead of CrudRepository then you can use saveAndFlush(entity) to make sure the changes are immediately flushed after merge.

Write Less DAOs with Spring Hibernate using Annotations

My Spring+Hibernate configuration files are small and super tight. I use auto scanning to find my model entities/daos.
I don't want to have to write a DAO + DAOImpl for EVERY Entity in my hierarchy.
Some may qualify to have their own, like if they have complex relationships with other entities and require more than basic CRUD functionality. But for the rest...
Is there any way to circumvent the defacto standard?
Say, something like a generic DAO, ex:
http://www.ibm.com/developerworks/java/library/j-genericdao/index.html
Then I can do something like
GenericDao dao = appContext.getBean("genericDao");
dao.save(car);
dao.save(lease);
Is this possible with annotations? I don't want to have to configure anything in xml. If I cannot do above, is it still possible to have one GenericDaoImpl.java with something like:
#Repository("carDao")
#Repository("leaseDao")
class GenericDaoImpl extends CustomHibernateDaoSupport implements GenericDao {
...
}
and then
GenericDao dao = appContext.getBean("carDao");
dao.save(car);
dao = appContext.getBean("leaseDao"); //carDao is garbage coll.
dao.save(lease);
Is this practical at all?
Using generics, you might try something like this:
#Repository
#Transactional
public class GenericDAOImpl<T> implements GenericDAO<T> {
#Autowired
private SessionFactory factory;
public void persist(T entity) {
Session session = factory.getCurrentSession();
session.persist(entity);
}
#SuppressWarnings("unchecked")
public T merge(T entity) {
Session session = factory.getCurrentSession();
return (T) session.merge(entity);
}
public void saveOrUpdate(T entity) {
Session session = factory.getCurrentSession();
session.saveOrUpdate(entity);
}
public void delete(T entity) {
Session session = factory.getCurrentSession();
session.delete(entity);
}
}
The content may be different, but the general idea is applicable.
You should be able to then autowire the DAO in your controller and service classes by using
#Autowired
private GenericDAO<Car> carDao;
You can combine Spring/Hibernate with JPA, which provides the EntityManager for a large amount of basic persistence tasks:
#Service
public class CarService {
#PersistenceContext
private EntityManager em;
public void saveCarAndLease(Car car, Lease lease) {
em.persist(car);
em.persist(lease);
}
}
It will also handle transactions and simple queries without needing to write a DAO. For the more complex operations, you can still write a DAO and fall back to Hibernate's SessionFactory (although JPA is an option here too).
Some tutorials suggest you should still write the DAO for abstraction of the JPA plumbing. However, I have personally found this unnecessary (JPA has a very small integration footprint), and in fact this is also the way Spring Roo deals with the data layer behind the scenes.
Have you tried to use Spring Data. I mean to say Spring JPA where you can use repositories.
You can eliminate writing all stuffs for each entity.

Categories

Resources