ruslan platonov - transactions
TRANSCRIPT
Slide 1
Transaction Management Patterns
Ruslan PlatonovLead Java Developer at C.T.Co
Definition of Transaction
Transaction = Logical unit of work
Provides ACID
Atomicity
Consistency
Isolation
Durability
Typical Issues
Lack of knowledge in the area
Not clear understanding (knowledge) of transaction management strategy on application level
DB team should care about transactions
All these things results inanti patterns insideour projects
Ex 1: Auto-commit
hibernate.connection.autocommit = true
hibernate.connection.release_mode = after_statement
Ex 2: Programmatic Control
Connection connection = null;Statement statement = null;try { Class.forName("driverClass"); connection = DriverManager.getConnection("url", "user", "pass"); connection.setAutoCommit(false); statement = connection.createStatement();
// Execute queries statement.executeUpdate("UPDATE Table1 SET Value = 1 WHERE Name = 'foo'"); statement.executeUpdate("UPDATE Table2 SET Value = 2 WHERE Name = 'bar'");
connection.commit();
} catch (SQLException ex) { if (null != connection) { connection.rollback(); }} finally { if (null != statement) { statement.close(); } if (null != connection) { connection.close(); }}
Ex 3: Incorrect Demarcation
@Repositorypublic class UserRepository {
@Transactional public void save(User user) { ... }
}
@Componentpublic class UserService { @Autowired private UserRepository repo;
public void disableUsers( List usersList) { for(User user : usersList) { repo.save(user); } }}
Ex 4: Batch processing
@Componentpublic class LongRunningJob {
@Autowiredprivate RecordRepository repository;
@Transactional public void updateRecords() { for(int i = 1; i < 100000; i++) { Record rec = repository.getById(i); repository.updateTimeStamp(rec, new Date()); } }}
Consequences
Data Inconsistency
Performance Issues
High load on DB
How can we improveour code?
Some Ideas
Use declarative definition
Add transparency
Decouple from application logic, make flexible
Simplify maintenance
Transaction Models
Transaction Models
Local
Programmatic
Declarative
Local Transaction Model
Transactions are handled by DB
Developer manage connections not transaction
Local Transaction Model Example
Local Transaction Model Considerations
Not recommended
Suitable for simple cases
Plenty of room for errors
Cannot maintain ACID when coordinating multiple resources (DB, JMS)
Programmatic Transaction Model
Developer manages transactions not connections
Developer is responsible for starting and terminating transactions
Programmatic Transaction Model Example
Programmatic Transaction Model with Decorator
public class AccountServiceDecorator implements AccountService {private AccountService service;public AccountServiceDecorator(AccountService service) {...}public boolean transfer(Amount amount, Account debetAcc, Account creditAcc { boolean transferred = false; try { startTransaction(); transferred = service.transfer(amount, debetAcc, creditAcc); commit(); } catch (RuntimeException e) { rollback(); throw e; } return transferred;}}
Programmatic Transaction Model Considerations
Not recommended
Typical scenarios
Client-initiated transactions
Localized JTA transactions
Long running transactions (span multiple request)
Manual handling of rollback (pay attention to exceptions)
Declarative Transaction Model
The most recommended model
No Java code for transaction management
Developer only tells the container how to manage transactions
Declarative Transaction Model with ASPECT (1)
public class AccountServiceImpl implements AccountService { @Transactional public boolean transferAmount(final Amount amount, final Account debetAcc, final Account creditAcc) { ..... }}
Declarative Transaction Model with ASPECT (2)
@Aspectpublic class TransactionAspect { private TransactionService transactionService = new TransactionServiceNull();
@Pointcut("execution(@org.spring...Transactional * *(..))") public void transactionalMethod() {} public void setTransactionService(final TransactionService transactionService) { this.transactionService = transactionService; } .... to be continued ....
Declarative Transaction Model with ASPECT (3)
... continued ... @Before("transactionalMethod()") public void beforeTransactionalMethod(JoinPoint joinPoint) { transactionService.beginTransaction(); } @AfterReturning("transactionalMethod()") public void afterTransactionalMethod(JoinPoint joinPoint) { transactionService.commit(); } @AfterThrowing(pointcut = "transactionalMethod()", throwing = "e") public void afterThrowingFromTransactionalMethod(JoinPoint joinPoint, RuntimeException e) { transactionService.rollback(); }}
Declarative Transaction Model
with Spring Annotations
@Componentpublic class UsersService { @Transactional(propagation = Propagation.REQUIRED) public void modifyUser(User user) { ... }}
Declarative Transaction Model
with Spring XML Configuration
Transaction Propagation Attribute
Required create new or reuse
Mandatory reuse but never starts new
RequiresNew always starts new
Supports not require, but uses if present
NotSupported suspends TX if present
Never cannot be invoked with TX (throws exception)
Transaction Design Patterns
Transaction Design Patterns
Open Session in View
Client Owner
Domain Service Owner
Server Delegate Owner
PresentationApplicationDomainExternal SystemRequest
Open Session in View Pattern
Transactions are demarcated on request level
Whole request is responsible for transaction management
Open Session in View Pattern
Spring Example
oemInViewFilter org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter entityManagerFactoryBeanName reportsEntityManagerFactory
oemInViewFilter *.jsp
Open Session in View Pattern Considerations
Simple to implement and maintain
Single entry point for configuration
May lead to performance issues when mapped to any request
Not suitable for complex applications
Has no control over transaction propagation
Doesn't support long transactions
Client Owner Pattern
Client (presentation) layer is responsible for transaction management
@Component@Scope(BeanDefinition.SCOPE_PROTOTYPE)public class MainScreenController {
@Transactional public void load() { // 1-N Calls to application }
}
Client Owner Pattern Considerations
More flexible control
Most suitable for fine-grained application services
Application and underlying layers should never take control over transactions
Most suitable for cases when application layer architecture can't be changed
Domain Service Owner Pattern
Services layer is responsible for transaction handling
@Component@Scope(BeanDefinition.SCOPE_PROTOTYPE)Public class MainScreenController { private MainScreenApplicationService service; public void load() { service.load(); }}@Componentpublic class MainScreenApplicationService {
@Transactional public void load() { ... }}
Domain Service Owner Pattern Considerations
Client always makes a single request to application layer
Services are course-grained (Facades)
Domain and persistence layers should never take control over transactions
Client doesn't contain any transaction logic
Server Delegate Owner Pattern
A subtype of Command Pattern
External system / services facades own the transaction
Server Delegate Owner Pattern Example
@Component@Transactionalpublic class UpdateRateCommand { private CurrencyRateSystem crs; private RateData data;
public UpdateRateCommand(RateData data) { this.data = data; }
public void execute() { Currency currFrom = data.getFrom(); Currency currTo = data.getTo(); Rate rate = crs.rate(currFrom, currTo, new Date()); data.setRate(rate); }}
Server Delegate Owner Pattern Considerations
Transactions are encapsulated
Transactions are not managed by presentation and services layers
There is even more to learn
EJB Transaction management patterns and implementation
Java Transaction Service (JTS) and Java Transaction API (JTA)
XA Transaction processing
Transaction management in JMS
Long running transactions
and more
Summary
Try to use Declarative patterns only
Define transaction boundaries correctly
Use appropriate patterns to:
Improve performance
Clearly define transaction management strategy
Make code easy to understand, implement and maintain
Minimize amount of bugs
Thank you!
Questions?
References
http://www.infoq.com/minibooks/JTDS
http://blog.smartkey.co.uk/2010/03/open-session-in-view-pattern-spring-jpa/