Transactions with Spring and JPA - java

I am learning to use JPA. And I'm a little confused.
According JPA EntityManager manages transactions. But a design pattern is to inject the EntityManager in DAOs. So how is possible that are different EntityManager to the same transaction?
This is the case I want to solve
I have the DAOs defined
#Repository
JPARepository1 {
#PersistenceContext
protected EntityManager em;
....
.
#Repository
JPARepository2 {
#PersistenceContext
protected EntityManager em;
....
I have a Service
#Service
public class ServiceImpl1 {
#Autowired
private JPARepository1 repo1;
#Autowired
private JPARepository2 repo2;
public void mainMethod(){
Object o= transactionalMethod1();
try{
transactionalMethod2(o);
}catch (Exception e){
transactionalMethod3(o);
}
}
private Object transactionalMethod1(){
....
}
private void transactionalMethod2(Object o){
....
}
private void transactionalMethod3(Object o){
....
}
Then from #Controller I will invoke mainMethod().
What would be the right way to do transactional to transactionalMethod1, transactionalMethod2 and transactionalMethod3,within the same Service and using the same Repository's.
I would like it if there is an exeption in transactionalMethod2, this abort the transaction, but keep the transactions of transactionalMethod1 and transactionalMethod3
Thanks, sorry for my English

Usually you configure one EntityManager, so the wired manager is always the same, the one you configured. The instance of this manager though, is different in every wiring.
So, every transaction in your service uses a different instance of the EntityManager and thus every transaction invoked is seperated from each other.
As so, an exception in transactionalMethod2 doesn't necessarily affects the transactionalMethod1 and transactionalMethod3
What would be the right way to do transactional to transactionalMethod1, transactionalMethod2 and transactionalMethod3,within the same Service and using the same Repository's.
Now, you have two options to do service methods transactions
1) You could annotate your whole #Service like that:
#Service
#Transactional
public class ServiceImpl1 {
....
so every method declared here is also a transaction.
2) You could annotate each method as #Transactional:
#Transactional
private Object transactionalMethod1(){
....
}
#Transactional
private void transactionalMethod2(Object o){
....
}
#Transactional
private void transactionalMethod3(Object o){
....
}
If you want to use a single repository just #Autowired a single one and use it in your #Transactional method. E.g:
#Service
#Transactional
public class ServiceImpl1 {
#Autowired
private JPARepository1 repo1;
public void mainMethod(){
Object o= transactionalMethod1();
try{
transactionalMethod2(o);
}catch (Exception e){
transactionalMethod3(o);
}
}
private Object transactionalMethod1(){
return repo1.findOne();
}
private void transactionalMethod2(Object o){
repo1.create(o);
}
private void transactionalMethod3(Object o){
repo1.delete(o)
}

Related

JPA Interface extending JpaRepository only, with use of EntityManager in default methods

First of all, for those who wanted to know how to use an EntityManager in an interface extending a JpaRepository.
Here is a potential solution.
But !!! I'm aware this is maybe a baaaad practice, and experienced people in Spring and JPA will maybe try to kill me ;) apologizes...
So, after this BIG warning, here is my question :
I would like to use only interfaces without a Custom implementation and this is what I did :
#Repository
#Transactional
public interface BookingDao extends JpaRepository<Booking, Long> {
Booking findByCodeId(String codeId);
void deleteByCodeId(String codeId);
default Integer findCountOfBookingOldDay() {
EntityManager entityManager = ApplicationContextProvider.getEntityManager();
Query query = entityManager.createNativeQuery("XXXX");
Number result = (Number) query.getSingleResult();
return result.intValue();
}
}
#Component(value = "applicationContextProvider")
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext context;
public static ApplicationContext getApplicationContext() {
return context;
}
public static EntityManager getEntityManager() {
return EntityManagerFactoryUtils.getTransactionalEntityManager(context.getBean(LocalContainerEntityManagerFactoryBean.class).getObject());
return context.getBean(EntityManager.class);
}
#Override
public void setApplicationContext(ApplicationContext ac) throws BeansException {
context = ac;
}
}
I'm aware this is maybe not the best practice, and the best way would be to use #PersistenceContext (takes care to create a unique EntityManager for every thread) in a class... But what would be in my case the best alternative :
this :
return EntityManagerFactoryUtils.getTransactionalEntityManager(context.getBean(LocalContainerEntityManagerFactoryBean.class).getObject());
or this :
return context.getBean(EntityManager.class)
or maybe another better way, still by using only interface.
Thank you for your remarks/advices.
PS: "EntityManagerFactoryUtils" is not doing the same as PersistenceContext ?
For what you want to do I'd annotate a method in the interface by #Query("<your native select counting what you need>", native=true).
When I need any fancy logic, I usually create a service, which is using the repository like this:
#Service
#Transactional
public class MyService {
private final MyRepository repository;
#Autowired
public MyService (MyRepository repository) {
this.repository = repository;
}
public int myMethod(){
//code using repository
}
}

Correct use of the EntityManager in an #Async call

I am trying to use the #Async capabilities of the Spring framework to perform a simple indexing task.
The problem I'm facing is that I feel that the EntityManager used in my Async function is somehow reused from previous calls so my data is not up to date and sometimes uses old data.
Here is the code I wrote as an example. The goal is to update a product's data and index it asynchronously after I publish an event using Spring's ApplicationEventPublisher:
ProductService
#Service
class ProductService {
private final EntityManager entityManager;
private final ApplicationEventPublisher eventPublisher;
#Autowired
public ProductService(EntityManager entityManager, ApplicationEventPublisher eventPublisher) {
this.entityManager = entityManager;
this.eventPublisher = eventPublisher;
}
#Transactional
public void patchProduct (String id, ProductDto productDto) {
Product product = this.entityManager.find(Product.class, id);
product.setLabel(productDto.getLabel());
this.entityManager.flush();
this.eventPublisher.publishEvent(new ProductEvent(product, ProductEvent.EVENT_TYPE.UPDATED));
}
}
EventListener
#Component
public class ProductEventListener {
private final AsyncProcesses asyncProcesses;
#Autowired
public ProductEventListener (
AsyncProcesses asyncProcesses
) {
this.asyncProcesses = asyncProcesses;
}
#EventListener
public void indexProduct (ProductEvent productEvent) {
this.asyncProcesses.indexProduct(productEvent.getProduct().getPok());
}
}
AsyncProcesses
#Service
public class AsyncProcesses {
private final SlowProcesses slowProcesses;
#Autowired
public AsyncProcesses(SlowProcesses slowProcesses) {
this.slowProcesses = slowProcesses;
}
#Async
public void indexProduct (String id) {
this.slowProcesses.indexProduct(id);
}
}
SlowProcesses
#Service
public class SlowProcesses {
private EntityManager entityManager;
private ProductSearchService productSearchService;
#Autowired
public SlowProcesses(EntityManager entityManager, NewProductSearchService newProductSearchService) {
this.entityManager = entityManager;
this.newProductSearchService = newProductSearchService;
}
#Transactional(readonly = true)
public void indexProduct (String pok) {
Product product = this.entityManager.find(Product.class, pok);
// this.entityManager.refresh(product); -> If I uncomment this line, everything works as expected
this.productSearchService.indexProduct(product);
}
}
As you can see on the SlowProcesses file, if I refresh the product object in the entityManager, I get the correct and up to date data. If I do not, I might get old data from previous calls.
What is the correct way to use the EntityManager in an Asynchronous call? Do I really have to refresh all my objects in order to make everything work? Am I doing something else wrong?
Thank you for reading through
Since instances of EntityManager are not thread-safe as pointed out by Jordie, you may want to try this instead:
Instead of injecting an EntityManager, inject an EntityManagerFactory. Then from the EntityManagerFactory retrieve a new EntityManager instance that is used only for the duration of the method in question.

JPA/Hibernate dynamically injecting entity manager

I have a JPA/hibernate setup with multiple entity managers. What I am trying to do is dynamically injecting the entity manager in an abstract class used by multiple schemas with the same entity definition -- the tables are exactly the same across different databases in a single MySQL server. I am trying not to write unnecessary duplicate code, but I can't seem to find a way to inject the persistence context dynamically without duplicating a lot of code. Is there any way to do this?
Well, do you need to change the EntityManager that exists in a DAO instance? If yes, I'd say just switch your connection pool instead.
If instead you want to select to which instance to connect, set up the necessary keys in one or more profiles, then use that to get the necessary connection properties for your connection pool.
If you want to have multiple instance of the same DAO, use qualified beans and constructor injection to get the proper entity managers to them (abstract away everything else like factory / pool creation into methods).
I ended up creating an abstract DAO with all the basic list, update, delete methods and extending by another abstract DAO in which I set the entity manager for that particular set. Any DAOs that extend the last one will have the correct annotated entity manager associated with them. From that point on I am able to reuse my models, and all I have to do is extend the right DAO on my service layer.
The magic happens by calling setEntityManager(EntityManager em) using the #PerisstenceContext with the persistence unitName. I am not entirely sure why this works, but seems to do the trick.
Here's what I did:
AbstractJpaDao:
#MappedSuperclass
public class AbstractJpaDao <T>{
private Class<T> clazz;
protected EntityManager entityManager;
public final void setClazz(final Class<T> clazzToSet) {
this.clazz = clazzToSet;
}
#Transactional
public T getById(final long id) {
return entityManager.find(clazz, id);
}
//... all the others ...
}
InheritedDao1:
#MappedSuperclass
public class InheritedDao <T> extends AbstractJpaDao <T>{
//This is what allows me to inject the entityManager by its annotation
#PersistenceContext(unitName = "myPU")
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
}
InheritedDao2:
#MappedSuperclass
public class OtherInheritedDao <T> extends AbstractJpaDao <T>{
//This is what allows me to inject the entityManager by its annotation
#PersistenceContext(unitName = "otherPU")
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
}
Service1:
#Service
#Transactional(readOnly = true)
public class MyService extends InheritedDao<MyModel> {
public MyService() {
setClazz(MyModel.class);
}
}
Service2:
#Service
#Transactional(readOnly = true)
public class OtherService extends OtherInheritedDao<MyModel> {
public OtherService() {
//same model as used in MyService
setClazz(MyModel.class);
}
}

Understanding of Transactional services - spring

I have a service implementation with a particular method like so:
public class ExampleServiceImpl implements ExampleService {
#AutoWired
#Resource
private RecordRepository recordRepository;
private void processRecord() {
// some code here
}
#Transactional(readOnly=false)
public void processRecord(Record a) {
Record original = getOriginal(a);
recordRepository.saveChanges(a,original);
}
}
Where the Record class is the root object of an object graph. RecordRepository looks something like the following with sub repositories to save various children of the objects in the graph.
public class RecordRepository extends BaseRepository<Record> {
#AutoWired
#Resource
private IDao databaseDao;
#AutoWired
#Resource
private SubRecordRepository subRecordRepository;
public void saveChanges(Record a, Record b) {
//Perform some processing on a, b
for(SubRecord subA : a.getSubRecords()) {
subRecordRepository.saveChanges(subA);
}
databaseDao.updateRecord(a);
}
}
public class DatabaseDao extends NamedParameterJdbcDaoSupport implements IDao {
#Autowired
public DatabaseDao(#Qualifier("org.somewhere.Datasource") DataSource ds) {
super();
this.setDataSource(ds);
}
public void updateRecord(Record inRecord) {
String query = (String) sql.get("updateRecord");
SqlParameterSource parms = new BeanPropertySqlParameterSource(inRecord);
getNamedParameterJdbcTemplate().update(query, parms);
}
public void insertSubRecord(SubRecord inSubRecord) {
String query = (String) sql.get("insertSubRecord");
SqlParameterSource parms = new BeanPropertySqlParameterSource(inSubRecord);
getNamedParameterJdbcTemplate().insert(query, parms);
}
// other update and insert methods
}
Will the transaction be applied across all involved inserts\updates from the processRecord call? In other words, if an insert or update fails, will all previously called inserts and updates from ExampleServiceImpl.processRecord get rolled back?
Yes. The transactional aspect makes sure that a transaction is started before the annotated method is called, and that the transaction (if started by this method) is committed or rollbacked once the method returns.
The transactional interceptor doesn't know (and doesn't care) about which other methods are called inside the annotated method. Every read and write to the DataSource handled by the Spring transaction manager will be included in the same transaction.

Injecting multiple dao into one service

if I have several DAOs to be injected into a Service that need to work together in a single transaction, how can I do this ?
#Component
public class CallerClass{
#Autowired
private TransactionClass1 class1;
#Autowired
private TransactionClass2 class2;
public void saveOperation(){
try{
class1.save();
class2.save();
}catch(Exception ex){
}
}
}
Like above simple codes. However, this code is lack
You would just inject all the DAOs in the same manner as you do normally i.e. setter or constructor using #Inject or #Autowired.
You then annotate your service method as Transactional and invoke the required operations on the multiple DAOs. The transaction will encompass all of the dao calls within it.
#Transactional
public void doStuff() {
dao1.doStuff();
dao2.doStuff();
}
You must open the transaction before you use the first dao (For example with #Transactional).
public class MyService{
#Inject
Dao1 dao1;
#Inject
Dao2 dao2;
#Transactional
public doStuffInOneTransaction{
Object x = dao1.load();
Object y = doSomething(x);
dao2.save(y);
}
}
Do you use JTA? Do you implement your transactions on your own? Please provide more information about your architecture so we can respond accordingly.
EDIT:
Check this one out, for example:
http://community.jboss.org/wiki/OpenSessionInView

Categories