22 Temmuz 2020 Çarşamba

SpringData @Transactional Anotasyonu

Giriş
Şu satırı dahil ederiz. Transaction Türkçe'ye etkileşim olarak tercüme ediliyor.
import org.springframework.transaction.annotation.Transactional;
Alanlar şöyle


Başlamadan önce
1. Spring içinde ismi transactionManager olan bean olmalıdır. Eğer ismi daha farklı bir bean kullanmak istersek şöyle yaparız.
<bean id="myTransactionManager"
...
</bean>

<tx:annotation-driven transaction-manager="myTransactionManager"/>
2. @EnableTransactionManagement anotasyonu kodda olmalıdır.

3. SpringBoot kullanıyorsak @EntityScan anotasyonu kodda olmalıdır.

Proxy Kodları
Transaction'ın başlamasını sağlayan proxy kodu.
Örnek
Elimizde şöyle bir kod olsun.
@Transactional 
public void method1(){
  //do something
  call method2();
  //do something
  ...
  ...
  failed here
}

@Transactional
public void method2(){
  //do something
  save()
}
Eğer method2'yi inject edilmeyen bir bean ile kendimiz çağırırsak transaction başlamaz. Açıklaması şöyle.
In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual transaction at runtime even if the invoked method is marked with @Transactional. Also, the proxy must be fully initialized to provide the expected behaviour so you should not rely on this feature in your initialization code, i.e. @PostConstruct
Örnek
Elimizde şöyle bir kod olsun. saveCustomer2() REQUIRES_NEW olarak işaretli olmasına rağmen yeni transaction başlatmaz.
@Repository
public class CustomerDAO {  
    @Transactional(value=TxType.REQUIRED)
    public void saveCustomer() {
        // some DB stuff here...
        saveCustomer2();
    }
    @Transactional(value=TxType.REQUIRES_NEW)
    public void saveCustomer2() {
        // more DB stuff here
    }
}
Multi-thread Kodlar
Transaction bir thread içinde başlamalı ve aynı thread içinde bitmelidir. Açıklaması şöyle.
The Spring API works very well with almost all of the transaction management requirements as long as the transaction is on a single thread. The problem arises when we want to manage a transaction across multiple threads. Spring doesn't support transactions over multiple threads out of the box. Spring doesn't explicitly mention that in the documentation, but you will end up with runtime errors or unexpected results if you try to do so.
Persistence Context
@Transactional içinde Persistence Context kullanılır. Açıklaması şöyle.
One of the key points about @Transactional is that there are two separate concepts to consider, each with it's own scope and life cycle:
- the persistence context
- the database transaction
Persitence Context eşittir DB Transaction gibi düşünülüyor ancak öyle değil. Açıklaması şöyle.
The persistence context is just a synchronizer object that tracks the state of a limited set of Java objects and makes sure that changes on those objects are eventually persisted back into the database.

This is a very different notion than the one of a database transaction. One Entity Manager can be used across several database transactions, and it actually often is.
JUnit
Spring test'lerdeki @Transactional olarak işaretli kodları rollback etmek üzere ayarlanmıştır. Açıklaması şöyle.
By default, the framework will create and roll back a transaction for each test.
Açıklaması şöyle.
If you want a transaction to commit - unusual, but occasionally useful when you want a particular test to populate or modify the database - the TestContext framework can be instructed to cause the transaction to commit instead of roll back via the @TransactionConfiguration and @Rollback annotations.
Tanımlama
Sınıf için şöyle yaparız. Bu durumda sınıfın tüm metodları transactional olur.
@Transactional
@Service
public class FooService {
  ...
}
1. isolation Alanı 

DEFAULT Değeri
Şöyle yaparız.
@Transactional(rollbackFor = DataAccessException.class,
               readOnly = false, timeout = 30,
               propagation = Propagation.SUPPORTS,
               isolation = Isolation.DEFAULT)
public void saveFoo(Foo foo) throws DataAccessException {
  ...
}
REPEATABLE_READ Değeri
Açıklaması şöyle
REPEATABLE READ, as the name says, only provides guarantees with respect to existing rows (namely that if a row is found to exist, it won't be altered by other transactions and the read then becomes "repeatable").
Şöyle yaparız.
@Transactional(isolationLevel = REPEATABLE_READ)
void addHuman(int height){
  ...
}
2. label Alanı
Açıklama yaz

3. noRollbackFor Alanı
@Transactional - Rollback yazısına taşıdım.

4. noRollbackForClassName Alanı
Açıklama yaz

5. rollbackFor Alanı
@Transactional - Rollback yazısına taşıdım.

5. rollbackForClassName Alanı
@Transactional - Rollback yazısına taşıdım.


6. propagation Alanı - Mandatory
@Transactional Anotasyonu Propagation Değerleri yazına taşıdım.

7. readOnly Alanı
Örnek
Şöyle yaparız.
@Transactional(readOnly = true)
Örnek
Şöyle yaparız.
@Transactional(readOnly = false, rollbackFor=Exception.class)

8. timeout Alanı
Açıklaması şöyle.
Timeout enables client to control how long the transaction runs before timing out and being rolled back automatically by the underlying transaction infrastructure.
Eğer bir transaction'ın önemliyse bu alanı kullanmak gerekebilir. Açıklaması şöyle.
- One is to stop records being locked for long and unable to serve any other requests.

- Let says you are booking a ticket. On the final submission page, it is talking so long and will your user wait forever? So you set http client time out. But now you have the http client time out, what happens if you don't have transaction time out? You displayed error to user saying it didn't succeed but your transaction takes it time as it does not have any timeout and commits after the your http client has timed out.
9. timeoutString Alanı
Açıklama yaz

10. transactionManager Alanı

Hangi transactionManager bean'inin kullanılacağını beliritr. Normalde bu alanı tanımlamak zorunda değiliz. Tanımlı değilse Spring otomatik olarak transactionManager isimli bean'i kullanır.

transactionManager Tanımlama - jndi DataSource
Şöyle yaparız.
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/MyDataSource"/>
<bean id="transactionManager" 
  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>
transactionManager Tanımlama - JPA
JpaTransactionManager Sınıfı yazısına taşıdım

transactionManager Tanımlama - HibernateTransactionManager
HibernateTransactionManager Sınıfı yazısına taşıdım

transactionManager Tanımlama - DataSourceTransactionManager
Şöyle yaparız.
<bean id="transactionManager"
   class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>
11. value Alanı
transactionManager alanı için alias'tır.

Hiç yorum yok:

Yorum Gönder