2012-10-18 19 views
5

Ho riscontrato un problema con l'ottenimento della sessione sulla classe interna di anonymus in modalità ibernazione con la fabbrica di sessioni primaverili. ecco il codice:Sessione di ibernazione all'interno della classe interna

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

     ... 
    }); 

La questione è org.hibernate.HibernateException: nessuna sessione trovato per thread corrente questo accade di solito quando il metodo DAO non è all'interno della transazione. Quindi come farlo funzionare con una classe interiore?

risposta

1

penso di definire @Transactional(readOnly = true) a livello di classe interna, la primavera non sarà in grado di rilevare e applicare l'aspetto della transazione su di esso. quindi non funzionerà di sicuro.

ma credo che se si scrive qualcosa di simile di seguito potrebbe funzionare non sicuro al 100% (dubito una volta che si richiama transazione metodo iterator è chiuso)

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

un'altra opzione può essere lasciato chiamante essere responsabile di transazione o scrivere metodo wrapper su iterator() come getAllDomain() e applicare la transazione a tale metodo.

soluzione che ha funzionato (citato nei commenti)

può essere che si può fare un po 'di patch in getCurrentSession() come getCurrentSession() da sessionFactory se non disponibile utilizzare openSession(), naturalmente si deve chiuderlo manualmente se è stata aperta la nuova sessione .

+0

Grazie per la risposta, ho provato prima di chiedere senza successo. E non voglio che il chiamante sia responsabile della gestione delle transazioni perché non desidero @Transactional nel mio livello di servizio. –

+1

potrebbe essere possibile eseguire alcune patch in 'getCurrentSession()' come getCurrentSession() da sessionFactory se non disponibile, quindi utilizzare 'openSession()', naturalmente è necessario chiuderlo manualmente se si apre una nuova sessione. –

+0

ha funzionato :-) comunque, aspettiamo di vedere se c'è un altro suggerimento –

1

È possibile configurare aspetto load-time tessendo

Ecco l'esempio di base come farlo

contesto Primavera

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

classe Entity

pacchetto 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(); 
    } 
} 

classe Dao

pacchetto 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à di prova

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

} 

Ecco il mio 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> 

Dopo tutto è necessario eseguire JVM con il seguente argomento -javaagent:<PATH-TO>/spring-instrument-{vertion}.jar. Per evitare di aggiungere l'argomento -javaagent può anche configurare l'aspetto della tessitura in compile-time.

Problemi correlati