Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 19 Next »

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

Dobre praktyki

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.

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

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.

Wykonie operacji wewnątrz transakcji hibernate
TransactionWrapper.get().doInHibernateTransaction( ( session ) -> {
    QueryExecutor qe = ComponentFactory.getQueryExecutor();
    SQLQuery sql = qe.createSQLQuery( ... );
    ...
    sql.executeUpdate();
});
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 (od wersji 3.2.76 należy korzystać z wcześniejszego punktu)

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

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:

 

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( ... );
            }
        } );
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();
				...
		    }
        } );


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.

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:

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:

SharkTransactionTemplate tx = new SharkTransactionTemplate();
tx.execute( new SharkTransactionCallbackWithoutResult()
{
    
    @Override
    public void doInSharkTransactionWithoutResult( SharkTransaction transaction, TransactionStatus status )
        throws Exception
    {
		// wykorzystanie transakcji
    }
} ); 

Domyślna konfiguracja SharkTransactionTemplate wykorzystuje aktualną transakcję, jeżeli jest dostępna lub otwiera nową.



Przydatne zasoby:

 

 

  • No labels