事务脚本

事务脚本

使用过程来组织业务逻辑,每个过程处理来自表现层的单个请求。对于很对业务应用来说都可以被看作是一系列事务。业务的一个请求将触发一系列的业务处理逻辑,而我们在代码中通常采用 SpringAOP 声明式事务方式将事务控制在业务层的实现类的方法上面,一个请求对应一套业务流程,对应一个事务控制。前面我们也提到了事物的 4 个特性中,有一个隔离性表示事务与事务间是相互隔离的,互不影响的。

事务脚本将所有这些业务逻辑组织成单个过程,在组织时通常都是考虑的业务逻辑的过程,将业务逻辑按照一定的顺序排列执行,然后将事务控制在某一个主方法的入口上,并且在过程中直接调用数据库,或者调用数据库封装器(如 MyBatis、Hibernate 等 ORM 映射框架)。每个事物都有属于它自己的事物脚本,这里的脚本指的是方法。事务脚本比较适合于业务逻辑相对简单的情况下,理论上来说,事务控制在 3 层架构中任何一层都是可以的,但是我们通常来说,都是控制在业务层的实现上的。事务脚本是属于领域逻辑模式中一种,将其置于与其他处理表现层和数据源层的类相对独立的类中。如果置于数据源层的类中,会失去事务脚本的控制原则,因为可能只控制了一部分业务逻辑,而其他的业务逻辑并没有控制到。

对于事务脚本来说,很多时候都有 3 个具体的类来构成,他们一般分别是 Sevice,Dao,JavaBean, Service 类主要用于组织业务逻辑,Dao 类主要用于实现数据的存储,JavaBean 主要用于数据的封装。事务脚本贵在简单,对于少量逻辑的应用程序来说,它非常实用。如果业务逻辑复杂时,就会导致事务之间的冗余代码。

public void Save(){
     Dao1 dao1=new Dao1(); dao1.IsExists();//检查一些东西
     Dao2 dao1=new Dao2(); dao2.Save();//保存一些数据
}


public void Submit(){
    try{
      BeginTran();
      Dao1 dao1=new Dao1(); dao1.IsExists();//检查一些东西
      Dao2 dao1=new Dao2(); dao2.Save();//保存一些数据
      Dao3 dao3=new Dao3(); dao3.GoToNextFlow();//流程提交
      Commit();
    }catch(){
        Rollback();
    }
}

事务脚本的优势是简单,容易上手,DAO(数据访问对象)的重用可能性高,强于经典的三层。不过与与使用 O/RM 相比,还是需要写 SQL 语句,虽然可以重用数据访问的代码,因为没有领域模型,所以很多业务规则依然没办法重用。经典的三层一旦遇到事务密集的项目,业务层和数据访问层就会黏在一起了,如果对三层进行改良,把事务管理提上来,放在业务层,然后思维模式稍加改变,就变成了事务脚本。

典型应用

这里以银行转账事务脚本实现为例,在事务脚本的实现中,关于在两个账号之间转账的领域业务逻辑都被写在了 MoneyTransferService 的实现里面了,而 Account 仅仅是 getters 和 setters 的数据结构,也就是我们说的贫血模型:

public class MoneyTransferServiceTransactionScriptImpl
      implements MoneyTransferService {
  private AccountDao accountDao;
  private BankingTransactionRepository bankingTransactionRepository;
  . . .
  @Override
  public BankingTransaction transfer(
      String fromAccountId, String toAccountId, double amount) {
    Account fromAccount = accountDao.findById(fromAccountId);
    Account toAccount = accountDao.findById(toAccountId);
    // . . .
    double newBalance = fromAccount.getBalance() - amount;
    switch (fromAccount.getOverdraftPolicy()) {
    case NEVER:
      if (newBalance < 0) {
        throw new DebitException("Insufficient funds");
      }
      break;
    case ALLOWED:
      if (newBalance < -limit) {
        throw new DebitException(
            "Overdraft limit (of " + limit + ") exceeded: " + newBalance);
      }
      break;
    }
    fromAccount.setBalance(newBalance);
    toAccount.setBalance(toAccount.getBalance() + amount);
    BankingTransaction moneyTransferTransaction =
        new MoneyTranferTransaction(fromAccountId, toAccountId, amount);
    bankingTransactionRepository.addTransaction(moneyTransferTransaction);
    return moneyTransferTransaction;
  }
}

这完全是面向过程的代码风格。

上一页