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

[color=red]注意:此贴已被论坛评为新手贴,没有参考价值,我留在这里来记录一下自己的思路而已[/color]
坛子里有一篇主题差不多的文章,但是我要说的不是他那个。不知道是我理解错误还是其他什么原因,整整一天时间不断的测试,找资料,总觉得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日更新:
问题解决:原因,[color=red]没有给范型接口配置声明式事务。[/color]
看了SpringSide2.0的源码,才知道如果DAO继承自范型接口,那么还要给范型DAO配置声明式事务,而不是像我之前设想的那样,继承自范型接口的操作将会在给子类配置时自动被配置了。不过需要注意的是进行声明式事务配置时,需要指定proxy-target-class="true"来使用Cglib来进行代码增强,而不能使用默认的java动态代理。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值