JPA Transaction scope - jpa

I am having a container-managed transaction and three Enterprise Java Beans. The first bean is a link between other two EJBS:
#Stateful
public class UserManagement
{
#EJB
UsersFacade usersFacade;
#EJB
UserDetailsFacade userDetailsFacade;
public void addUser()
{
//Point 1
UserEntity ue = new UserEntity();
UserDetailsEntity ude = new UserDetailsEntity();
ue.setDetails(ude);
userFacade.create(ue); //Wrapper around EntityManager.persist method
userDetailsFacade.create(ude); Wrapper around EntityManager.persist method
//Point 2
}
}
Question: Will all of the operations within addUser() be performed in single transactions (userFacade.create and userDetailsFacade.create ) ?
Does #TransactionAttribute(TransactionAttributeType.REQUIRED) mean that transaction starts togheter with addUser method and it includes all methods executed from within addUser method. And the transaction ends in the moment when addUser ends?
And how to make sure that addUser will have its own private transaction (which will include methods from within it) and that the transaction will be commited when the method terminates. ?

Related

#Transactional and serializable level problem

I have a problem with isolation levels in JPA. For example I have following code:
#Transactional(isolation = Isolation.SERIALIZABLE)
public void first() {
Obj obj = new Obj();
obj.setName("t");
objDAO.save(obj);
second();
}
#Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.SERIALIZABLE)
public void second(){
List<Obj> objs = objDAO.findAll();
}
In my opinion the second method should not see uncomitted changes from method first. So new object with name "t" should not be visible till commit (but it is).
If I am wrong, then please, give me example in JPA where it won't be visible. Many thanks for any advice.
If your methods are inside one class it will not work because container will treat this as a single transaction. The container doesn't know that you want to create new transaction.
From the Spring reference:
Note: In proxy mode (which is the default), only 'external' method calls coming in through the proxy will be intercepted. This means that 'self-invocation', i.e. a method within the target object calling some other method of the target object, won't lead to an actual transaction at runtime even if the invoked method is marked with #Transactional!
If you want to call method second() in new transaction you can try this:
#Autowired
private ApplicationContext applicationContext;
#Transactional(isolation = Isolation.SERIALIZABLE)
public void first() {
Obj obj = new Obj();
obj.setName("t");
objDAO.save(obj);
applicationContext.getBean(getClass()).second();
}
#Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.SERIALIZABLE)
public void second(){
List<Obj> objs = objDAO.findAll();
}

When does a object become detached in Spring Data JPA?

