2010-12-03 9 views
2

Je veux que mes méthodes de lecture n'utilisent pas une transaction car ce n'est pas du tout nécessaire, je ne marque que mes méthodes create/update avec @Transactional. Mais comment je fais ça? J'ai une configuration assez basique de Spring avec etc ...Spring & Hibernate: méthodes de service non-transactionnelles

SessionFactory est injecté dans mon DAO, et dans chaque méthode j'appelle sessionFactory. getCurrentSession(). DoQueryStuff();

Ceci, néanmoins, les résultats de cette erreur:

org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here 

Si vous avez besoin ma configuration Spring:

<?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:aop="http://www.springframework.org/schema/aop" 
xmlns:context="http://www.springframework.org/schema/context" 
xmlns:mvc="http://www.springframework.org/schema/mvc" 
    xmlns:oxm="http://www.springframework.org/schema/oxm" 
xmlns:tx="http://www.springframework.org/schema/tx" 
    xmlns:util="http://www.springframework.org/schema/util" 
xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
    http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd 
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context-3.0.xsd 
    http://www.springframework.org/schema/mvc 
    http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd 
    http://www.springframework.org/schema/oxm 
    http://www.springframework.org/schema/oxm/spring-oxm-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/util 
    http://www.springframework.org/schema/util/spring-util-3.0.xsd"> 

<context:annotation-config /> 
<context:component-scan base-package="be.howest.kidscalcula" /> 
<mvc:annotation-driven /> 

<bean id="viewResolver" 
    class="org.springframework.web.servlet.view.InternalResourceViewResolver"> 
    <property name="prefix"> 
     <value>/WEB-INF/views/</value> 
    </property> 
    <property name="suffix"> 
     <value>.jsp</value> 
    </property> 
</bean> 


<bean id="myDataSource" 
    class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
    <property name="driverClassName" value="com.mysql.jdbc.Driver" /> 
    <property name="url" value="jdbc:mysql://localhost/kidscalcula" /> 
    <property name="username" value="root" /> 
    <property name="password" value="" /> 
</bean> 

<bean class="org.springframework.orm.hibernate3.LocalSessionFactoryBean" 
    id="sessionFactory"> 
    <property name="dataSource" ref="myDataSource" /> 
    <property name="mappingResources"> 
     <list> 
      <value>be/howest/kidscalcula/model/Foto.hbm.xml</value> 
      <value>be/howest/kidscalcula/model/Kindleerplanonderdeel.hbm.xml 
      </value> 
      <value>be/howest/kidscalcula/model/Klas.hbm.xml</value> 
      <value>be/howest/kidscalcula/model/Leerkracht.hbm.xml</value> 
      <value>be/howest/kidscalcula/model/Leerling.hbm.xml</value> 
      <value>be/howest/kidscalcula/model/Leerplan.hbm.xml</value> 
      <value>be/howest/kidscalcula/model/LeerplanOefenreeks.hbm.xml 
      </value> 
      <value>be/howest/kidscalcula/model/Leerplanonderdeel.hbm.xml</value> 
      <value>be/howest/kidscalcula/model/Niveau.hbm.xml</value> 
      <value>be/howest/kidscalcula/model/Oefenreeks.hbm.xml</value> 
      <value>be/howest/kidscalcula/model/Overgangsregel.hbm.xml</value> 
      <value>be/howest/kidscalcula/model/Rapport.hbm.xml</value> 
      <value>be/howest/kidscalcula/model/RapportLeerplanonderdeel.hbm.xml 
      </value> 
      <value>be/howest/kidscalcula/model/Schooljaar.hbm.xml</value> 
      <value>be/howest/kidscalcula/model/Subonderdeel.hbm.xml</value> 
     </list> 
    </property> 
    <property name="hibernateProperties"> 
     <props> 
      <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop> 
      <prop key="hibernate.connection.pool_size">3</prop> 
      <prop key="hibernate.show_sql">true</prop> 
      <prop key="hibernate.format_sql">true</prop> 
      <prop key="hibernate.use_sql_comments">true</prop> 
      <prop key="hibernate.cache.use_second_level_cache">false</prop> 

     </props> 
    </property> 
</bean> 

<!-- Configure the multipart resolver --> 
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> 
    <!-- one of the properties available; the maximum file size in bytes --> 
    <property name="maxUploadSize" value="500000" /> 
