Spring @Transactional persist方法不起作用

时间:2011-08-15 05:10:08

标签: java spring

我有一个Spring MVC示例应用程序,它使用UserDaoImpl类将User类型对象保存到数据库。以下是UserDaoImpl代码。

public class UserDaoImpl implements UserDao<User> {

private EntityManagerFactory emf;

@PersistenceContext
private EntityManager em;

@Transactional
public void saveUser(User user){
    em.persist(user);
}

}

我的UserDao界面看起来像这样。

public interface UserDao<User> {
public void saveUser(User user);

}

当我的UserDaoImpl类实现UserDao接口时,发生了奇怪的事情。当试图坚持它时会出现以下错误。

java.lang.ClassCastException: $Proxy71 cannot be cast to org.samith.UserDaoImpl

当我从UserDaoImpl类中删除“implements UserDao”部分时,用户会按预期持久保存到数据库。

此外,我尝试了没有User参数的UserDao接口(非通用版本)。仍然出现以上错误。

这可能是一个微不足道的问题要回答,但我正在寻找解决方案大约几个小时。

我做错了什么?

2 个答案:

答案 0 :(得分:3)

您没有提供问题代码(或完整的堆栈跟踪),但是这个概述是这样的:

当您将类注释为@Transactional,并且Spring为您创建实例时,您获得的不是该类,而是实现该类接口的Java动态代理。 http://download.oracle.com/javase/1.3/docs/guide/reflection/proxy.html

因此,你不能将该对象强制转换为原始类型(它不再是那种类型!)而必须使用它的接口。

如果没有要实现的接口,它将为您提供该类的CGLib代理,它基本上只是您的类的运行时修改版本,因此可以分配给类本身。

搜索您正在注入或转换为UserDaoImpl类型的位置,并改为改为对UserDao的引用,它将正常工作。

我已经阅读了CGLib代理和动态Java代理之间的性能差异非常小,因此您还可以将以下内容添加到spring配置中以强制它使用CGLib代理而不是Java动态代理:

<aop:config proxy-target-class="true">

一般情况下,我建议您不要使用CGLib Proxies,而是从其界面访问您的类。松散耦合将允许您进行运行时替换,并限制您意外引入脆弱类依赖性的能力。

然而,使用Java动态代理会引入一些问题,而你正在做的事情与我正在做的事情相近,你应该知道这一点:

How to use Dynamic Proxies with JSF when the method signature contains Object ... args

答案 1 :(得分:0)

<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>

也为我工作。由于接受答案的所有者,这一点是proxy-target-class="true"。但是接下来需要cglib依赖。