技术开发 频道

基于Spring的DAO层设计



    查询接口方法的设计

    DAO层类中除了CRUD的数据操作外,另一个重要的操作就是根据条件查询结果。不同的ORM框架都允许你动态绑定参数指定查询条件。查询条件项数目往往是不固定的,如既可能要求以userName为条件查询User,也可能要求以userName+status等组合条件查询User。条件项数目的不定性给查询接口方法的设计造成为一定的困难, 实体DAO定义带参的查询方法时,一般有5种方式,下面分别对这些方式进行介绍。

    方式1:每一个条件项参数对应一个入参
    在查询方法中为每一个用到查询条件项定义一个对应的入参,如:
    List findOrder(String hql,Date startTime,Date endTime,int deptId)
    这种方式的方法签名含义清晰,可读性强,内部的逻辑处理简单,但接口稳定性差。假如这个findOrder()方法需要添加一个userName的条件,有两种重构的方式:第一,调整方法的签名,新增一个String userName入参,这种重构被认为是不健康的重构,因为它违反软件设计中经典的“开-闭原则”,此外如果条件项数目很多,方法签名将显得过于拖沓;第二,在DAO类中新增一个重载查询方法,如果查询条件项的组合数过多,DAO类的方法数目将直线上升,整个实体DAO类将显得臃肿笨重。 
    方式2:使用数组传递条件项参数
    通过数组的方式传递查询条件项参数,由于参数类型的不一致性,要求参数类型采用Object[]:
List findOrder(String hql,Object[] params) 这种方法接口可以应付查询条件项参数组合的多样性并保持接口的稳定性,开发者必须在方法内部从数组中获取参数再传递给查询引擎。缺点是方法的可读性不强,调用者往往需要通过查看接口对应的Javadoc才能正确使用。此外,在JDK 5.0以下的版本中,因为没有自动拆/解包的语言特性,调用前必须对基本类型的参数使用包裹类封装,有时在方法内部还需要进行相反的过程,在使用上较为不便。不过由于Spring为支持的ORM框架都提供了类似的查询接口(如HibernateTemplate#find(String queryString, Object[] values)),所以方法内部的处理相对还是比较简单的。开发者采用如下的方式进行调用:
Object[] params = new Object[]{"112",new Integer(12),new Integer(1)}; list = findOrder(hql,params);
    方式3:使用JDK 5.0的不定参数
    如果在JDK 5.0中,则可以采用不定参数进行方式签名,这种方式在逻辑上和方式2并无多大的区别:
    List findOrder(String hql,Object... params)

    方式4:将查询条件项参数封装成对象

    为了提高方法1中方法签名简洁性,增强方法2、3中方法签名的可读性,方式4提出将查询条件项参数封装成一个对象的思路,查询方法使用查询条件对象传递查询条件:
    List<Order> findOrder(String hql,OrderQueryParam param)
    OrderQueryParam查询条件对象封装了hql查询语句可能会用到的条件项参数,在查询方法内部,开发者必须判断查询条件对象的属性并正确绑定条件项参数。由于需要为条件项参数定义一个类,因此会造成类数目的膨胀,有时甚至一个实体DAO需要对应多个查询条件封装类。另外,当需要添加一个新的条件项参数时,条件封装类还需要进行相应调整。
OrderQueryParam param = new OrderQueryParam(); param.setUserName("zhang"); param.setDeptId(12); param.setStatus()0; list = findOrder(hql,param);
    方式5:使用Map传递条件项参数
    另一种被广泛使用的方法是采用Map传递条件项参数,键为参数名,值为参数值:
    List<Order> findOrder(String hql,Map params)
    这种方式可以在条件项变化,接口方法依然可以保持稳定,同时通过键指定参数名的方式在一定程度上解决了接口的健壮性(当调用者指定错误参数名时容易得到错误报警)。但和方法2、3一样调用者必须通过接口Javadoc才能进行调用。
Map paramMap = new HashMap(); paramMap.put("userName","zhang"); paramMap.put("deptId",12); paramMap.put("status",0); list = findOrder(hql,paramMap);
    小结
    虽然Spring为我们提供了使用各种ORM框架的方便类,但这离实际的应用开发还有一段需要缩短的距离。具体的应用一般会在Spring所提供的支持类基础上提供过一步的封装,建立方便的DAO基类,简化接口方法添加泛型支持等功能。一个设计良好的DAO基类可以大大减少DAO层整体代码的总量,提高项目的开发效率。
0
相关文章