</bean> 


<!-- 
    Transaction manager for a single Hibernate SessionFactory (alternative 
    to JTA) 
--> 
<bean id="transactionManager" 
    class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 
    <property name="sessionFactory"> 
     <ref bean="sessionFactory" /> 
    </property> 
</bean> 

<tx:annotation-driven /> 

Est-ce que cette erreur ont quelque chose à voir avec le fait que La propagation est la norme Obligatoire?

Répondre

1

Il est possible de démarrer une session en dehors d'une transaction même en utilisant la gestion des transactions Spring. Appelez sessionFactory.openSession() pour obtenir une nouvelle session. Cette session est locale car elle n'est pas liée à un thread et ne sera donc pas renvoyée lorsque vous appelez sessionFactory.getCurrentSession(). Vous devrez le gérer et vous assurer qu'il est correctement fermé à la fin de votre session ou en cas d'erreur.

0

Vous ne pouvez pas accéder aux données sans une session (mise en veille prolongée).

Une façon de fournir une telle session est un (lors de l'utilisation du printemps):

  • org.springframework.orm.hibernate3.support.OpenSessionInViewFilter ou
  • org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter (cela dépend de la façon dont vous utilisez votre fournisseur de persistance)

L'effet secondaire positif de ces adaptateurs est que la session est toujours ouverte lorsque les affichages JSP sont rendus. Ainsi, vous n'aurez aucun problème de chargement paresseux lors de l'accès à un tel programme non encore chargé. propriété pendant le rendu.

@see http://community.jboss.org/wiki/OpenSessioninView

10

Marquer la méthode comme transactionnelle et en lecture seule pour assurer la transaction ne modifie pas les données:

@Transactional(readOnly=true) 

C'est une optimisation utile lorsque vous travaillez avec Hibernate. Pour en savoir plus sur les implications de cette annotation, voici un grand message: Read-Only transactions with Spring and Hibernate

+0

Je sais que cela existe, mais quelle est la différence de performance entre faire une lecture de données sans transaction et celle avec une transaction, mais sur readOnly = true? Je voulais éviter d'utiliser @Transactional dans les méthodes en lecture seule, car il n'y a aucune transaction nécessaire en premier lieu. – toomuchcs

+1

Vous ne pouvez pas faire cela. Hibernate nécessite que toutes les opérations d'accès aux données (y compris en lecture seule) doivent aller à l'intérieur d'une transaction. –

+0

Ce n'est pas hiberner, toutes les opérations db ouvrent et ferment une transaction, même une simple sélection dans un développeur SQL par exemple, donc ce n'est pas un problème de mettre des opérations de lecture sur une transaction. Si vous avez beaucoup de lectures, c'est encore plus optimisé pour faire toutes ces lectures dans une transaction unique ... –

2

Comme le message indique clairement, aucune session est liée au fil et la configuration que vous avez spécifié ne permet pas un « non-transaction "session à créer. Je vais essayer d'expliquer chacun de ces scénarios. Lorsque la transaction de Spring est activée dans votre configuration (comme vous l'avez fait), Spring entrelace l'objet SessionFactory avec un proxy qui empêche la création de nouvelles sessions, si elles ne sont pas déjà présentes, lorsque SessionFactory.getCurrentSession est appelée. Le proxy obtiendra uniquement la session en cours liée au thread local et aucune création de session ad-hoc (non-transactionnelle) n'est autorisée par votre code. C'est ainsi que votre configuration empêche la création de session non-trasactionnelle. Lorsque vous annotez une méthode/classe avec @Transactional, TransactionInterceptor de Spring crée une session et la lie au thread en cours lorsque la méthode est appelée afin qu'elle soit disponible plus tard. OpenSessionInViewFilter de Spring, s'il est activé, liera également une session au thread en cours.Puisque vous n'en faites aucune, aucune session liée au fil n'est trouvée. Ce que vous devez faire est d'annoter votre classe avec @Transactional (readOnly = True), puis d'annoter vos méthodes create/update/delete avec @Transactional (readOnly = False). Il est important que vous ayez une transaction en lecture seule lorsque vous lisez des données. Cela vous assure que personne ne peut valider des données pendant cet appel.