I don not have any clear concept why we use #transactional annotation. My need a realtime concept for use this.
Please give me clear concept with example on this.
A transaction is a series of operations which either all occur or nothing occurs. In database systems you can therefore start a transaction, then execute a series of queries and then either commit the transaction if all the queries were successful or rollback if you had an error. During the transaction all the changes are only visible for you session and in case of a rollback all the changes you have made will be undone.
As a real world example you could take a money transfer from one account to another. There is one query to withdraw from an account and another query to credit the money to the other account. If you would execute those queries without a transaction and the second query fails for whatever reason, the money would have been withdrawn from one account but not credited to another, which means you would have eliminated money.
Spring built an abstraction layer for that with the #Transactional annotation, which starts a transaction before you method is called and commits it if all was fine or does a rollback when an exception was thrown.
public class MoneyTransferService {
#Autowired
private JdbcTemplate jdbcTemplate;
#Transactional
public void transferMoney(Double amount, Integer debitAccount, Integer creditAccount) {
jdbcTemplate.update("UPDATE accounts SET balance = balance - ? where accountId = ?", amount, debitAccount);
jdbcTemplate.update("UPDATE accounts SET balance = balance + ? where accountId = ?", amount, creditAccount);
}
}
Related
I am trying to create a Restful API with Spring boot and Spring data JPA to do the CRUD operations. The database will be Oracle relational database.Now for concurrent access , If we only use spring transactions using #Transactional, will that serve our purpose of concurrent CRUD operations.
I see there are JPA Optimistic and pessimistic locking strategy version column. My specific question is , for concurrent CRUD operations do we need both Spring transactions and JPA locking strategy? OR only configuring Spring transactions accordingly will be sufficient?
Try to start with the following simple approach that IMO will be suitable in many cases: Optimistic locking with Spring Retry.
1) Add version property annotated with #Version to your entities (you can do it in base abstract entity class, for example, to simplify the process):
#Entity
public class MyEntity {
#Id
#GeneratedValue
private Long id;
#Version
private Long version;
// other stuff
}
In this case when you, for example, will update your entity then Hibernate will use the current value of version property in condition clause of update query, and increment this value to store the entity with it. For example this code of some service:
#Transactional
public Optional<MyEntity> update(Long id, MyEntity source) {
return myEntityRepository
.findById(id)
.map(target -> mapper.updateEntity(source, target));
}
will generate the following SQL queries:
1. select * from my_entities where id = ?;
2. update my_entities set ..., version = <version value from query #1> + 1 where id = ? and version = <version value from query #1>;
So if another concurrent process manages to update this entity first, then your method fails with an exception (OptimisticLockException).
2) To manage to exceptions in that method, add #Retryable annotation to it (and #EnableRetry annotation on your config or application class):
#Retryable(maxAttempts = 2)
#Transactional
public Optional<MyEntity> update(Long id, MyEntity source) {
// ...
}
In this case, if an exception rises in that method it will be called again in a new transaction to repeat the operation.
Additional info:
Optimistic Locking in JPA
Guide to Spring Retry
My Spring Retry demo
Optimistic lock is default strategy of JPA. Optimistic locking is can be used for most of the applications. Optimistic lock is much more easier and efficient. Pessimistic lock need to be used in cases like, where you need to know Collision before committing your transaction.
So you do not need to configure a locking strategy.
I need to perform several operations in one transaction
produce kafka message
update Table A
update Table B
I'm fine with sending message and don't update both tables (A and B). I'm not ok to produce message and update one of tables.
I'm trying to achieve my goal using #Transactional annotation
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
#Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.SERIALIZABLE)
public void handle(Event approvalEvent) {
var entity = entityService.getLatestVersion(approvalEvent.getTransactionId());
entityService.approve(entity.getTransactionId());
logService.logApproval(entity);
producer.send(approvalEvent);
}
do I do it right?
The problem with the approach above that you are interacting with two distinct systems (Database and Message queue) in one transaction. The combinations of scenarios to handle when operation on one system is successful and fails in other system makes the solution complex.
There is pattern in the microservices world to handle the exact same scenario. It is called outbox pattern.
You can read more about it here.
The short summary is you have an additional table in your database called outbox that contains the messages that are to be published to the message queue.
In the DB transaction for adding\updating the entity you insert a row in the outbox table tool containing the details of operation on the entity.
Then you asynchronously read the rows from outbox table and publish to message queue either via poling or using change data capture. See a sample implementation here using debezium.
Your transaction code would look like this.
#Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.SERIALIZABLE)
public void handle(Event approvalEvent) {
var entity = entityService.getLatestVersion(approvalEvent.getTransactionId());
entityService.approve(entity.getTransactionId());
logService.logApproval(entity);
//Outbox is the table containing the records to be published to MQ
outboxRepo.save(approvalEvent);
}
In my spring boot application, I have parallel running multiple threads of following #Transactioanl method.
#Transactional
public void run(Customer customer) {
Customer customer = this.clientCustomerService.findByCustomerName(customer.getname());
if(customer == null) {
this.clientCustomerService.save(customer);
}
// another database oparations
}
When this running on multiple threads at the same time, since customer object will not be save until end of the transaction block, is there any possibility to duplicate customers in the database?
If your customer has an #Idfield which define a Primary Key column in Customer database, the database will throw you an exception like javax.persistence.EntityExistsException. Even if you run your code on multiple threads, at a point in time, maybe at the database level, only one will acquire a lock on the new inserted row. Also you must define #Version column/field at top entity level in order to use optimistic-locking. More details about this you can find here.
I am reading the transaction management Using Spring framework. In first combination I used Spring + hiberante and used Hibernate's API's to control the transaction (Hibenate API's). Next, I wanted to test using #Transactional annotation, and it did work.
I am getting confused on:
Do JPA , JTA, Hibernate have their "own" way of transaction
management. As an example, consider if I use Spring + Hibernate, in
that case would u use "JPA" transactions?
Like we have JTA, is it true to say we can use Spring and JTA to
control transactions?
The #Transactional annotation, is that specific to Spring
Framework? From what I understood, this annotation is Spring
Framework specific. If this is correct, is #Transactional using
JPA/JTA to do the transaction control?
I do read online to clear my doubts, however something I don't get direct answer. Any inputs would be great help.
#Transactional in case of Spring->Hibernate using JPA i.e.
#Transactional Annotations should be placed around all operations that are inseparable.
So lets take example:
We have 2 model's i.e. Country and City.
Relational Mapping of Country and City model is like one Country can have multiple Cities so mapping is like,
#OneToMany(fetch = FetchType.LAZY, mappedBy="country")
private Set<City> cities;
Here Country mapped to multiple cities with fetching them Lazily.
So here comes role of #Transactinal when we retrieve Country object from database then we will get all the data of Country object but will not get Set of cities because we are fetching cities LAZILY.
//Without #Transactional
public Country getCountry(){
Country country = countryRepository.getCountry();
//After getting Country Object connection between countryRepository and database is Closed
}
When we want to access Set of Cities from country object then we will get null values in that Set because object of Set created only this Set is not initialize with there data to get values of Set we use #Transactional i.e.,
//with #Transactional
#Transactional
public Country getCountry(){
Country country = countryRepository.getCountry();
//below when we initialize cities using object country so that directly communicate with database and retrieve all cities from database this happens just because of #Transactinal
Object object = country.getCities().size();
}
So basically #Transactional is Service can make multiple call in single transaction without closing connection with end point.
Hope this will helpful to you.
I've a misunderstanding of Spring #Transactional annotation and persist. I am using Spring 3.1, with JPA and Hibernate. I thought that persist meant, add the entity to the persistence context (but don't execute any query until commit or flush), and that the #Transactional annotation meant, wrap the method with a transaction.
However, in this short example, when the execution pointer reaches persist, it fails with an exception, since name can't be null (db constraint).
import javax.persistence.EntityManager;
#PersistenceContext
private EntityManager entityManager;
#Transactional
public void test() {
Brand brand = new Brand();
entityManager.persist(brand);
brand.setName("test");
}
If I swap setName() and persist(), everything works. However, I don't understand why the other way around doesn't since I thought that any query would be built and executed at the end of the method.
Can someone please explain?
In JPA, once an object passed to persist() it becomes "managed", as part of becoming managed JPA implementation must generate an id for the persistent object.
If id generation is based on auto-increment (GenerationType.IDENTITY), then an insert statement needs to be issued to the db to get and assign the key. When the id generation is based on sequence / table then ids are managed and assigne by the JPA Implementation managed id pools, in which case a straight insert is not a requirement.
Having an object is passed to persist() and has become managed, any changes to it is persistent fields must be flushed to the database at the and of the transaction. In your case if the id generation is Identity then an insert must be followed an update. If the id generation is some other method then, a single insert statement is sufficient. If the transaction is rolled back, no SQL should be get sent to database at all.
This is the implementation in Batoo JPA.
Hope this makes sense.
Its committed at end of method thanks to transactional annotation. But the new record is created on persist, and any exceptions can be thrown.
Before the end of method it can still be rolled back; I normally annotate with rollback for exception.
The persist executes the "insert" query. The transacation annotation is just for starting a transaction and if a exception occurs roll back the transaction.