Wstęp
Zarządzanie transakcjami jest możliwe za pomocą adnotacji @Transactonal, @UserTransactional, oraz @SharkTransactional. Adnotacje te możemy używać tylko w klasach zarządzanych przez kontekst aplikacji.
- @Transactional - tworzy transakcję Hibernate
- @SharkTransactional - tworzy transakcję SharkTransaction
- @UserTransactional - tworzy transakcję UserTransaction
Info |
---|
|
Zaleca się stosowanie adnotacji do zarządzania transakcjami w klasach oznaczonych adnotacją @Service |
W klasach, które nie są zarządzane przez kontekst aplikacji możemy wywoływać nasze bloki kodu również wewnątrz jednej transakcji wykorzystując do tego odpowiednie metody wrappujące z klasy TransactionWrapper (od wersji 3.2.76). We wcześniejszych wersjach należy skorzystać bezpośrednio z TransactionTemplate.
Tip |
---|
Należy pamiętać, że wszystkie operacje związane z bazą danych, które wykonujemy w danym zadaniu, powinny odbywać się wewnątrz jednej transakcji. Dzięki temu nasz kod będzie transakcyjny oraz będzie się szybciej wykonywać. |
Przykłady użycia z wykorzystaniem adnotacji
Code Block |
---|
language | java |
---|
title | Wykonanie kilku operacj w jednej transakcji |
---|
|
@Service
public class CustomServiceImpl
implements CustomService
{
@Autowired
private StructureService structureService;
@Transactional
public void addPositionAndOu()
{
Position p = new Position( "name", "symbol" );
OrganizationalUnit ou = new OrganizationalUnit();
ou.setName( "name" );
ou.setSymbol( "symbol" );
structureService.createPosition( p );
structureService.createOrganizationalUnit( ou );
}
public void addPositionAndOuNonTransactional()
{
Position p = new Position( "name", "symbol" );
OrganizationalUnit ou = new OrganizationalUnit();
ou.setName( "name" );
ou.setSymbol( "symbol" );
structureService.createPosition( p );
structureService.createOrganizationalUnit( ou );
}
}
|
W powyższym przykładzie funkcja bez adnotacji @Transactional utworzy osobne transakcje dla każdej funkcji save, natomiast w funkcji oznaczonej @Transactional obie operacje będą działać na jednej tej samej transakcji.
Manualne zarządzanie transakcjami
Jeżeli potrzebujemy wykonać blok kodu wewnątrz aktywnej transakcji hibernate lub sharkowej oraz mieć dostęp do sesji i transakcji, to należy skorzystać z klasy TransactionWrapper.
Code Block |
---|
language | java |
---|
title | Wykonie operacji wewnątrz transakcji hibernate |
---|
|
TransactionWrapper.get().doInHibernateTransaction( ( session ) -> {
QueryExecutor qe = ComponentFactory.getQueryExecutor();
SQLQuery sql = qe.createSQLQuery( ... );
...
sql.executeUpdate();
}); |
Code Block |
---|
language | java |
---|
title | Wykonie operacji wewnątrz transakcji sharkowej |
---|
|
TransactionWrapper.get().doInSharkTransaction( ( sharkTransaction ) -> {
ActivityService activityService = ServiceFactory.getActivityService();
Map<String, Object> activityContext = activityService.getActivityContext( processId, activityId );
activityContext.put( "id_zmiennej", "nowa_wartość" );
activityService.setActivityContext( processId, activityId, activityContext );
}); |
Nasz kod może również zwracać dowolny wynik.
Manualne zarządzanie transakcjami poniżej wersji 3.2.76
Istnieje możliwość manualnego zarządzania transakcjami w przypadkach gdy potrzebujemy większej kontroli lub potrzebujemy ich w obszarze kodu, w którym nie mamy możliwości skorzystania z adnotacji opisanych powyżej.
W tym celu możemy wykorzystać klasę TransactionManagerFactory
Code Block |
---|
language | java |
---|
title | Zarządzanie transakcjami poprzez TransactionTemplate |
---|
|
TransactionTemplate tt = new TransactionTemplate( TransactionManagerFactory.getHibernateTransactionManager() );
tt.execute( new TransactionCallbackWithoutResult()
{
@Override
protected void doInTransactionWithoutResult( TransactionStatus status )
{
QueryExecutor qe = ComponentFactory.getQueryExecutor();
SQLQuery sql = qe.createSQLQuery( ... );
...
sql.executeUpdate();
}
} ); |
Jeżeli potrzebujemy mieć dostęp do obiektu Session od Hibernate, należy TransactionTemplate wykorzysać następująco:
Code Block |
---|
language | java |
---|
title | Zarządzanie transakcjami z dostępem do Session |
---|
|
TransactionTemplate tt = new TransactionTemplate( TransactionManagerFactory.getHibernateTransactionManager() );
tt.execute( new SessionAwareTransactionCallbackWithoutResult()
{
@Override
public void doWithSession( Session session )
{
session.delete( ... );
}
} ); |
Code Block |
---|
language | java |
---|
title | Zarządzanie transakcjami poprzez TransactionTemplate |
---|
|
final SharkTransactionManager mgr= TransactionManagerFactory.getSharkTransactionManager();
TransactionTemplate tt = new TransactionTemplate( mgr );
tt.execute( new TransactionCallbackWithoutResult()
{
@Override
protected void doInTransactionWithoutResult( TransactionStatus status )
{
SharkTransaction sharkTransaction = mgr.getSharkTransaction();
...
}
} ); |
Code Block |
---|
language | java |
---|
title | Manualne zarządzanie transakcjami |
---|
|
SharkTransactionManager= TransactionManagerFactory.getSharkTransactionManager();
TransactionStatus txStatus = null;
try
{
txStatus = mgr.getTransaction( new DefaultTransactionDefinition() );
SharkTransaction sharkTransaction = mgr.getSharkTransaction();
...//wykonywanie operacji na transakcji
mgr.commit( txStatus );
}
catch ( Exception ex )
{
mgr.rollback( txStatus );
} |
SharkTransactionTemplate
Klasa com.suncode.pwfl.transaction.support.SharkTransactionTemplate
ułatwia zarządzanie transakcją Shark'ową w czytelny i bezpieczny sposób.
Tip |
---|
Wszędzie tam, gdzie potrzebujemy transakcję Shark'ową powinniśmy wykorzystywać klasę SharkTransactionTemplate ze względu na łatwiejsze jej użycie. Obsługa kodu transakcyjnego może być skomplikowana i wymaga uważnego traktowania. |
Jeżeli kod wykorzystujący transakcję zwraca wynik, wywołanie będzie wyglądać następująco:
Code Block |
---|
SharkTransactionTemplate tx = new SharkTransactionTemplate();
int result = tx.execute( new SharkTransactionCallback<Integer>()
{
@Override
public Integer doInSharkTransaction( SharkTransaction transaction, TransactionStatus status )
throws Exception
{
// wykorzystanie transakcji
return 1;
}
} ); |
W przypadku, gdy wywołujemy procedurę która nie zwraca żadnego wyniku, możemy skorzystać z innego callback'u SharkTransactionCallbackWithoutResult
:
Code Block |
---|
SharkTransactionTemplate tx = new SharkTransactionTemplate();
tx.execute( new SharkTransactionCallbackWithoutResult()
{
@Override
public void doInSharkTransactionWithoutResult( SharkTransaction transaction, TransactionStatus status )
throws Exception
{
// wykorzystanie transakcji
}
}; |
Info |
---|
Domyślna konfiguracja SharkTransactionTemplate wykorzystuje aktualną transakcję, jeżeli jest dostępna lub otwiera nową. |
Przydatne zasoby: