Java应用通过JTA API声明JTA事务的步骤如下。
(1)在Hibernate配置文件中配置数据源以及JTA平台属性:
hibernate.connection.datasource= java:comp/env/jdbc/SAMPLEDB
hibernate.transaction.coordinator_class=jta
hibernate.transaction.jta.platform=JBossTS
(2)在程序中创建javax.naming.InitialContext对象:
Context context=new InitialContext();
(3)在程序中,通过JTA的javax.transaction.UserTransaction接口来声明JTA事务。
以下程序代码声明了一个分布式的事务。entityManagerFactoryBeijing代表运行在北京的一个数据库存储源,entityManagerFactoryShanghai代表运行在上海的一个数据库存储源。entityManager1和entityManager2会分别操纵这两个存储源中的数据。由于entityManager1和entityManager2所做的数据库操作都位于同一个JTA事务中,因此JTA实现会保证这个JTA事务的原子性。
UserTransaction utx=
(UserTransaction)new InitialContext()
.lookup("java:comp/UserTransaction");
EntityManager entityManager1=null;
EntityManager entityManager2=null;
try{
//声明开始事务
utx.begin();
entityManager1=entityManagerFactoryBeijing
.createEntityManager();
entityManager2=entityManagerFactoryShanghai
.createEntityManager();
//通过entityManager1执行一些更新北京数据库的操作
Account account1=entityManager1
.find(Account.class,Long.valueOf(1));
account1.setBalance(account1.getBalance()-100);
//通过entityManager2执行一些更新上海数据库的操作
Account account2=entityManager2
.find(Account.class,Long.valueOf(2));
account2.setBalance(account2.getBalance()+100);
entityManager1.flush(); //清理EntityManager1缓存
entityManager2.flush(); //清理EntityManager2缓存
//提交事务
utx.commit();
}catch (Exception e) {
if (utx!=null){
try{
//Status接口位于javax.transaction包中,表示事务状态
if ( utx.getStatus() == Status.STATUS_ACTIVE ||
utx.getStatus() == Status.STATUS_MARKED_ROLLBACK) {
utx.rollback();//操作不成功则撤销事务
}
}catch(Exception ex){
log.error("无法撤销事务",ex); //记录日志
}
}
throw new RuntimeException(e); //继续抛出异常
}finally {
try{
entityManager1.close();
entityManager2.close();
}catch(RuntimeException ex){
log.error("无法关闭EntityManager",ex); //记录日志
}
}
以上程序代码演示了一个分布式的转账事务,从位于北京的一个账户中转账100元到上海的一个账户中。JTA实现会保证这个分布式的转账事务的原子性。
默认情况下,通过UserTransaction的commit()方法提交事务时,该方法不会自动清理底层Session的持久化缓存,因此必须在程序中调用EntityManager的flush()方法来手工清理缓存。此外,程序必须在提交事务后手工关闭EntityManager。