I have a situation where lets say I have two services
AccountService
CustomerService
Both annotated with #Transactional with some createXXX() methods.
Now from my AccountController lets say I have a method where I would first call createAccount() and once I get back the Account-ID from createAccount() I may then call createCustomer() (To create a Customer and also update Account-ID from Account on the Customer)
If for some reason createCustomer() fails I will be left with a polluted state where Account has already been persisted but no Customer created.
Should I resolve this with a TransactionSynchronizationManager OR how should I handle this situation?
Spring transaction use REQUIRES propagation level by default (see org.springframework.transaction.annotation.Transactional#propagation). It means, Spring will not create a new transaction unless there is an existing one. Use this feature: you can either annotate controller's method with #Transactional or create a new service that will trigger the top-level transaction. The idea is that as soon as you created one transaction, service calls will not create new ones. As a result, you have just one transaction that can either successfully commit or fail.
Related
I have applied #Transactional in my interface, and inside my serviceImpl, the corresponding method is calling some other methods, one method is reading, another method is writing. Although I have anotated as Transactional, when I am giving concurrent request, my insert method is throwing org.hibernate.exception.LockAcquisitionException: error.
Another problem is, this insert method is a shared method and it performs the insert method like Dao.save(obj) . Dao.save() is a generic method So i can not do anything here. I have to apply something on interface to avoid no lock aquired exception.
Is it possible to tell wait untill lock is aquired? Or retry if transaction is failed? Or lock all the tables until the transaction is completed so that another request can not access the relevent resources?
My hibernate version is 3.x, And database is mysql 5.6
The best way to do this is,
Mark your methods transactional
In your mysql database settings set the transaction isolation level as SERIALIZABLE
I am using Hibernate4 but not Spring. In the application I am developing I want to log a record of every Add, Update, Delete to a separate log table. As it stands at the moment my code does two transactions in sequence, and it works, but I really want to wrap them up into one transaction.
I know Hibernate does not support nested transactions, only in conjunction with Spring framework. I´ve read about savepoints, but they´re not quite the same thing.
Nothing in the standards regarding JPA and JTA specification has support for nested transactions.
What you most likely mean with support by spring is #Transactional annotations on multiple methods in a call hierarchie. What spring does in that situation is to check is there an ongoing transaction if not start a new one.
You might think that the following situation is a nested transaction.
#Transactional
public void method1(){
method2(); // method in another class
}
#Transactional(propagation=REQUIRES_NEW)
public void method2(){
// do something
}
What happens in realitiy is simplified the following. The type of transactionManager1 and transactionManager2 is javax.transaction.TransactionManager
// call of method1 intercepted by spring
transactionManager1.begin();
// invocation of method1
// call of method 2 intercepted by spring (requires new detected)
transactionManager1.suspend();
transactionManager2.begin();
// invocation of method2
// method2 finished
transactionManager2.commit();
transactionManager1.resume();
// method1 finished
transactionManager1.commit();
In words the one transaction is basically on pause. It is important to understand this. Since the transaction of transactionManager2 might not see changes of transactionManager1 depending on the transaction isolation level.
Maybe a little background why I know this. I've written a prototype of distributed transaction management system, allowing to transparently executed methods in a cloud environment (one method gets executed on instance, the next method might be executed somewhere else).
I am using the play framework to develop a web application which accesses a postgres db using JOOQ and spring transactions.
Currently I am implementing the user signup which is structured in the following way:
The user posts the signup form
The request is routed to a controller action which maps all parameters like e-mail, password etc. on a DTO. The different fields of the DTO are annotated with JSR 303 constraints.
The e-mail field is annotated with a constraint validator that makes sure that the same address is not added twice. This validator has an autowired reference to the UserRepository, so that it can invoke it's isExistingEmail method.
The signup method of the user service is called, which basically looks as follows:
#Transactional(isolation = Isolation.SERIALIZABLE)
public User signupUser(UserDto userDto) {
validator.validate(userDto);
userRepository.add(userDto);
return tutor;
}
In case of a validation error the validator.validate(userDto) call inside of the service will throw a RuntimeException.
Please note that the repository's add method is annotated with #Transactional(propagation = Propagation.MANDATORY) while the isExistingEmail method does not have any annotations.
My problem is that when I post the signup form twice in succession, I receive a unique constraint error from the database since both times the userRepository.isExistingEmail call returns false. However, what I would expect is that the second signup call is not allowed to add the user to the repository, as I set the isolation level of the transaction to serializable.
Is this the expected behavior or might there be a JOOQ/spring transactions configuration issue?
I added a TransactionSynchronizationManager.isActualTransactionActive() call in the service to make sure a transaction is actually active. So this part seems to work.
After some more research and reading the documentation on transaction isolation in the postgres manual I have come to realize that my understanding of spring managed transactions was just lacking.
When setting the isolation level to SERIALIZABLE postgres won't really block any concurrent transactions. Instead it will make use of predicate locks to monitor if a committed transaction would produce a result that is different than actually running concurrent transactions one after another.
An exception will only be thrown by the underlying database driver if the state of the data is not valid when the second transaction tries to commit. I was able to verify this behavior and to force a serialization failure by temporarily removing the unique constraint on my e-mail field.
My final solution was to reduce the isolation level to READ_COMMITTED and to handle the unique constraint violation exception when invoking userRepository.add(userDto), since a SERIALIZABLE isolation level is not really necessary to deal with this particular use case.
Please let me know of any better ways of dealing with this kind of standard situation.
I'm a new Spring user.
I have a question about scope and transaction.
For example, there's a service:
<bean id="bankInDaoService" class="service.dao.impl.UserDaoServiceImpl">
Let's say there are 2 people who want to bank-in at the same time.
And I already put #Transactional above for Hibernate transaction the method for bank-in purpose.
My questions are:
Since default Spring scope is singleton. Will these 2 people share the same values. (person 1 bank-in 500, person 2 bank-in 500)?
Will the #Transactional be effective? I mean let the first person finishes bank-in, and then person 2.
I'll be really thankful for your help.
You have wrongly understood the useage of #Transactional annotation.
#Transactional annotation is used in case where you want to get all or none of your transactions to be successful. If any of the transaction fails then other successful transaction will be rolled back. It is not for synchronisation.
If you have registration page where you take input for 10 fields and 5 are for table user and 5 are for table company and you are inseting both records from a single service function. At that time you should use #Transactional annotation. If insertion is successful in user table and fails in company table then the user table record will be rolled back.
Hope this helps you. Cheers.
You are correct that by default Spring beans are singletons. But this won't be a problem unless your implementation modifies some internal state on each invocation (which would be rather odd - typically a service method will just work with the parameters it's been given).
As I just alluded to, each service method invocation will have its own parameters; i.e.:
deposit(person1_ID, 500)
deposit(person2_ID, 750)
As you've said "at the same time" we can safely assume we have a multi-threaded server that is handling both these people simultaneously, one per thread. Method parameters are placed on the stack for any given thread - so as far as your service is concerned, there is absolutely no connection/chance of corruption between the two people's deposits.
Now turning to the #Transactional annotation: Spring uses "aspects" to implement this behaviour, and again these will be applied separately to each thread of execution, and are independent.
If you're looking for #Transactional to enforce some kind of ordering (for example, you want person2 to withdraw the exact amount person1 deposited) then you need to write a new method that performs both operations in sequence within the one #Transactional scope.
In a Grails app, the default behaviour of service methods is that they are transactional and the transaction is automatically rolled-back if an unchecked exception is thrown. However, in Groovy one is not forced to handle (or rethrow) checked exceptions, so there's a risk that if a service method throws a checked exception, the transaction will not be rolled back. On account of this, it seems advisable to annotate every Grails service class
#Transactional(rollbackFor = Throwable.class)
class MyService {
void writeSomething() {
}
}
Assume I have other methods in MyService, one of which only reads the DB, and the other doesn't touch the DB, are the following annotations correct?
#Transactional(readOnly = true)
void readSomething() {}
// Maybe this should be propagation = Propagation.NOT_SUPPORTED instead?
#Transactional(propagation = Propagation.SUPPORTS)
void dontReadOrWrite() {}
In order to answer this question, I guess you'll need to know what my intention is:
If an exception is thrown from any method and there's a transaction in progress, it will be rolled back. For example, if writeSomething() calls dontReadOrWrite(), and an exception is thrown from the latter, the transaction started by the former will be rolled back. I'm assuming that the rollbackFor class-level attribute is inherited by individual methods unless they explicitly override it.
If there's no transaction in progress, one will not be started for methods like dontReadOrWrite
If no transaction is in progress when readSomething() is called, a read-only transaction will be started. If a read-write transaction is in progress, it will participate in this transaction.
Your code is right as far as it goes: you do want to use the Spring #Transactional annotation on individual methods in your service class to get the granularity you're looking for, you're right that you want SUPPORTS for dontReadOrWrite (NOT_SUPPORTED will suspend an existing transaction, which won't buy you anything based on what you've described and will require your software to spend cycles, so there's pain for no gain), and you're right that you want the default propagation behavior (REQUIRED) for readSomething.
But an important thing to keep in mind with Spring transactional behavior is that Spring implements transaction management by wrapping your class in a proxy that does the appropriate transaction setup, invokes your method, and then does the appropriate transaction tear-down when control returns. And (crucially), this transaction-management code is only invoked when you call the method on the proxy, which doesn't happen if writeSomething() directly calls dontReadOrWrite() as in your first bullet.
If you need different transactional behavior on a method that's called by another method, you've got two choices that I know of if you want to keep using Spring's #Transactional annotations for transaction management:
Move the method being called by the other into a different service class, which will be accessed from your original service class via the Spring proxy.
Leave the method where it is. Declare a member variable in your service class to be of the same type as your service class's interface and make it #Autowired, which will give you a reference to your service class's Spring proxy object. Then when you want to invoke your method with the different transactional behavior, do it on that member variable rather than directly, and the Spring transaction code will fire as you want it to.
Approach #1 is great if the two methods really aren't related anyway, because it solves your problem without confusing whoever ends up maintaining your code, and there's no way to accidentally forget to invoke the transaction-enabled method.
Approach #2 is usually the better option, assuming that your methods are all in the same service for a reason and that you wouldn't really want to split them out. But it's confusing to a maintainer who doesn't understand this wrinkle of Spring transactions, and you have to remember to invoke it that way in each place you call it, so there's a price to it. I'm usually willing to pay that price to not splinter my service classes unnaturally, but as always, it'll depend on your situation.
I think that what you're looking for is more granular transaction management, and using the #Transactional annotation is the right direction for that. That said, there is a Grails Transaction Handling Plugin that can give you the behavior that you're looking for. The caveat is that you will need to wrap your service method calls in a DomainClass.withTransaction closure and supply the non-standard behavior that you're looking for as a parameter map to the withTransaction() method.
As a note, on the backend this is doing exactly what you're talking about above by using the #Transactional annotation to change the behavior of the transaction at runtime. The plugin documentation is excellent, so I don't think you'll find yourself without sufficient guidance.
Hope this is what you're looking for.