浏览 2335 次
锁定老帖子 主题:泛型DAO和Spring的事务配置问题
该帖已经被评为新手帖
|
|
---|---|
作者 | 正文 |
发表时间: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动态代理。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |