130 likes | 371 Views
J2EE —— 第 30 章 事务. 什么是事务. 原子性、一致性、不可中断、持久性 容器管理事务:企业 bean 方法和事务关联 事务属性 Required RequiresNew Mandatory NotSupported Supports Never. 设置事务属性. 部署描述符中 方法属性优先, bean 属性其次 会话 bean :业务方法 实体 bean :业务方法, create, remove, find 方法 消息驱动 bean : onMessage 方法. 回滚容器管理事务. 系统异常:自动回滚
E N D
什么是事务 • 原子性、一致性、不可中断、持久性 • 容器管理事务:企业bean方法和事务关联 • 事务属性 • Required • RequiresNew • Mandatory • NotSupported • Supports • Never
设置事务属性 • 部署描述符中 • 方法属性优先,bean属性其次 • 会话bean:业务方法 • 实体bean:业务方法,create, remove, find方法 • 消息驱动bean:onMessage方法
回滚容器管理事务 • 系统异常:自动回滚 • 程序异常:手动回滚context.setRollBackOnly() public void transferToSaving(double amount) throws InsufficientBalanceException { checkingBalance -= amount; savingBalance += amount; try { updateChecking(checkingBalance); if (checkingBalance < 0.00) { context.setRollbackOnly(); throw new InsufficientBalanceException(); } updateSaving(savingBalance); } catch (SQLException ex) { throw new EJBException ("Transaction failed due to SQLException: " + ex.getMessage()); } }
同步会话bean的实例变量 • 回滚时会撤销数据中的修改 • 回滚时会撤销对实体bean的实例变量修改 • 回滚时不会自动撤销对会话bean的实例变量修改,需要实现SessionSynchronization接口显式重置实例变量 • afterBegin:可以加载实例变量 • beforeCompletion:可以回滚 • afterCompletion:可以重置实例变量
同步会话bean的实例变量示例 public void afterBegin() { try { checkingBalance = selectChecking(); savingBalance = selectSaving(); } catch (SQLException ex) { throw new EJBException("afterBegin Exception: " + ex.getMessage()); } } public void afterCompletion(boolean committed) { if (committed == false) { try { checkingBalance = selectChecking(); savingBalance = selectSaving(); } catch (SQLException ex) { throw new EJBException( "afterCompletion SQLException: " + ex.getMessage()); } } }
练习 • 探索JBoss中设置事务属性的方法 • 容器管理的事务中禁止的方法 • java.sql.Connection的commit, setAutoCommit和rollback方法 • java.ejb.EJBContext的getUserTransaction • javax.transaction.UserTransaction的方法 • bean管理的事务:只能是会话bean或消息驱动bean,不能是实体bean
JDBC事务 public void ship (String productId, String orderId, int quantity) { try { makeConnection(); con.setAutoCommit(false); updateOrderItem(productId, orderId); updateInventory(productId, quantity); con.commit(); } catch (Exception ex) { try { con.rollback(); throw new EJBException("Transaction failed: " + ex.getMessage()); } catch (SQLException sqx) { throw new EJBException("Rollback failed: " + sqx.getMessage()); } } finally { releaseConnection(); } } • 从上一个commit,rollback,或connect后第一个SQL语句开始事务
JTA事务 public void withdrawCash(double amount) { UserTransaction ut = context.getUserTransaction(); try { ut.begin(); updateChecking(amount); machineBalance -= amount; insertMachine(machineBalance); ut.commit(); } catch (Exception ex) { try { ut.rollback(); } catch (SystemException syex) { throw new EJBException ("Rollback failed: " + syex.getMessage()); } throw new EJBException ("Transaction failed: " + ex.getMessage()); } } • 可以同时修改异构的多个数据库 • 不支持事务嵌套
没有提交就返回 • bean管理事务的无状态会话bean,一个业务方法必须提交或者回滚事务 • bean管理事务的有状态会话bean,一个业务方法可以没有提交或回滚事务 • JTA事务,保持bean实例与事务的联系 • JDBC事务,如果数据库连接关闭,则不再保持bean实例与事务的联系 • bean管理事务中禁止调用:getRollbackOnly和setRollBackOnly方法
事务超时 • 容器管理事务 • domain.xml中:timeout-in-seconds=0 (5) • bean管理事务 • setTransactionTimeout方法 • 隔离级别 • 缺省:TRANSACTION_READ_COMMITED • 可修改:con.setTransactionIsolation(TRANSACTION_READ_UNCOMMITTED)