Нет EntityManager с фактической транзакцией, доступной для текущего потока: несколько файлов конфигурации xml - PullRequest
2 голосов
/ 14 февраля 2020

Здравствуйте. У меня возникла следующая проблема: У меня есть приложение mvc с поддержкой следующих файлов конфигурации. Есть два отдельных файла конфигурации Spring, один для jpa и один для Spring mvc Проблема в том, что когда я пытаюсь что-то сохранить в базе данных, я получаю сообщение об ошибке:

Ошибка обработки запроса сообщения; Вложенное исключение - javax.persistence.TransactionRequiredException: Нет EntityManager с фактической транзакцией, доступной для текущего потока - не может надежно обработать «постоянный» вызов

(у меня есть @Transactional в классе обслуживания), если я переместлю из jpaConfig. xml в servlet-config. xml приложение работает нормально. Я не могу выяснить, почему это происходит, и я считаю неправильным перемещать этот тег в файл конфигурации mvc. Можете ли вы помочь мне понять, почему это происходит?

Интернет. xml:

<?xml version="1.0" encoding="UTF-8"?>
     <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
      http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
     version="4.0">

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:jpaContext.xml</param-value>
</context-param>


<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<servlet>
    <servlet-name>fitTrackerServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/config/servlet-config.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>fitTrackerServlet</servlet-name>
    <url-pattern>/app/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
    <servlet-name>fitTrackerServlet</servlet-name>
    <url-pattern>/pdfs/**</url-pattern>
</servlet-mapping>

servlet-config. xml:

<?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:mvc="http://www.springframework.org/schema/mvc"
   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.xsd
   http://www.springframework.org/schema/mvc 
  http://www.springframework.org/schema/mvc/spring-mvc.xsd">

<mvc:annotation-driven/>
<context:component-scan base-package="com.example"/>

<mvc:interceptors>
    <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
        <property name="paramName" value="language"/>
    </bean>
</mvc:interceptors>

<mvc:resources mapping="pdfs" location="/pdfs/**"/>

<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver" >
    <property name="order" value="1" />
    <property name="contentNegotiationManager" >
        <bean class="org.springframework.web.accept.ContentNegotiationManager">
            <constructor-arg>
                <bean class="org.springframework.web.accept.PathExtensionContentNegotiationStrategy" >
                    <constructor-arg>
                        <map>
                            <entry key="json" value="application/json" />
                            <entry key="xml" value="application/xml" />
                        </map>
                    </constructor-arg>
                </bean>
            </constructor-arg>
        </bean>
    </property>
    <property name="defaultViews">
        <list>
            <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" />
            <bean class="org.springframework.web.servlet.view.xml.MarshallingView" >
                <constructor-arg>
                    <bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
                        <property name="classesToBeBound">
                            <list>
                                <value>com.example.domain.Activity</value>
                            </list>
                        </property>
                    </bean>
                </constructor-arg>
            </bean>
        </list>
    </property>
</bean>

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

<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
    <property name="basename" value="messages"/>
</bean>

<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
    <property name="defaultLocale" value="en"/>
</bean>

и jpaContext. xml:

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

<bean id="entityManagerFactoryBean" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="packagesToScan" value="com.example.domain"/>

    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
    </property>
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.hbm2ddl.auto">create</prop>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
        </props>
    </property>
</bean>

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/fitness_tracker?autoReconnect=true"/>
    <property name="username" value="root"/>
    <property name="password" value="password"/>
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactoryBean"/>
</bean>

<tx:annotation-driven/>

Дао:

@Repository
public class GoalRepositoryImpl implements  GoalRepository {

  @PersistenceContext
  private EntityManager em;

  @Override
  @Transactional
  public Goal save(Goal goal) {
      em.persist(goal);
      em.flush();

      return goal;
  }
}

1 Ответ

1 голос
/ 21 февраля 2020

Здравствуйте! Наконец-то я нашел решение с помощью коллеги.

Spring может иметь несколько контекстов одновременно.

  • Одним из них будет контекст root , а все остальные контексты будут дочерними контекстами.
  • Все дочерние контексты могут обращаться к bean-компонентам, определенным в root контексте, но не наоборот.

В моей сети. xml У меня есть два файла конфигурации xml: файл servlet-config. xml и jpaContext. xml, первый из которых используется DispacherServlet, который создает дочерний контекст приложения. второй используется ContextLoaderListener, который создает root прикладной контекст.

У меня был элемент component-scan в дочернем контексте, поэтому компоненты были созданы внутри дочернего контекста. Когда служебный бин пытался начать новую транзакцию с аннотацией, управляемая аннотацией не могла увидеть бин (потому что это было из дочернего контекста), и, таким образом, я получал ошибку.

путем изменения компонента Сканирование в servlet-config. xml для создания только контроллеров:

<context:component-scan base-package="com.example.controllers"/>

и добавление нового компонента сканирования в контекст root (jpaContext. xml)

<context:component-scan base-package="com.example"/>

проблема решена.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...