I have a service that is using a Spring Data Repository to retrieve an object. The service is NOT marked as transactional, thus I assumed that any object returned from the repository would be detached since the transaction would be scoped to the repository. However, it seems as though the object is NOT detached which surprises me. Here is a code sample:
public class MyService {
#Autowired
private MyRepository repo;
#Autowired
private EntityManager entityManager;
/**
* Updates a persisted entity based on the given DTO representation.
*/
public MyObjectDto update(MyObjectDto dto) {
MyObjectJpa existing = repo.findOne(dto.getId());
entityManager.isJoinedToTransaction(); // returns false so no transaction should be active in this scope I would assume
entityManager.contains(existing); // this returns true, but I don't know why
if (existing != null) {
MyObjectJpa updated = toJpa(dto);
// calling repo.save(..) modifies the state of 'existing' object which surpised me
MyObjectDto updatedDto = toDto(repo.save(updated));
return updatedDto;
}
return null;
}
Why is the 'existing' object in my code sample still managed by the entityManager even though my service method is not marked as transactional (i.e. not using the #Transactional annotation from Spring)? Thanks.
In Spring Boot parameter spring.jpa.open-in-view is set to true by default.
I think you should turn it to false.
From java-doc:
Register OpenEntityManagerInViewInterceptor. Binds a JPA EntityManager to the thread for the entire processing of the request.

change the OptimisticLockPolicy to use local-time

I'm using Eclipselink JPA, I have an Entity with a Timestamp field annotated with #Version por optimistic locking.
By default, this sets the entitymanager to use database time, so, if I have to do a batch update it doesn't work properly as it query the database for time each time it wants to do an insert.
How can I change the TimestampLockingPolicy to use LOCAL_TIME?
The class org.eclipse.persistence.descriptors.TimestampLockingPolicy.class has a public method useLocalTime() but I dont know how to use or, from where should I call it.
Found the answer:
first lets create a DescriptorCustomizer
public class LocalDateTimeCustomizer implements DescriptorCustomizer {
#Override
public void customize(ClassDescriptor descriptor) throws Exception {
OptimisticLockingPolicy policy = descriptor.getOptimisticLockingPolicy();
if (policy instanceof TimestampLockingPolicy) {
TimestampLockingPolicy p = (TimestampLockingPolicy) policy;
p.useLocalTime();
}
}
}
then annotate the entity that has the #Version with
#Customizer(LocalDateTimeCustomizer.class)

Using a Producer Method To Choose a Bean Implementation

I followed the example on here for dynamically selecting the implementation to inject during run time. I then try to implement it based on my understanding but my code always return the default implementation;
Here is my code
#Stateless
public class MemberRegistration {
#Inject
private Logger log;
#Inject
private EntityManager em;
#Inject
private Event<Member> memberEventSrc;
#Inject
#Switch
IHandler handler;
private int handlerValue;
public String testCDI(int value) {
handlerValue = value;
log.info("handling " + value);
log.info("handling " + handlerValue);
return handler.handle();
}
#Produces
#RequestScoped
#Switch
public IHandler produceHandler(#New Handler0 handler0,
#New Handler1 handler1) {
log.info("Calling producer method with handler: "+handlerValue);
switch (handlerValue) {
case 1:
log.info("returning one");
return handler1;
case 0:
log.info("returning 0");
return handler0;
default:
log.info("returning default");
return handler1;
}
}
}
When i call the method testCDI I then update the handlerValue so that my producer method can use that value. What am I missing here to ensure that the producer method is called when the right value is available?
The code is running on Wildfly 8.2.0
The instance injected isn't going to be resolved when you call the method, but at the time of injection of the bean (the stateless session bean in this case). As a result, handlerValue will be 0.
You can however use an Instance<IHandler> to defer the injection. Use an annotation literal instead of your switch to do something like
#Inject
#Any
private Instance<IHandler> handlerInst
Then in your code
IHandler handler = handlerInst.select(new SwitchLiteral(value)).get();
then do work against that guy, but in your producer you need to use the InjectionPoint class to read the Switch annotation represented by the SwitchLiteral
You are running into cycling dependency here with your simplified code. Fields injected with plain #Inject need to be resolved BEFORE MemberRegistration is created, but handler field can only be created with a producer method AFTER MemberRegistration is created (beans with producer methods are created according to same rules as other CDI beans).
There are 2 solutions:
Either you create a separate HandlerProducer class, which will contain produceHandler() method and also handlerValue field. You should mark the class as #ApplicationScoped in order to reuse the same instance all over.
Or you need not only to produce IHandler dynamically, but also use (inject it) dynamically only when really needed in the MemberRegistration - this way handler is produced not BEFORE MemberRegistration is created, but after or never if not required. You do this by injecting Instance object and then use its get() method to retrieve handler when needed. Anyway, I am not sure if CDI will create a new instance every time, or reuse existing EJB. Scopes of EJBs and plain CDI beans are completely different and in general, I would not use an EJB as a bean with producer methods. It is better to always create a separate bean for producer methods, as in solution 1.
Example for solution 2 follows:
#Inject
#Switch
Instance<IHandler> handlerInjector;
private int handlerValue;
public String testCDI(int value) {
handlerValue = value;
log.info("handling " + value);
log.info("handling " + handlerValue);
return handlerInjector.get().handle();
}

Why transaction can't commit in a self-invoked ejb method with #REQUIRES_NEW Annotation

First I want to explain my self-invoked ejb method in this situation. I have a stateful session bean with a method which starts a new transaction (Annotated by #REQUIRES_NEW). To invoke this method inside the bean itself and make the annotation effective, I use SessionContext#getBusinessObject() to achieve the effect of #EJB (#EJB here causes stackoverflow?!). My code is shown below:
#Stateful
#Local
public class TransactionTest implements ITransactionTest {
#PersistenceContext(unitName="Table",Type=PersistenceContextType.EXTENDED)
private EntityManager manager;
#Resource
SessionContext sc;
ITransactionTest me;
#PostConstruct
public void init(){
me = this.sc.getBusinessObject(ITransactionTest.class);
}
public void generateRecord(int i) throws RuntimeException{
Record record = new Record();
record.setId(i+"");
record.status(1);
manager.persist(record);
manager.flush(); //If not flush, result is correct. Why?
me.updateRecord(i);
}
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void updateRecord(int i) throws RuntimeException{
try {
Record record = manager.find(Record.class, i+"");
record.setStatus(2);
manager.flush();
} catch(Exception e) {
e.printStackTrace();
throw new RuntimeException();
}
}
}
While,generateRecord() runs properly. The console shows it executes 'insert' and 'update' HQL without any exception (I use Hibernate as JPA provider). However, the 'update' result doesn't appear in the database. Why? Does updateRecord() commit correctly?
Also, I try it in two altenative ways: First is invoking generateRecord() (it will no longer invoke updateRecord()) and updateRecord() consecutively in another bean. It can give me the right result.
The second is removing the first flush(). Then both 'insert' and 'update' HQL will be executed at the second flush(). This method can also produce right result.
My program is running under JBOSS 6.1.0-Final and database is Oracle.
Best Regards,
Kajelas