I have a stateless bean that observes an event and saves a record:
#Stateless
public class Manager {
#Inject
Repository repository;
Manager() {}
#Inject
Manager(Repository repository) {
this.repository = repository;
}
public void EventHandler(#Observes MyEvent myEvent) {
save(event.obj);
}
private save(Object object) {
repository.add(object);
}
}
My repository is like this:
#Stateless
public class Repository {
#PersistenceContext
EntityManager em;
Repository() {}
public void add(Object object) {
em.persist(object);
// em.flush(); <---
}
}
It doesn’t work unless I uncomment the line
The thing I don’t understand is why do I need to flush! Shouldn’t the transaction commit automatically?
Could it be that I have an EJB container and the cdi transaction started by Observes never actually ends but do something weird? Or it ends but doesn’t commit because he doesn’t know about EJB?
persist() is not meant to insert the row immediately, but rather at flush time, which is usually immediately before transaction commit.
However, if this is not what you are asking, but the row is not inserted even after the transaction has ended, it may be that flush mode for that transaction is set to manual.
Related
I need some clarification regarding Spring transation.
In ClassA I am creating a declaritive transaction. From ClassA I am calling method1() of ClassB.
ClassB is having #Transactional(propagation = Propagation.REQUIRED) annotation in classs level.
In method1() I am doing a save operation.
My question is, when that data will be committed ? Will it be committed while control will come out from
method1()? or in ClassA where we are committing the transaction manually ?.
Code:
ClassA
class ClassA {
void myMethod() {
TransactionStatus status = null;
DefaultTransactionDefinition def =
new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
def.setTimeout(contentFileProcessingConfigBean.getFileCopyTransactionTimeout());
status = transactionManager.getTransaction(def);
b.method1();
if (status != null) {
transactionManager.commit(status);
}
}
}
ClassB
#Transactional(propagation = Propagation.REQUIRED)
class ClassB {
void method1() {
//doing save operation
}
}
Probably after B.method1() finishes the aspect which is wrapping the call to #Transactional (visible in the stack trace) will commit the transaction. However this will depend on:
Are A and B are both Spring beans?
Is the same transactionManager bean used by transactions in A and B?
Maybe if A is written using TransactionTemplate instead of plain TransactionManager object.
Mixing the manual and declarative transaction management is not recommended as you have to guess. I guess it will come to transactionManager which you are not showing.
Given
class CallingClass {
#Autowired SomeService someService;
doit() {
someService.readOnlyCall();
}
}
#Transactional(readOnly = true)
class SomeService {
#Autowired AnotherService anotherService;
readOnlyCall() {
// logic which may then do...
anotherService.writeCall();
}
}
class AnotherService {
#Transactional // not readonly
writeCall() {
// save some entity
}
}
Will the entity be committed to the database when the writeCall method exits or when the readOnlyCall method exits?
And how can you modify it so it commits after the writeCall method?
The entity will not be committed to the database in both method exits. It is because
Your SomeService class has read-only (which you have specify). It will set FlushMode.NEVER which to prevent commit the transaction
Your SomeService class and AnotherService class has REQUIRED propagation type(which is by default and you have not specify other type for both class). It will create a new transaction if doesn't exist but will use current transaction if there is.
In this case the SomeService class begin transaction with read-only and AnotherService class will participates in the existing read-only transaction. Therefore, no entity will be committed.
To make it commits after the writeCall method, just add setting on writeCall method as below:
#Transactional (readOnly = false, propagation =Propagation.REQUIRES_NEW) // not readonly
writeCall() {
// save some entity
}
These settings have precedence for writeCall method. It will suspend current read-only transaction and create a new read/write transaction. Therefore, it will commits after the writeCall method complete transaction.
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)
}
I'm using a UnitOfWork in a background task method (operated by Quartz) with Guice-persist on top of hibernate. The background task call a service, which need to commit the current transaction in the middle of it's task - and continue on another transaction. How can I commit the current UnitOfWork and create a new one?
class BackgroundJob {
#Inject UnitOfWork unitOfWork;
#Inject MyService myService;
public void run() {
try {
unitOfWork.begin();
myService.foo();
} finally {
unitOfWork.end();
} } }
class MyServiceImpl implements MyService {
#Override public void foo() {
foo1();
// I would like to commit here and start a new transaction
foo2();
} }
The service is also managed by Guice, but is a singleton, and do not have access to the caller UnitOfWork as is.
Ideally I do not want to change service signature. A workaround is for the caller to give two UnitOfWork as parameters to foo(), but this seems a bit hacked.
EDIT: For ease of use of future fellow reader, here is my implementation of the solution given by ColinD, which fits the bill nicely:
class BackgroundJob {
#Inject UnitOfWork unitOfWork;
#Inject MyService myService;
public void run() {
try {
unitOfWork.begin();
myService.foo();
} finally {
unitOfWork.end();
} } }
class MyServiceImpl implements MyService {
#Override public void foo() {
foo1();
foo2();
}
#Transactional private void foo1() { ... }
#Transactional private void foo2() { ... }
}
If I recall correctly, a unit of work in Guice Persist is not a single transaction. Rather, it represents a single unit of work such as a single web request or, in your case, a single background job. I believe that a single database connection is used for a whole unit of work, but that unit of work may have multiple distinct transactions. In fact, I think that just starting and ending a unit of work will not cause any transactions to be started or ended.
I think what you want to do is to annotate both foo1() and foo2() (but not foo()) with #Transactional. As long as there's no outer transaction wrapping both calls, they'll each run in a separate transaction.
This may fit the bill.
class BackgroundJob {
#Inject UnitOfWork unitOfWork;
#Inject MyService myService;
public void run() {
try {
unitOfWork.begin();
myService.foo1();
unitOfWork.end();
unitOfWork.begin();
myService.foo2();
unitOfWork.end();
} finally {
unitOfWork.end();
}
}
}
I am using JPA with Spring. If I were to let Spring handle the transactions, then this is what my Service layer would look like assuming the EntityManager has been properly injected into the DAOs:
MyService {
#Transactional
public void myMethod() {
myDaoA.doSomething();
myDaoB.doSomething();
}
}
However, if I were to do transactions manually, I have to make sure to pass that instance of EntityManager into each of the DAOs within a transaction. Any idea how can this be better refactored? I fee ugly doing new MyDaoA(em) or passing em into each DAO method like doSomething(em).
MyService {
private EntityManagerFactory emf;
public void myMethod() {
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
MyDaoA myDaoA = new MyDaoA(em);
MyDaoB myDaoB = new MyDaoB(em);
try {
tx.begin();
myDaoA.doSomething();
myDaoB.doSomething();
tx.commit();
} catch(Exception e) {
tx.rollback();
}
}
}
However, if I were to do transactions
manually, I have to make sure to pass
that instance of EntityManager into
each of the DAOs within a transaction.
This is where you are wrong. From the Spring Reference, JPA section:
The main problem with such a DAO is
that it always creates a new
EntityManager through the factory. You
can avoid this by requesting a
transactional EntityManager (also
called "shared EntityManager" because
it is a shared, thread-safe proxy for
the actual transactional
EntityManager) to be injected instead
of the factory:
public class ProductDaoImpl implements ProductDao {
#PersistenceContext
private EntityManager em;
public Collection loadProductsByCategory(String category) {
Query query = em.createQuery(
"from Product as p where p.category = :category");
query.setParameter("category", category);
return query.getResultList();
}
}
The #PersistenceContext annotation has
an optional attribute type, which
defaults to
PersistenceContextType.TRANSACTION.
This default is what you need to
receive a shared EntityManager proxy.
add this to your spring config
<bean p:entityManagerFactory-ref="emf" class='org.springframework.orm.jpa.support.SharedEntityManagerBean' />
now you can #Autowired EntityManager inside your dao
for the transaction management, since you already using spring, and #Transactional annotation, i assume you already have one transaction manager declared in your spring.xml
so using spring's transaction management
as
transactionStatus = platformTransactionManager.getTransaction(new DefaultTransactionDefinition());
// do your work here
platformTransactionManager.commit(transactionStatus );
Shot in the dark a bit I guess, but do you know you can do:
TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
That usually eliminates the majority of cases where you would want/need to use programmatic transactions in a system that otherwise has declarative transactions.