Added documentation about control abstractions for transaction handling.
This commit is contained in:
parent
0799a5b5e9
commit
84c1d34028
@ -198,11 +198,21 @@ Transaction demarcation with the Doctrine DBAL looks as follows:
|
||||
try{
|
||||
// do stuff
|
||||
$conn->commit();
|
||||
} catch(\Exception $e) {
|
||||
} catch(Exception $e) {
|
||||
$conn->rollback();
|
||||
//handle or rethrow
|
||||
throw $e;
|
||||
}
|
||||
|
||||
Alternatively, the control abstraction `Connection#transactional($func)` can be used to make
|
||||
the code more concise and to make sure you never forget to rollback the transaction in the case
|
||||
of an exception. The following code snippet is functionally equivalent to the previous one:
|
||||
|
||||
[php]
|
||||
$conn->transactional(function($conn) {
|
||||
// do stuff
|
||||
});
|
||||
|
||||
|
||||
The `Doctrine\DBAL\Connection` also has methods control the transaction isolation level as supported by the underlying database.
|
||||
`Connection#setTransactionIsolation($level)` and Connection#getTransactionIsolation() can be used for that purpose.
|
||||
The possible isolation levels are represented by the following constants:
|
||||
|
@ -51,15 +51,35 @@ Explicit transaction demarcation is required when you want to include custom DBA
|
||||
or when you want to make use of some methods of the `EntityManager` API that require an active transaction.
|
||||
Such methods will throw a `TransactionRequiredException` to inform you of that requirement.
|
||||
|
||||
A more convenient alternative for explicit transaction demarcation is the use of provided control
|
||||
abstractions in the form of `Connection#transactional($func)` and `EntityManager#transactional($func)`.
|
||||
When used, these control abstractions ensure that you never forget to rollback the transaction or
|
||||
close the `EntityManager`, apart from the obvious code reduction. An example that is functionally
|
||||
equivalent to the previously shown code looks as follows:
|
||||
|
||||
++ Exception Handling
|
||||
[php]
|
||||
// $em instanceof EntityManager
|
||||
$em->transactional(function($em) {
|
||||
//... do some work
|
||||
$user = new User;
|
||||
$user->setName('George');
|
||||
$em->persist($user);
|
||||
});
|
||||
|
||||
The difference between `Connection#transactional($func)` and `EntityManager#transactional($func)` is
|
||||
that the latter abstraction flushes the `EntityManager` prior to transaction commit and also closes
|
||||
the `EntityManager` properly when an exception occurs (in addition to rolling back the transaction).
|
||||
|
||||
|
||||
+++ Exception Handling
|
||||
|
||||
When using implicit transaction demarcation and an exception occurs during `EntityManager#flush()`, the transaction
|
||||
is automatically rolled back and the `EntityManager` closed.
|
||||
|
||||
When using explicit transaction demarcation and an exception occurs, the transaction should be rolled back immediately
|
||||
and the `EntityManager` closed by invoking `EntityManager#close()` and subsequently discarded, as demonstrated in
|
||||
the example above. Note that when catching `Exception` you should generally rethrow the exception. If you intend to
|
||||
the example above. This can be handled elegantly by the control abstractions shown earlier.
|
||||
Note that when catching `Exception` you should generally rethrow the exception. If you intend to
|
||||
recover from some exceptions, catch them explicitly in earlier catch blocks (but do not forget to rollback the
|
||||
transaction and close the `EntityManager` there as well). All other best practices of exception handling apply
|
||||
similarly (i.e. either log or rethrow, not both, etc.).
|
||||
|
Loading…
Reference in New Issue
Block a user