Spring transactions, EntityManager lifecycle - java

I am developing a project with spring framework.
I have following architecture: all database code is in dao classes, all application logic is in service classes, http requests are processed using spring mvc rest controllers.
#Repository
public class UserDao {
#PersistenceContext
private EntityManager em;
public void editUser(User user) {
...
}
}
#Service
public class UserService {
#Autowired
private UserDao userDao;
#Transactional
public void editUser(User user) {
...
}
}
#RestController
#RequestMapping(value = "/UserCtrl", produces = "application/json;charset=UTF-8")
public class UserCtrl {
private static final Logger logger = LogManager.getLogger(AppConfig.LOGGER_NAME);
#Autowired
private ApplicationContext appContext;
#RequestMapping(value = "/editUser")
public ActionResult editUser(#ModelAttribute User user) {
ActionResult rslt = new ActionResult();
try {
UserService userService = appContext.getBean(UserService.class);
userService.editUser(user);
rslt.setSuccess(true);
} catch (Exception ex) {
logger.error("editUser", ex);
rslt.setSuccess(false);
}
return rslt;
}
}
This code works correctly.
One thing I cannot understand is how aop proxy of UserService bean starts transaction, when EntityManager is injected only in UserDao class. Can somebody explain me how this works and how EntityManager lifecycle is managed by spring framework ?
Any help appreciated.

The TransactionManager is responsible for managing the transaction boundaries
in Spring Framework.
When you annotate the business method with #Transactional you are instrumenting the method with an aspect.
Before executing the method, this aspect interact with TransactionManager which decides if it is necessary to create a new Transaction or use a preexisting one. In the case of create a new Transaction, a new Entity Manager is created from EntityManagerFactory and is associated to the current thread alonside with the Transaction.
The EntityManager is responsible to iterate with the database. When you inject it with #PersistenceContext, Spring injects an proxy to the EntityManager.
Whenever an operation is executed in the EntityManager proxy it looks the EntityManager associated with the thread.

Based on the snippet of code you provide you are using spring with some implementation of JPA you are using J2EE container for your web application and bases on my guess I think this is good article about how things works.
Basic concepts :
EntityManager - A class that manages the persistent state(or lifecycle) of an entity.
Persistence Unit - is a named configuration of entity classes.
Persistence Context - is a managed set of entity instances. The entities classes are part of the Persistence Unit configurations.
Managed Entities - an entity instance is managed if it is part of a persistence context and that Entity Manager can act upon it.
Based on this article you use Container Managed EntityManager by using #PersistenceContext
When a container of the application(be it a Java EE container or any other custom container like Spring) manages the lifecycle of the Entity Manager, the Entity Manager is said to be Container Managed. The most common way of acquiring a Container Managed EntityManager is to use #PersistenceContext annotation on an EntityManager attribute.
And the injection is like this :
A Transaction Scoped Entity Manager is returned whenever a reference created by #PersistenceContext is resolved.
and
Every time an operation is invoked on an Entity Manager, the container proxy(the container creates a proxy around the entity manager while instantiating it ) checks for any existing Persistence Context on the JTA Transaction. If it finds one, the Entity Manager will use this Persistence Context. If it doesnt find one, then it will create a new Persistence Context and associates it with the transaction.
So the lifecycle of of entity manager is managed by your container and
we work with an instance of EntityManager, the only role of EntityManager is to determine the lifetime of the Persistence Context. It plays no role in dictating how a Persistence Context should behave. To reiterate, Persistence Context is a managed set of Entity instances. Whenever a transaction begins, a Persistence Context instance gets associated with it. And when a Transaction ends(commits for example), the Persistence Context is flushed and get disassociated with the transaction.
In the nutshell container instantiate your EntityManager by the EntityManagerFactory you provide and manage it's lifecycle but inject the proxy of EntityManager for you. The TransactionManager is responsible for creating, commiting and ... tranactions based on annotations you provide ,whenever it begins the transaction the PersistancecContext associated with it and when the tranasction ends it commites the state of PersistenceContext. The EntityManager works with PersistenceContext and if it's not provided the EntityManager creates one. The EntityManager is threadsafe as long as it holds no state and the state (PersistenceContext) is attached to current tranasction.
Hope this helps.

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.

How to create non-transactional JUnit integration tests in Spring?

An integration test class is annotated with:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = IntegrationTestConfig.class)
It's not supposed to run in a transaction so isn't marked as #Transactional but I'm getting errors when trying to perform persist, merge etc. operations on the EntityManager, which is injected using #PersistenceContext:
No transactional EntityManager available
How can this be resolved?
EDIT:
As requested in the comments, the Spring version is 4.1.0.RELEASE and IntegrationTestConfig is below:
#EnableAspectJAutoProxy
#EnableAsync
#EnableScheduling
#EnableTransactionManagement
#Configuration
public class IntegrationTestConfig {
/**
* Override the existing JPA data source bean with a test data source.
* #return test data source
*/
#Bean
public DataSource dataSource() {
final SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
dataSource.setDriverClass(org.h2.Driver.class);
dataSource.setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;INIT=CREATE SCHEMA IF NOT EXISTS mydb");
dataSource.setUsername("sa");
dataSource.setPassword("");
return dataSource;
}
}
If you are sure that you are never going to call entityManager.flush(), obtain the PersistenceContext as follows:
#PersistenceContext(type = PersistenceContextType.EXTENDED)
private EntityManager entityManager;
Why is this needed? Spring Data JPA hands out what is called a shared EntityManager when the #PersistenceContext annotation is used (without any attributes). Full details for this are available in the JavaDocs for org.springframework.orm.jpa.SharedEntityManagerCreator. This class maintains a lookup table where the EntityManager methods flush, merge, persist, refresh and remove are required to be run inside a transaction. So, any time it encounters a method call that is not inside a transaction, it bails out.
The annotation #PersistenceContext has a type attribute that can be set to one of PersistenceContextType.EXTENDED or PersistenceContextType.TRANSACTION, with the later being the default. Therefore, the default #PersistenceContext causes SharedEntityManagerCreator to look for a transaction and bail out if none is found.
Using PersistenceContextType.EXTENDED bypasses the need to check for a transaction when obtaining the EntityManager and therefore the code should work.
flush still cannot be called without a transaction because the JPA providers require it to be called only within a transactional context.

Use of joinTransaction in JPA

The following code is from JPA specs. I could not understand why em.joinTransaction() is required in createLineItem(int quantity).
Can anyone provide an apt explanation?
#Stateful
public class ShoppingCartImpl implements ShoppingCart {
#PersistenceUnit
private EntityManagerFactory emf;
private EntityManager em;
private Order order;
private Product product;
#PostConstruct
public void init() {
em = emf.createEntityManager();
}
public void initOrder(Long id) {
order = em.find(Order.class, id);
}
public void initProduct(String name) {
product = (Product) em
.createQuery("select p from Product p where p.name = :name")
.setParameter("name", name).getSingleResult();
}
public LineItem createLineItem(int quantity) {
em.joinTransaction();
LineItem li = new LineItem(order, product, quantity);
order.getLineItems().add(li);
em.persist(li);
return li;
}
#Remove
public void destroy() {
em.close();
}
}
First, a few words of theory...
An application-managed entity manager participates in a JTA transaction in one of two ways.
If the persistence context is created inside the transaction, the persistence provider will automatically synchronize the persistence context with the transaction.
If the persistence context was created earlier (outside of a transaction or in a transaction that has since ended), the persistence context can be manually synchronized with the transaction by calling joinTransaction() on the EntityManager interface. Once synchronized, the persistence context will automatically be flushed when the transaction commits.
After reading the above definition a few questions may arise:
how do we know that ShoppingCartImpl participates in JTA transaction ?Because the class has been annotated with #Stateful (or #Stateless) annotation so the intention is to execute the class within Java EE environment which by default uses JTA transactions. A class doesn't need such annotation, if it will be executed in Java SE environment.
how do we know application-managed entity manager is used in this particular case?Because we are using #PersistenceUnit annotation to inject EntityManagerFactory and then manually creating and destroying EntityManager. By doing this we are telling Java EE container that we don't want our transaction to be automatically managed (like in case of transaction-scoped entity manager or extended entity manager types).
why em.joinTransaction() is required in createLineItem method?By calling em.joinTransaction() we notify the application-managed persistence context that it should synchronize itself with the current JTA transaction. Without such call the changes to Order would not be flushed to the underlying database when the transaction commits (at the end of createLineItem method). NOTE: since EntityManagerFactory instances are thread-safe and EntityManager instances are not, an application must not call em.joinTransaction() on the same entity manager in multiple concurrent transactions.

How to persist entities, how to create table from entities without "main class"?

I'm developing an application, and I started with creating my JPA entities (annotation + persistence.xml). Then in my persistence.xml file, I created a connection for a MySql data base (the connection is fine).
The problem is that I just don't know how to persist my entities without creating a "main class".
Do I have to run my main class for every single entity that I'm going to create?
To persist an entity, you need an instance of entityManager. Since you have a Java EE container you can get an instance of entityManager using the annotation #PersistenceContext in some bean
What I mean by some bean ? It's a bean managed by the Java EE container. So, for instance you have to define a bean like this :
#Stateless
public class MyController{
#PersistenceContext
private EntityManager em;
public void persistIt(Object anEntity){
em.persist(anEntity);
}
}
The annotation #Stateless indicate to the container that it must manage this class and take care of providing an instance of the entityManager when needed.
So to answer precisely to your question: it is not mandatory to have another class to persist an entity, as soon as you find a way to get access to an entityManager instance.
But:
it is definitively NOT a best practice.
to take advantages of entityManager injection: you must use another managed bean so that entityManager can be injected by the container.
Additionally, the controller is where you can handle your transactions properly.

Meaning of #PersistenceContext in JSF 1.2 Managed Beans

JSF 1.2 specification allows injection of an entity manager into a managed bean via the #PersistenceContext annotation (JSR 252, p. 5-13).
What is the semantics of such an entity manager regarding transactions and lifecycle?
Is an EAR-scoped JTA-style persistence unit supposed to work here?
#Stateless
public class YourServiceBean implements YourService {
#PersistenceContext(unitName="YourServicePU")
EntityManager em;
// ...
}
This will inject an EntityManager instance that you do not have to dispose of (the container takes care of it) and is supposed to play nice with container-managed transactions.

Categories

Resources