今天,将hibernate和spring结合使用,用单元测试调用一个保存方法,hibernate的插入sql打印出来了,单元测试也显示绿色条,成功了,可查询表时,表里就是没数据,原以为是数据没有提交,只是插入了,所以将mysql的隔离级别设置成未提交读取,可是数据还是没有出来,郁闷中,请教了一位大师,他说,如果在spring中不配置事务,spring中默认是回滚状态,难怪我数据一直查询不出来,后来将spring中事务配置上去,如下:
<!-- 配置事务的传播特性 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="add*" propagation="REQUIRED"/> <tx:method name="del*" propagation="REQUIRED"/> <tx:method name="modify*" propagation="REQUIRED"/> <tx:method name="*" read-only="true"/> </tx:attributes> </tx:advice> <!-- 那些类的哪些方法参与事务 --> <aop:config> <aop:pointcut id="allManagerMethod" expression="execution(* com.bjsxt.hibernate.UserManager.*(..))"/> <aop:advisor pointcut-ref="allManagerMethod" advice-ref="txAdvice"/> </aop:config>
配置之后,又出现了一个问题,类转换错误,代码是这样的:
protected void setUp() throws Exception {
BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext-*.xml");
userManager = (UserManager)factory.getBean("userManager");
}
报错原因是说$Proxy1 不能转换成UserManager类,为什么呢?
事先说明一下,我这个测试和以往的项目不同,以前用spring bean的时候,都是先写一个接口,然后写一个类来实现这个接口,而我,为了偷懒,没有写接口,直接写的是一个类,实现了HibernateDaoSupport 类。
问题就出在没写接口上,听大师讲,原因是因为spring中有两种代理,一种是jdk的动态代理,一种是用cglib 代理,。。。。。。。。。,由于我的类继承的是hibernateDaoSupport,所以生成的代理类,是HibernateDaoSupport的子类,而我的类,也是。。。的子类,所以两个类不能转换,怎么办呢?
事情总会有解决方法的。
在配置文件中配置了一项:
<!-- 那些类的哪些方法参与事务 --> <aop:config proxy-target-class="true"> <aop:pointcut id="allManagerMethod" expression="execution(* com.bjsxt.hibernate.UserManager.*(..))"/> <aop:advisor pointcut-ref="allManagerMethod" advice-ref="txAdvice"/> </aop:config>
多配置了一项这个内容,意思是生成代理类的时候,直接在现有类上生成子类,这样就没有问题了。
修改了这么多,测试了一下,终于,问题解决了,数据有了,呵呵。
摘自spring framework 6.6章 代理部分的内容:
Spring AOP部分使用JDK动态代理或者CGLIB来为目标对象创建代理。(建议尽量使用JDK的动态代理)
如果被代理的目标对象实现了至少一个接口,则会使用JDK动态代理。所有该目标类型实现的接口都将被代理。若该目标对象没有实现任何接口,则创建一个CGLIB代理。
如果你希望强制使用CGLIB代理,(例如:希望代理目标对象的所有方法,而不只是实现自接口的方法)那也可以。但是需要考虑以下问题:
-
无法通知(advise)
Final
方法,因为他们不能被覆写。 -
你需要将CGLIB 2二进制发行包放在classpath下面,与之相较JDK本身就提供了动态代理
强制使用CGLIB代理需要将 <aop:config>
的 proxy-target-class
属性设为true:
<aop:config proxy-target-class="true">
...
</aop:config>
当需要使用CGLIB代理和@AspectJ自动代理支持,请按照如下的方式设置 <aop:aspectj-autoproxy>
的 proxy-target-class
属性:
<aop:aspectj-autoproxy proxy-target-class="true"/>