`
matt.u
  • 浏览: 127305 次
  • 性别: Icon_minigender_1
  • 来自: CQ
社区版块
存档分类
最新评论

开发和测试业务逻辑问题集

阅读更多
每次在开发和测试业务逻辑biz时老是碰到这样那样似曾相识的问题,现在记一下备忘。
1、使用JPA/Hibernate/Ebean等ORM时来存取数据库时,不另外增加DAO层。理由是ORM已经封装和统一了不同数据库的基础访问、存取操作,不需要重复劳动,除非有特殊需要。

2、事务处理就是在biz层上定义的,推荐使用Spring容器来管理事务。

3、在使用事务注解时要注意@Transactional注解只能使用在public方式上才有效。放在protected/private方法上不会报错。另外只需要在要启动事务的最外层方法上加这个注解,内部方法是不需要的。

4、在对查询数据库操作,应使用只读事务,对数据加共享锁,以避免其他事务修改该数据。同时注意注解应使用这种形式:
@Transactional(propagation=Propagation.REQUIRED, readOnly=true)
使用Propagation.REQUIRED以确保事务的正常启动,如果使用propagation=Propagation.NOT_SUPPORTED则不会启动事务,readOnly属性实际上就失效了。

5、在使用Spring来管理Ebean的事务时,记得要设置<property name="defaultServer" value="true" />。否则死活不会成功。Ebean的Spring例子上好像有错。

6、在使用Spring来管理事务时,有两种生成代理方式。默认是Jdk自带的代理实现。推荐cglib方式,因为这种方式是使用的enhancer代理方式,是在原有XXXBizImpl上产生了一个增强的继承类,所以代理对象可以转换成XXXBizImpl。这样在测试时就更方便。因为我们业务接口方法肯定少于实现的方法。要测试实现上的各个方法,只有用cglib才能注入实现类。Jdk proxy只能注入接口。
要使用cglib除了增加相关依赖包,还要在spring中增加<aop:config proxy-target-class="true" />。
至于两种方式的性能,可参考http://budairenqin.iteye.com/blog/1500366,如果被测的cglib版本比较低。

7、使用unitils来对biz层进行测试,并使用dbunit来初始化测试数据。使用dbunit也会有几个问题:
使用@ExpectedDataSet注解时,会出现org.dbunit.dataset.RowOutOfBoundsException: 1 > (1)异常,但不影响结果,只需要换用新版本的dbunit就行了。出错的版本是dbunit2.2.2。
(2)在配置Spring事务后,本来测试时还正常的dataset测试文件,会报出org.dbunit.dataset.NoSuchColumnException: HIP_PERSON.BASIC_ADDR_ID -  (Non-uppercase input column: BASIC_ADDR_ID) in ColumnNameToIndexes cache map. Note that the map's column names are NOT case sensitive.异常。
出错的原因是第一条测试数据有8个字段,第二条测试数据只有3个,dbnit会用第一条数据的字段去要求第二条数据的,结果就报错了。结果这不是一个bug,可以看这里http://www.dbunit.org/components.html#flatxmlDataSet,
如果要想测试通过,需要把每条记录的字段都弄成一样多,但是这样太麻烦了。unitils也一直未更新解决该问题。结果只有自己重写了MultiSchemaXmlDataSetFactory。另:可自己通过DatabaseUnitils类来生成DataSet的XSD。
(3)需要注意的@ExpectedDataSet注解只验证dataset xml文件中对应的数据。不对数据库所有的数据进行验证。

8、在使用Spring管理事务时,会碰到Service/Biz实现类因调用自身方法而导致事务错误的情况。如下:
Class ABiz{
  @Resource
  private bBiz;
  @Transaciton
  public void add(){}

  public void addAll(){
    this.add(); //这里因为直接调用的this.add(),所以spring代理并不启动事务
    bBiz.xxx(); //这里的事务有效
  }
}

所以,需要在ABiz中注入自身,通过spring代理来调用带事务的业务方法。
代码修改如下:
Class ABiz{
  @Resource
  private bBiz;

  @Resource
  private aBiz;

  @Transaciton
  public void add(){}

  public void addAll(){
    aBiz.add(); //现在,事务注解就生效了
    bBiz.xxx(); //这里的事务有效
  }
}

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics