首页 文章

org.hibernate.LazyInitializationException:无法初始化代理 - 没有会话?

提问于
浏览
4

我试图从数据库中的对象做一个简单的加载,但我得到错误“无法初始化代理 - 没有会话”,任何想法?谢谢

org.hibernate.LazyInitializationException: could not initialize proxy - no Session
    org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.jav a:167)
    org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:215)
    org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
    com.myapp.domain.User_$$_javassist_0.getLogin(User_$$_javassist_0.java)
    com.myapp.validator.UserFormValidator.validate(UserFormValidator.java:34)

@Component 
public class UserFormValidator implements Validator {

@Autowired
private UserDAO userDAO;  

@Override
public boolean supports(Class<?> clazz) {
    return UserForm.class.equals(clazz);
}

public UserDAO getUserDAO() {
    return userDAO;
}

public void setUserDAO(UserDAO userDAO) {
    this.userDAO = userDAO;
}

@Override
public void validate(Object target, Errors errors) {
    User user = (User)getUserDAO().findById(new Integer(1));
    System.out.println ("User -> " + user.getLogin());
}
}

@Transactional
public class GenericDAOHibernateImpl <T, PK extends Serializable>
implements GenericDAO<T, PK> {

public GenericDAOHibernateImpl() {
    super();
}

private Class<T> type;

@Resource(name = "sessionFactory")
private SessionFactory sessionFactory;

public GenericDAOHibernateImpl(Class<T> type) {
    this.type = type;
}

public void saveOrUpdate(T object) {
    getSession().save(object);
}

public Object findById(Serializable id) {
     return getSession().load(type, id);
}

protected Session getSession() {
    return sessionFactory.getCurrentSession();
}
}

<?xml version="1.0" encoding="UTF-8"?>
<beans  xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p" 
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/tx 
        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd
        ">

<context:property-placeholder location="/WEB-INF/jdbc.properties" />

<!-- Enable annotation style of managing transactions -->
<tx:annotation-driven transaction-manager="transactionManager" />   

<!-- Declare the Hibernate SessionFactory for retrieving Hibernate sessions -->
<!-- See http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/orm/hibernate3/annotation/AnnotationSessionFactoryBean.html -->                           
<!-- See http://docs.jboss.org/hibernate/stable/core/api/index.html?org/hibernate/SessionFactory.html -->
<!-- See http://docs.jboss.org/hibernate/stable/core/api/index.html?org/hibernate/Session.html -->

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"
             p:dataSource-ref="dataSource"
             p:configLocation="classpath:hibernate.cfg.xml"
             p:packagesToScan="com.myapp.domain"/>  

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" 
destroy-method="close" 
p:driverClass="${jdbc.driverClassName}" 
p:jdbcUrl="${jdbc.url}"
p:user="${jdbc.username}"
p:password="${jdbc.password}"
p:acquireIncrement="5"
            p:idleConnectionTestPeriod="60"
            p:maxPoolSize="100"
            p:maxStatements="50"
            p:minPoolSize="10" 
/>


<!-- Declare a transaction manager-->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" 
            p:sessionFactory-ref="sessionFactory" />

@Entity
@Table(name="USER")
public class User extends appEntity {

@Id
@Column(name = "USER_ID", unique = true, nullable = false)
private Integer id;
@Column(name = "LOGIN")
private String login;
@Column(name = "PASSWORD")
private String password;


public String getLogin() {
    return login;
}
public void setLogin(String login) {
    this.login = login;
}

public Integer getId() {
    return id;
}
public void setId(Integer id) {
    this.id = id;
}
public String getPassword() {
    return password;
}
public void setPassword(String password) {
    this.password = password;
}

1 回答

  • 14

    尝试将 @Transactional 添加到validate方法:

    @Override
    @Transactional(readOnly=true)
    public void validate(Object target, Errors errors) {
        ...
    }
    

    会发生的是因为没有 @Transactional 注释,所以没有与该方法关联的会话,并且每个查询将在其自己的会话中运行,该会话之后立即关闭 .

    方法 session.load() 总是返回一个代理,与 session.get() 不同(请参阅此处了解differences between load vs get) .

    因此返回代理,但由于缺少 @Transactional ,创建代理的会话立即关闭 . 当第一次访问代理时,它's session is closed so we get the '没有会话'错误 .

    如果从 load() 更改为 get() 只会部分解决问题,因为如果在尝试加载后尝试加载例如延迟初始化集合,则会再次发生异常 .

    @Transactional 添加到业务方法将确保在方法调用期间存在相同的会话,并防止出现此错误和其他相关错误 .

相关问题