please could me somebody explain how working transaction in method, generally what is going. mapper is iBatis.
#Transactional
public void insert(SameDto same) {
sameDao.insert(same);
webserice.call(same);
}
SameDao.class ->
#Transactional
public void insert(SameDto same) {
mapper.updateToInvalidate(same);
SameDto other = new SameDto(...);
BigDecimal primaryKey= mapper.insert(other);
SameDto equalsSameDto = mapper.getByPrimaryKey(primaryKey);
continue ....
}
I don't understand because Object "equalsSameDto" is null. I could thinks that transaction is not committed yet. But it some legal way how to use it.
Thx for advise.
Related
I have 3 methods defined the following way. methodX and methodY are defined in different classes. methodY and methodZAsync are defined in same class.
#Transactional(propagation = Propagation.REQUIRED)
public void methodX(){
.....
methodY();
methodZAsync(); //
}
#Transactional(propagation = Propagation.REQUIRED)
public void methodY(){
.....
someDatabaseOperations();
.....
}
#Async
public void methodZAsync(){
.....
pollingBasedOnDataOperationsOfMethodY();
.....
}
The problem here is, methodZAsync requires methodY()'s DB operations to be committed before it can start it's work. And this fails because methodZAsync runs in a different thread.
One option is to make methodY's transaction to use #Transactional(propagation = Propagation.REQUIRES_NEW). But since methodY is used in multiple places with a different use cases, I'm not allowed to do that.
I've checked this question but TransactionSynchronization is an interface and Im not sure what to do with rest of the un-implemented methods.
So I thought, instead of making changes in methodY(), If I can somehow make methodX() to tell methodY() to use a new transaction(naive way: close current running transaction), It'll fix the things for me.
Is this doable from methodX() without having to modify methodY()?
You can create a new wrapper method around methodY() that creates a new transaction. Then you can call this new method from methodX() without impacting any other use cases.
#Transactional(propagation = Propagation.REQUIRED)
public void methodX(){
.....
methodYInNewTxn();
methodZAsync(); //
}
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodYInNewTxn() {
methodY();
}
#Transactional(propagation = Propagation.REQUIRED)
public void methodY(){
.....
someDatabaseOperations();
.....
}
Refer spring boot, there is also
#Transactional(propagation = Propagation.REQUIRES_NEW)
method are there go through. Hope you will get your proper answer
I've created the following captor:
public class CompanyOwnerMatcher extends ArgumentMatcher<CompanyOwner> {
private String uuid;
CompanyOwnerMatcher(String uuid) {
this.uuid = uuid;
}
#Override
public boolean matches(Object arg) {
if (!(arg instanceof CompanyOwner)) return false;
CompanyOwner owner = (CompanyOwner) arg;
return Objects.equals(uuid, owner.getUuid());
}
}
I get an exception in this code:
Mockito.verify(payInApi).submit(eq(1L), argThat(new CompanyOwnerMatcher(expectedOwnerUuid)));
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:148)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:266)
CompanyOwner is managed by hibernate. It's weird, but after I catch a CompanyOwner, I can't get any field values on it because I get LazyInitializationException, even on fields that are not marked as Lazy.
Would appreciate any help with regards to this problem.
Thanks!
I believe, Hibernate creates some kind of proxy of CompanyOwner.
Then it really depends on the code, the chances are that by the time you call the matcher the object is already detached from Hibernate Session.
In this case, you'll get the LazyInitializationException when you try to access fields like you've mentioned.
Its really impossible to understand out of the supplied code snipped why exactly the hibernate decides to wrap the object with proxy, I can only suggest to place a breakpoint in matches method to make sure that this is proxy indeed but then you'll have to figure out the reason for making this proxy.
If you see that proxy is indeed must be done in this case, probably the best would be "re-attaching" the object to the session. The exception should disappear however you'll probably see that hibernate issues a DB request in this case.
You might also be interested in This thread
if your object looks like it is proxied by hibernate (not yet fetched from DB because the entity is marked as LAZY), you can find out and force unproxy like this:
public <T extends BaseObject> T unproxy(final T arg) {
if (arg instanceof HibernateProxy) {
return (T) Hibernate.unproxy(arg);
}
return arg;
}
I recently stumbled into the next piece of Java EE6 code:
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void example(#Observes(during = TransactionPhase.AFTER_SUCCESS) final ExampleEvent exampleEvent) {
Is REQUIRES_NEW really needed?
I mean example method will always be called only after any previous transaction has ended successfully ( because of TransactionPhase.AFTER_SUCCESS).
Or am I missing something?
Your are only observing ExampleEvent, so your example()-Method will not be called by itself (based on the #TransactionAttribute) unless your do something like this:
#Inject
private Event<ExampleEvent> exampleEvent;
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void example(#Observes(during = TransactionPhase.AFTER_SUCCESS) final ExampleEvent exampleEvent) {
ExampleEvent event = new ExampleEvent();
exampleEvent.fire(event);
}
It makes sense to keep the #TransactionAttribute because the previous transaction just finished (AFTER_SUCCESS), so there is no current transaction therefore a new one is needed to be created. It can be possible that this would be done automatically (depending on the AS implementation) even without the annotation, but the result should be the same.
I have 2 methods in my service
public void updateAll() {
long[] ids = new long[] {1,2,3,4,5,6,7,8,9,10};
for (long id : ids) {
updateId(id);
}
}
public updateId(long id) {
repository.update(id);
}
Let's assume that after the 5th update I have an exception, I would like that the first 4 operations would be committed anyway.
I'm using the #Transactional annotation but if I put the annotation in both methods it doesn't work.
Do I need other parameter?? It might be propagation??
Could you show me how to set this methods?
Thank you!!
Just have:
#Transactional(propagation = Propagation.REQUIRES_NEW)
public updateId(long id) {
}
But, the important bit, call that method from another class.
i.e. move your loop out of this class.
The transactional annotations only kick-in when that public method is called from the outside. Within the same class, calling one transactional method from another will still only use the transaction of the first method.
You need a separate #Transactional on updateId with REQUIRES_NEW.
In my Stateful bean, I have the following lines:
#Stateful(mappedName = "ejb/RegistrationBean")
#StatefulTimeout(unit = TimeUnit.MINUTES, value = 30)
#TransactionManagement(value=TransactionManagementType.CONTAINER)
public class RegistrationStateful implements RegistrationStatefulRemote {
#PersistenceContext
EntityManager em;
private List<Event> reservedSessions = new ArrayList<Event>();
private boolean madePayment = false;
...
#TransactionAttribute(TransactionAttributeType.REQUIRED)
private void cancelReservation() {
if (reservedSessions.size() != 0) {
Teacher theTeacher;
for (Event session : reservedSessions) {
if ((theTeacher = session.teacher) == null) theTeacher = bestTeacher.teacher;
theTeacher = em.merge(theTeacher) //The exception is thrown here
//Make changes to theTeacher
em.flush(); //The exception is also thrown here
}
//Clear the reservedSessions list
reservedSessions.clear();
}
}
#Remove
public void endRegistration() {}
#PreDestroy
public void destroy() {
//Cancel outstanding reservations if payment has not been made
if (!madePayment) cancelReservation();
}
}
The line em.merge(someEntity) throws the TransactionRequiredException. Could someone please tell me why it happens? I thought with TransactionAttribute.REQUIRED, a transaction will AUTOMATICALLY be created if there isn't an active one. I tried to use em.joinTransaction() but it throws the same Exception. I'm a beginner at this transaction thing. I'd be very grateful if someone could explain this to me.
UPDATE: I'd like to add a bit more information
The Stateful bean actually also has the following function:
#TransactionAttribute(TransactionAttributeType.REQUIRED)
private void reserveSession(List<Event> sessions) throws ReservationException {
//Reserve the sessions
Teacher theTeacher;
for (Event session : sessions) {
if ((theTeacher = session.teacher) == null) theTeacher = bestTeacher.teacher;
theTeacher = em.merge(theTeacher);
//Make changes to theTeacher
em.flush();
}
}
The flow is as following: the user tells me his free time and I reserve some seats for him. After that, I show him his reserved seats and he can choose to make payment or cancel the reservations.
The reserved() function worked perfectly as expected but the cancelReservation() did not.
UPDATE 2: I have fixed the problem last night by commenting out the lines "#TransactionAttribute(TransactionAttributeType.REQUIRED)", "em.merge(theTeacher)" and "em.flush()" in the "cancelReservation()" function. The result is perfect. Would it be safe if I cut off those lines? I was afraid I would get "detached entity" exception when I used "em.merge()" in the first place.
The only thing that springs to mind (if you'll excuse the pun) is that if you're calling cancelReservation() from another method inside the bean, then i'm not sure the transaction annotation will be observed. The annotation ultimately works by summoning an interceptor, and i believe interceptors are only applied to calls between different classes (this is something i should really check).
So, if you have a non-transactional method on the bean which calls a transactional method, then a transaction won't be started when the transactional method is called.
I could be completely wrong about this. I'll go and have a bit of a read of the spec and get back to you.
EDIT: I had a read of the spec, and it reminded me what a disaster zone the J2EE specs are. Horrific. However, the section on transactions does seem to imply that the transaction attributes only apply to calls made to an EJB's business interface. I believe calls from one method to another inside a bean are not considered to go through the business interface, even when the method being called is part of that interface. Therefore, you wouldn't expect them to attract transactions.
Something you could try would be to route them through the interface; there is no nice way of doing this, but you should be able to inject a business-interface self-reference like this:
public class RegistrationStateful implements RegistrationStatefulRemote {
#EJB
private RegistrationStatefulRemote self;
You can then change your #PreDestroy method to look like this:
#PreDestroy
public void destroy() {
self.cancelReservation();
}
And i believe that should count as a normal business interface call, with transactions and so on.
I have never actually tried this, so this could be complete rubbish. If you try it, let me know how it works out!