内部类中的Hibernate会话

时间:2012-10-18 12:53:43

标签: java spring hibernate annotations inner-classes

我在使用spring session factory在hibernate上获取anonymus内部类的会话时遇到问题。 这是代码:

public class DomainDaoImpl extends BasicDaoImpl<Domain> implements Iterable<Collection<Domain>> {

...

@Override
public Iterator<Collection<Domain>> iterator() {
    return (new Iterator<Collection<Domain>>() {
        private int counter = 0;
        public static final int LIMIT = 100;

        ...

        @Override
        @Transactional(readOnly = true)
        public Collection<Domain> next() {
            final Criteria criteria = getCurrentSession().createCriteria(Domain.class);
            final LinkedHashSet<Domain> result = new LinkedHashSet<Domain>();

            List resultList = null;
            while (!(resultList = criteria.list()).isEmpty()) {
                criteria.setFirstResult((counter++ * LIMIT) + 1);
                criteria.setMaxResults(LIMIT);
                result.addAll(resultList);
            }
            return result;
        }

        ...
    });

问题是 org.hibernate.HibernateException:找不到当前线程的会话 这通常发生在DAO方法不在事务中时。 那么如何让它与内部类一起工作呢?

2 个答案:

答案 0 :(得分:1)

我认为在内部类级定义@Transactional(readOnly = true),spring将无法检测并应用事务方面。所以它肯定不会起作用。

但我认为如果你写下面的东西可能不会100%肯定(我怀疑一旦你调用iterator方法事务已经关闭)

@Override
@Transactional(readOnly = true)
public Iterator<Collection<Domain>> iterator() {
...
}

另一个选项可以让调用者负责iterator()之类的getAllDomain()上的事务或写包装器方法,并将事务应用于该方法。

有效的解决方案(在评论中提到)

  

可能你可以在getCurrentSession()中做一些补丁   来自sessionFactory的getCurrentSession()如果不可用则使用   openSession(),当然你必须在新会话时手动关闭它   打开。

答案 1 :(得分:1)

您可以配置加载时间方面编织

以下是如何操作的基本示例

春季背景

<?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:context="http://www.springframework.org/schema/context"
   xmlns:tx="http://www.springframework.org/schema/tx"
   xmlns:jdbc="http://www.springframework.org/schema/jdbc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd">

    <context:component-scan base-package="org.foo.bar" />
    <context:annotation-config />
    <context:load-time-weaver />

    <tx:annotation-driven mode="aspectj" proxy-target-class="true"/>

    <jdbc:embedded-database id="dataSource">
        <jdbc:script location="classpath:schema.sql"/>
    </jdbc:embedded-database>

    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="annotatedClasses">
            <list>
                <value>org.foo.bar.MyEntity</value>
            </list>
        </property>
    </bean>

    <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

</beans>

实体类

package org.foo.bar;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "ENTITY")
public class MyEntity {

    @Id
    private long id;
    private String name;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder();
        sb.append("MyEntity");
        sb.append("{id=").append(id);
        sb.append(", name='").append(name).append('\'');
        sb.append('}');
        return sb.toString();
    }
}

Dao class

package org.foo.bar;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.Iterator;
import java.util.NoSuchElementException;

@Component
public class MyEntityDao implements Iterable<MyEntity> {

    @Autowired
    private SessionFactory sessionFactory;

    @Override
    public Iterator<MyEntity> iterator() {
        return new Iterator<MyEntity>() {
            private int num = 0;
            private MyEntity item;

            @Override
            @Transactional(readOnly = true)
            public boolean hasNext() {
                item = getEntity();
                return item != null;
            }

            @Override
            @Transactional(readOnly = true)
            public MyEntity next() {
                try {
                    if(item == null) {
                        item = getEntity();
                        if(item == null) {
                            throw new NoSuchElementException();
                        }
                    }
                    return item;
                } finally {
                    item = null;
                }
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException();
            }

            private MyEntity getEntity() {
                final Criteria criteria = getCurrentSession().createCriteria(MyEntity.class);
                criteria.setFirstResult(num++);
                criteria.setMaxResults(1);
                return (MyEntity) criteria.uniqueResult();
            }
        };
    }

    public Session getCurrentSession() {
        return sessionFactory.getCurrentSession();
    }
}

<强> SQL

drop table ENTITY if exists

create table ENTITY (id bigint generated by default as identity (start with 1),  name varchar(255),  primary key (id))

insert into ENTITY (name) values ('Entity1')
insert into ENTITY (name) values ('Entity2')
insert into ENTITY (name) values ('Entity3')

单元测试

package org.foo.bar;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import static org.junit.Assert.assertEquals;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
    "classpath:applicationContext.xml"
})
public class MyEntityDaoTest {

    @Autowired
    private MyEntityDao dao;

    @Test
    public void testDao() throws Exception {
        int count = 0;
        for(MyEntity a : dao) {
            count++;
        }
        assertEquals(3, count);
    }

}

这是我的pom.xml     http://maven.apache.org/xsd/maven-4.0.0.xsd">         4.0.0

    <groupId>org.foo.bar</groupId>
    <artifactId>spring-aspectj-hibernate</artifactId>
    <version>1.0</version>

    <properties>
        <spring.version>3.1.1.RELEASE</spring.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-instrument</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.6.12</version>
        </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>4.1.1.Final</version>
        </dependency>

        <dependency>
            <groupId>org.hsqldb</groupId>
            <artifactId>hsqldb</artifactId>
            <version>1.8.0.10</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
            <scope>test</scope>
        </dependency>

    </dependencies>

</project>

毕竟你必须使用以下参数-javaagent:<PATH-TO>/spring-instrument-{vertion}.jar运行JVM。要防止添加-javaagent参数,您还可以配置aspectj编译时编织。