Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Polish

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
titleDobre 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.

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
languagejava
titleWykonanie 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
languagejava
titleWykonie operacji wewnątrz transakcji hibernate
TransactionWrapper.get().doInHibernateTransaction( ( session ) -> {
    QueryExecutor qe = ComponentFactory.getQueryExecutor();
    SQLQuery sql = qe.createSQLQuery( ... );
    ...
    sql.executeUpdate();
});
Code Block
languagejava
titleWykonie 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

Code Block
languagejava
titleZarzą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
languagejava
titleZarzą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
languagejava
titleZarzą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
languagejava
titleManualne zarządzanie transakcjami
      SharkTransactionManager mgr = 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:

 

 

English

Introduction

Transactions can be managed using the @Transactional, @UserTransactional, and @SharkTransactional annotations. We can use these annotations only in classes managed by the application context.

  • @Transactional - creates a Hibernate transaction
  • @SharkTransactional - creates a SharkTransaction
  • @UserTransactional - creates a UserTransaction
Info
titleBest practices

It is recommended to use annotations to manage transactions in classes marked with @Service annotation

In classes that are not managed by the application context, we can also call our code blocks inside a single transaction using the appropriate wrapper methods from the TransactionWrapper class (from version 3.2.76). In earlier versions, use the TransactionTemplate directly.

Tip

Keep in mind that all the database operations we perform in a task should take place inside a single transaction. This will make our code transactional and faster to execute.


Usage examples using annotations

Code Block
languagejava
titlePerforming several operations in a single transaction
@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 );
    }
}

In the above example, the function without the @Transactional annotation will create separate transactions for each save function, while in the function marked @Transactional, both operations will run on the same transaction.

Manual transaction management

If you need to execute a block of code inside an active hibernate or shark transaction and have access to sessions and transactions, then you should use the TransactionWrapper class.

Code Block
languagejava
titlePerform operations inside hibernate transactions
TransactionWrapper.get().doInHibernateTransaction( ( session ) -> {
    QueryExecutor qe = ComponentFactory.getQueryExecutor();
    SQLQuery sql = qe.createSQLQuery( ... );
    ...
    sql.executeUpdate();
});
Code Block
languagejava
titlePerform operations inside a shark transaction
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 );
});

The code can also return any result.

Manual transaction management below version 3.2.76 (from version 3.2.76 onward, use the previous point)

It is possible to manually manage transactions in cases where we need more control or need them in a code area where we cannot use the annotations described above.

For this purpose, you can use the TransactionManagerFactory class.

Code Block
languagejava
titleTransaction management via 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();
            }
        } );

 

If you need to access the Session object from Hibernate, you should use TransactionTemplate as follows:

 

Code Block
languagejava
titleTransaction management with access to Session
        
		TransactionTemplate tt = new TransactionTemplate( TransactionManagerFactory.getHibernateTransactionManager() );
        tt.execute( new SessionAwareTransactionCallbackWithoutResult()
        {
            @Override
            public void doWithSession( Session session )
            {
                session.delete( ... );
            }
        } );
Code Block
languagejava
titleTransaction management via 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
languagejava
titleManual transaction management
      SharkTransactionManager mgr = TransactionManagerFactory.getSharkTransactionManager();
      TransactionStatus txStatus = null;
      try
      {
            txStatus = mgr.getTransaction( new DefaultTransactionDefinition() );
            SharkTransaction sharkTransaction = mgr.getSharkTransaction();
            ...//performing operations on a transaction
            mgr.commit( txStatus  );
      }
	  catch ( Exception ex )
      { 
		    mgr.rollback( txStatus );
	  }

SharkTransactionTemplate

The com.suncode.pwfl.transaction.support.SharkTransactionTemplate class facilitates Shark transaction management in a readable and secure way.

Tip

Wherever we need a Shark transaction you should use the SharkTransactionTemplate class because of its easier use. Transaction code handling can be complicated and needs to be handled carefully.

 

If the code using the transaction returns a result, the call will look like this:

Code Block
SharkTransactionTemplate tx = new SharkTransactionTemplate();
int result = tx.execute( new SharkTransactionCallback<Integer>()
{
    @Override
    public Integer doInSharkTransaction( SharkTransaction transaction, TransactionStatus status )
        throws Exception
    {
		// use of transactions
        return 1;
    }
} );

In case you call a procedure that does not return any result, you can use another callback SharkTransactionCallbackWithoutResult:

Code Block
SharkTransactionTemplate tx = new SharkTransactionTemplate();
tx.execute( new SharkTransactionCallbackWithoutResult()
{
    
    @Override
    public void doInSharkTransactionWithoutResult( SharkTransaction transaction, TransactionStatus status )
        throws Exception
    {
		// use of transactions
    }
} ); 

Info

The default SharkTransactionTemplate configuration uses the current transaction, if available, or opens a new one.



Useful resources: