2012-10-18 2 views
5

Ich habe ein Problem mit der Sitzung auf der internen Klasse anonymus im Winterschlaf mit Spring Session Factory. Hier ist der Code:Hibernate-Sitzung innerhalb der inneren Klasse

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; 
     } 

     ... 
    }); 

Die Frage ist org.hibernate.HibernateException: Keine Session gefunden für aktuellen Thread dies in der Regel passiert, wenn DAO-Methode nicht innerhalb der Transaktion ist. Also, wie man es mit einer inneren Klasse arbeiten lässt?

Antwort

1

ich denke, @Transactional(readOnly = true) auf der inneren Klassenebene zu definieren, wird Frühling nicht in der Lage sein, Transaktionsaspekt darüber zu erkennen und anzuwenden. also wird es nicht sicher funktionieren.

, aber ich denke, wenn man so etwas wie unten schreiben könnte nicht 100% sicher arbeiten (ich bezweifle, wenn Sie Iteratormethode Transaktion geschlossen aufrufen)

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

eine weitere Option verantwortlich Anrufer sein für die Transaktion kann lassen oder schreiben Wrapper-Methode über iterator() wie getAllDomain() und Transaktion auf diese Methode anwenden.

Lösung, die gearbeitet (in den Kommentaren erwähnt)

können Sie in getCurrentSession() wie getCurrentSession() von session einige Patch tun können, wenn nicht verfügbar ist, dann Open() verwenden, natürlich haben Sie Schließen Sie es manuell, wenn die neue Sitzung geöffnet wird.

+0

Danke für die Antwort, ich habe es versucht, bevor Sie ohne Erfolg gefragt. Und ich möchte nicht, dass der Aufrufer für die Transaktionsverwaltung verantwortlich ist, weil ich @Transactional in meiner Serviceebene nicht möchte. –

+1

vielleicht können Sie einige Patches in 'getCurrentSession()' wie getCurrentSession() von sessionFactory machen, wenn nicht verfügbar, dann verwenden Sie 'openSession()', natürlich müssen Sie es manuell schließen, wenn eine neue Sitzung geöffnet wurde. –

+0

es funktionierte :-) Wie auch immer, lass uns warten, ob es einen anderen Vorschlag gibt –

1

Sie können Last-Zeitaspekt konfigurieren Weben

Hier ist das Grundbeispiel ist, wie es

<?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> 

Entity Klasse

Frühling Kontext zu tun

Paket 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 Klasse

Paket 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') 

Unit-Test

Paket 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); 
    } 

} 

Hier ist meine 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> 

Schließlich müssen Sie JVM mit dem folgenden Argument -javaagent:<PATH-TO>/spring-instrument-{vertion}.jar ausführen, um das Hinzufügen von -javaagent Argument zu verhindern kann auch aspectj kompilierzeit weben konfigurieren.