论坛首页 入门技术论坛

泛型DAO和Spring的事务配置问题

浏览 2335 次
该帖已经被评为新手帖
作者 正文
   发表时间:2008-01-31  
注意:此贴已被论坛评为新手贴,没有参考价值,我留在这里来记录一下自己的思路而已
坛子里有一篇主题差不多的文章,但是我要说的不是他那个。不知道是我理解错误还是其他什么原因,整整一天时间不断的测试,找资料,总觉得Spring对于范型接口的事务配置有问题。
public interface GenericDAO<T, ID extends Serializable> {
	/**
	 * A common method for load a instance with Id specified
	 * @param id
	 * @return
	 */
	public T findById(ID id);
	/**
	 * Get a entity by the ID
	 * @param id
	 * @param lock
	 * @return
	 */
    public T findById(ID id, boolean lock);

    /**
     * Get all the entities
     * @return
     */
    public List<T> findAll();
    /**
     * Get all the entities page by page
     * @param index
     * @param offset
     * @return
     */
    public List<T> findAllByPage(int index, int offset);
    /**
     * Get a list of entities by example
     * @param exampleInstance
     * @return
     */
    public List<T> findByExample(T exampleInstance);
    /**
     * Make the entity persistent
     * @param entity
     * @return
     */
    public boolean save(T entity);
    /**
     * Delete an entity
     * @param entity
     * @return
     */
    public boolean delete(T entity);
    /**
     * Update an entity
     * @param entity
     * @return
     */
    public boolean update(T entity);
    
}

上面是范型接口的定义
有一个GenericHibernateDAO实现了上面的接口,提供了类型安全的基本的CRUD操作
现在有一个具体的DAO操作,比如User
那么可以这样来做
public interface UserDAO extends GenericDAO<User, Integer>
//other method signature


public class UserDAOImpl extends GenericHibernateDAO<User, Integer> implements UserDAO
//implementation for other method except basic CRUD operations

现在UserDAOImpl即使不写一行代码,那么也具备了基本的CURD能力,工程是使用了webwork框架,并且使用了Spring的
OpenSessionInViewFilter,那么对于update,save之类得方法,必须要配置事务管理,才可以正常工作。
那么我写下下面的Spring配置
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
	<property name="sessionFactory" ref="sessionFactory"/>
</bean>

<tx:advice id="txAdvice" transaction-manager="txManager">
  <tx:attributes>
   <tx:method name="save*" propagation="REQUIRED" />
   <tx:method name="update*" propagation="REQUIRED"/>
   <tx:method name="delete*" propagation="REQUIRED"/>
   <tx:method name="find*" read-only="true"/>
   <tx:method name="get*" read-only="true" />
   <tx:method name="*"/>

  </tx:attributes>
</tx:advice>

<aop:config>
  <aop:pointcut id="daoOperation" expression="execution(* x.y.z.dao.UserDAO.*(..))"/>
  <aop:advisor advice-ref="txAdvice" pointcut-ref="daoOperation"/>
</aop:config>

奇怪的问题出现了,通过GenericDAO继承过来的方法签名对于事务管理都无效。
报错信息为:
org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.NEVER/MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.
而额外的新增的方法居然是正常工作的,我原来怀疑是不是不支持接口继承啊,于是专门做了一下测试,把UserDAO额外的方法签名全部放到UserService接口中,那么类型结构就成了这个样子:
UserService extends GenericDAO<User, Integer>
//method signature here

UserDAO extends UserService
这样居然测试之后的结果居然是除GenericDAO额外的方法签名都是可以正常受事务管理器管理的,那就证明对于父接口的aop不成问题;那么结论是什么呢?难道是范型接口中的方法支持有问题?

请哪位兄弟解答一下,或者哪位兄弟有类似疑问的也请回帖。我是百思不得其解了。
--------------
2.1日更新:
今天又测试了一下,发现自己的猜想是片面的,只是一种特殊情况下的错误理解;其实对于范型的接口继承,Spring是没有问题的,却发现了一个更奇怪的问题:必须要在DepartmentDAOImpl中重载接口中的方法,Spring的声明式事务才会有效果。或者父接口不能为范型。
也就是说,要么这样重载:
public boolean save(User user) {
    return super.save(user);
}

要么就完全的实现另外一个接口,这样其实也就保证了具体业务的类中实际有方法实现,而不是从范型父类中继承的方法。
需要说明的是,对于这个问题,很多人的设计是不会出的,因为他们会进行更高层次的抽象,也就是说这个范型DAO之上还有一个业务层,这里通常是一些*Service或者*Manager方法,而通常的事务配置应该在业务层上配置.这样的我试过,是完全正常的,不过这无非也就是避免了在范型接口的方法上配置事务.不过无疑这样的设计是很好的,也应该使用,比如新增一个用户,先要查看该用户是否之前存在,然后才是真正的写入到数据库的操作,这两个DAO操作组成了addUser这一个"业务逻辑".可是,我的设计中,却偏不愿意这么干,我不想为了一些简单的操作,再多建2n个类和接口.而按照DAO层之上再加业务逻辑层的设计方法,却是对于一个需要持久化的实体会有4n个类或者是接口.我换了一种策略,我不再想着在DAO上做事务配置的文章,而是在webwork的action的增加需要事务的方法,在Spring配置中对这些具有固定前缀的方法配置事务,这样和webwork中把表单参数集中到Action的方法有点类似,想当初我烦Struts就是因为没一个表单,不管多简单,都要一个ActionForm,要么就从request对象里面取.对于我的这个小软件系统,很多操作并不复杂,基本就是一个Action一个DAO操作,涉及到多个DAO连用的也就那么几个Action,我大可以在Action中来写这些.并且由于webwork是采用Spring作为ObjectFactory的,所以Action本来就在Spring的object池中了,那么也就省去了,再到Spring配置文件中配置n个server或者Manager的类.而且说到数据库迁移和测试的能力,在DAO层上的抽象,对于我的项目,我觉得也足够了。
也许不是Spring达不到我的要求,但是好看完Spring的文档之后,也试验了好久,还是找不到原因,就是找不到针对DAO的范型接口中定义的方法做声明式事务的方法.有时间要好好看看Spring的源码,看看它AOP这一块到底到底是怎么搞的,来解除我的疑惑.
---------------------
2008年3月18日更新:
问题解决:原因,没有给范型接口配置声明式事务。
看了SpringSide2.0的源码,才知道如果DAO继承自范型接口,那么还要给范型DAO配置声明式事务,而不是像我之前设想的那样,继承自范型接口的操作将会在给子类配置时自动被配置了。不过需要注意的是进行声明式事务配置时,需要指定proxy-target-class="true"来使用Cglib来进行代码增强,而不能使用默认的java动态代理。
论坛首页 入门技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics