使用 JPA 的 Spring MVC 3.0 应用程序不保存到数据库

发布于 2024-12-11 16:10:41 字数 18982 浏览 0 评论 0原文

我正在尝试弄清楚如何使用 Spring MVC,并且我已经编写了一个示例应用程序来执行此操作。我使用 Roo 进行基本设置,但我添加了一些我自己的东西。

我正在尝试使用 JPA 和事务来与我的 MySQL 数据库进行交互,但是据我所知,事务从未被创建。我追踪到对 EntityManagerFactoryUtils.doGetTransactionalEntityManager 方法的调用,它似乎在检查 TransactionSynchronizationManager.isSynchronizationActive() 时失败。

我查看了其他遇到此问题的人,看起来他们需要将 @Transactional 注释添加到他们的服务中课程,但我已经上过,但没用。

这是我的设置:

web.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
   xmlns="http://java.sun.com/xml/ns/javaee" 
   xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
   http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath*:META-INF/spring/applicationContext*.xml</param-value>
  </context-param>
  <listener>
    <listener-class>
      org.springframework.web.context.ContextLoaderListener
    </listener-class>
  </listener>
  <filter>
    <filter-name>OpenEntityManagerInViewFilter</filter-name>
    <filter-class>
      org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter
    </filter-class>
  </filter>
  <filter-mapping>
    <filter-name>OpenEntityManagerInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  <servlet>
    <servlet-name>mvcTest</servlet-name>
    <servlet-class>
      org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/spring/webmvc-config.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>mvcTest</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>mvcTest</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
  <welcome-file-list>
    <welcome-file>home.jsp</welcome-file>
  </welcome-file-list>
</web-app>

applicationContext.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:aop="http://www.springframework.org/schema/aop" 
    xmlns:context="http://www.springframework.org/schema/context" 
    xmlns:jee="http://www.springframework.org/schema/jee" 
    xmlns:tx="http://www.springframework.org/schema/tx" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-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/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

    <!--
        This will automatically locate any and all property files you have
        within your classpath, provided they fall under the META-INF/spring
        directory. The located property files are parsed and their values can
        then be used within application context files in the form of
        ${propertyKey}.
    -->
    <context:property-placeholder location="classpath*:META-INF/spring/*.properties"/>
    <!--
        Turn on AspectJ @Configurable support. As a result, any time you
        instantiate an object, Spring will attempt to perform dependency
        injection on that object. This occurs for instantiation via the "new"
        keyword, as well as via reflection. This is possible because AspectJ
        is used to "weave" Roo-based applications at compile time. In effect
        this feature allows dependency injection of any object at all in your
        system, which is a very useful feature (without @Configurable you'd
        only be able to dependency inject objects acquired from Spring or
        subsequently presented to a specific Spring dependency injection
        method). Roo applications use this useful feature in a number of
        areas, such as @PersistenceContext injection into entities.
    -->
    <context:spring-configured/>
    <!--
        This declaration will cause Spring to locate every @Component,
        @Repository and @Service in your application. In practical terms this
        allows you to write a POJO and then simply annotate the new POJO as an
        @Service and Spring will automatically detect, instantiate and
        dependency inject your service at startup time. Importantly, you can
        then also have your new service injected into any other class that
        requires it simply by declaring a field for your service inside the
        relying class and Spring will inject it. Note that two exclude filters
        are declared. The first ensures that Spring doesn't spend time
        introspecting Roo-specific ITD aspects. The second ensures Roo doesn't
        instantiate your @Controller classes, as these should be instantiated
        by a web tier application context. Refer to web.xml for more details
        about the web tier application context setup services.

        Furthermore, this turns on @Autowired, @PostConstruct etc support. These 
        annotations allow you to use common Spring and Java Enterprise Edition 
        annotations in your classes without needing to do any special configuration. 
        The most commonly used annotation is @Autowired, which instructs Spring to
        dependency inject an object into your class.
    -->
    <context:component-scan base-package="com.sedi.test">
        <context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
    </context:component-scan>
    <bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
        <property name="driverClassName" value="${database.driverClassName}"/>
        <property name="url" value="${database.url}"/>
        <property name="username" value="${database.username}"/>
        <property name="password" value="${database.password}"/>
        <property name="testOnBorrow" value="true"/>
        <property name="testOnReturn" value="true"/>
        <property name="testWhileIdle" value="true"/>
        <property name="timeBetweenEvictionRunsMillis" value="1800000"/>
        <property name="numTestsPerEvictionRun" value="3"/>
        <property name="minEvictableIdleTimeMillis" value="1800000"/>
        <property name="validationQuery" value="SELECT 1"/>
    </bean>
    <bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>
    <tx:annotation-driven/>

    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

    <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>

    <bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
        <property name="persistenceUnitName" value="persistenceUnit"/>
        <property name="dataSource" ref="dataSource"/>
    </bean>
</beans>

webmvc-config.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:context="http://www.springframework.org/schema/context" 
    xmlns:mvc="http://www.springframework.org/schema/mvc" 
    xmlns:p="http://www.springframework.org/schema/p" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-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">

    <!-- The controllers are autodetected POJOs labeled with the @Controller annotation. -->
    <context:component-scan base-package="com.sedi.test" use-default-filters="false">
        <context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
    </context:component-scan>

    <!-- Turns on support for mapping requests to Spring MVC @Controller methods
         Also registers default Formatters and Validators for use across all @Controllers -->
    <mvc:annotation-driven />

    <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources -->
    <mvc:resources location="/, classpath:/META-INF/web-resources/" mapping="/resources/**"/>

    <!-- Allows for mapping the DispatcherServlet to "/" by forwarding static resource requests to the container's default Servlet -->
    <mvc:default-servlet-handler/>

    <!-- register "global" interceptor beans to apply to all registered HandlerMappings -->
    <mvc:interceptors>
        <bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor"/>
        <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" p:paramName="lang"/>
    </mvc:interceptors>

    <!-- selects a static view for rendering without the need for an explicit controller -->
    <mvc:view-controller path="/" view-name="index"/>
    <mvc:view-controller path="/uncaughtException"/>
    <mvc:view-controller path="/resourceNotFound"/>
    <mvc:view-controller path="/dataAccessFailure"/>

    <!-- Resolves localized messages*.properties and application.properties files in the application to allow for internationalization. 
        The messages*.properties files translate Roo generated messages which are part of the admin interface, the application.properties
        resource bundle localizes all application specific messages such as entity names and menu items. -->
    <bean class="org.springframework.context.support.ReloadableResourceBundleMessageSource" id="messageSource" p:basenames="WEB-INF/i18n/messages,WEB-INF/i18n/application" p:fallbackToSystemLocale="false"/>

    <!-- store preferred language configuration in a cookie -->
    <bean class="org.springframework.web.servlet.i18n.CookieLocaleResolver" id="localeResolver" p:cookieName="locale"/> 

    <!-- resolves localized <theme_name>.properties files in the classpath to allow for theme support -->
    <bean class="org.springframework.ui.context.support.ResourceBundleThemeSource" id="themeSource"/>

    <!-- store preferred theme configuration in a cookie -->
    <bean class="org.springframework.web.servlet.theme.CookieThemeResolver" id="themeResolver" p:cookieName="theme" p:defaultThemeName="standard"/>

    <!-- This bean resolves specific types of exceptions to corresponding logical - view names for error views. 
         The default behaviour of DispatcherServlet - is to propagate all exceptions to the servlet container: 
         this will happen - here with all other types of exceptions. -->
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver" p:defaultErrorView="uncaughtException">
        <property name="exceptionMappings">
            <props>
                <prop key=".DataAccessException">dataAccessFailure</prop>
                <prop key=".NoSuchRequestHandlingMethodException">resourceNotFound</prop>
                <prop key=".TypeMismatchException">resourceNotFound</prop>
                <prop key=".MissingServletRequestParameterException">resourceNotFound</prop>
            </props>
        </property>
    </bean>

    <!-- allows for integration of file upload functionality -->
    <bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver"/>
    <bean class="org.springframework.web.servlet.view.UrlBasedViewResolver" id="tilesViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView"/>
    </bean>
    <bean class="org.springframework.web.servlet.view.tiles2.TilesConfigurer" id="tilesConfigurer">
    <property name="definitions">
      <list>
        <value>/WEB-INF/layouts/layouts.xml</value>
        <!-- Scan views directory for Tiles configurations -->
        <value>/WEB-INF/views/**/views.xml</value>
      </list>
    </property>
  </bean>
</beans>

persistance.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    version="2.0" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
        http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
  <persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
            <!-- value="create" to build a new database on each run; value="update" to modify an existing database; value="create-drop" means the same as "create" but also drops tables when Hibernate closes; value="validate" makes no changes to the database -->
            <property name="hibernate.hbm2ddl.auto" value="create"/>
            <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy"/>
            <property name="hibernate.connection.charSet" value="UTF-8"/>
            <!-- Uncomment the following two properties for JBoss only -->
            <!-- property name="hibernate.validator.apply_to_ddl" value="false" /-->
            <!-- property name="hibernate.validator.autoregister_listeners" value="false" /-->
        </properties>
    </persistence-unit>
</persistence>

这是正在调用的服务:

package com.sedi.test.service;

import java.util.List;

import javax.inject.Inject;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.sedi.test.domain.Calendar;
import com.sedi.test.repository.CalendarDao;

@Service("calendarService")
@Transactional(readOnly = false)
public class CalendarServiceImpl implements CalendarService{
    private CalendarDao calendarDao;

    @Inject
    public void setCalendarDao(CalendarDao calendarDao){
        this.calendarDao = calendarDao;
    }

    public Calendar get(Long id){
        return calendarDao.get(id);
    }

    public List<Calendar> getAll(){
        return calendarDao.getAll();
    }

    public void save(Calendar object){
        calendarDao.save(object);
    }

    public void delete(Calendar object){
        calendarDao.delete(object);
    }

    public void delete(Long id){
        delete(get(id));
    }

}

这是使用的 DAO 类:

package com.sedi.test.repository;

import org.springframework.stereotype.Repository;

import com.sedi.test.domain.Calendar;
import com.sedi.util.mvc.domain.dao.GenericDaoJpa;

@Repository("calendarDao")
public class CalendarDaoJpa extends GenericDaoJpa<Calendar> implements CalendarDao{

    public CalendarDaoJpa(){
        super(Calendar.class);
    }
}

最后,这是继承自的 GenericDao:

package com.sedi.util.mvc.domain.dao;

import java.io.Serializable;
import java.util.Iterator;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.hibernate.search.jpa.FullTextEntityManager;
import org.hibernate.search.jpa.Search;
import org.springframework.dao.DataAccessException;

@SuppressWarnings("unchecked")
public class GenericDaoJpa<T extends Serializable> implements GenericDao<T>{

    private Class<T> type;

    protected EntityManager entityManager;

    public GenericDaoJpa(Class<T> type){
        super();
        this.type = type;
    }

    @PersistenceContext
    public void setEntityManager(EntityManager entityManager){
        this.entityManager = entityManager;
    }

    public T get(Long id){
        return (T) entityManager.find(type, id);
    }

    public List<T> getAll(){
        return entityManager.createQuery("select obj from "+type.getName()+" obj").getResultList();
    }

    public void save(T object) throws DataAccessException{
        entityManager.merge(object);
    }

    public void delete(T object) throws DataAccessException{
        entityManager.remove(object);
    }

    public void indexEntity(T object){
        FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager);
        fullTextEntityManager.index(object);
    }

    public void indexAllItems(){
        FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager);
        List<T> results = fullTextEntityManager.createQuery("from "+type.getCanonicalName()).getResultList();
        int counter = 0, numItemsInGroup = 10;
        Iterator<T> resultsIt = results.iterator();
        while (resultsIt.hasNext()) {
            fullTextEntityManager.index(resultsIt.next());
            if (counter++%numItemsInGroup==0) {
                fullTextEntityManager.flushToIndexes();
                fullTextEntityManager.clear();
            }
        }
    }

}

正如我所说,我已经查明了这一点,它正在影响所有班级。我知道它正在访问数据库,因为如果我删除它们,就会重新创建表。 Eclipse(嗯,实际上是 Spring Tool Suite)告诉我服务保存方法是由 org.springframework.transaction.interceptor.TransactionInterceptor.invoke(org.aopalliance.intercept.MethodInitation) 建议的。

我怀疑我在 applicationContext.xml 中做了一些关于 tx 内容的错误,但它看起来像是我从哪里获取信息的。我有点抓狂了。有谁知道我犯了什么(最有可能是非常明显的)错误?

非常感谢您抽出时间

I'm trying to figure out how to use Spring MVC and I've put together a sample application to do so. I used Roo for basic set up, but I've added a fair bit of my own stuff.

I'm trying to use JPA with transactions to interact with my MySQL database, but, from what I can tell, the transactions are not ever being created. I traced this out to a call to the EntityManagerFactoryUtils.doGetTransactionalEntityManager method and it seems to fail on checking TransactionSynchronizationManager.isSynchronizationActive()

I've looked at other people having this problem and it looks like they needed to add the @Transactional annotation to their service classes, but I already had that and it wasn't working.

Here is my set up:

web.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
   xmlns="http://java.sun.com/xml/ns/javaee" 
   xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
   http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath*:META-INF/spring/applicationContext*.xml</param-value>
  </context-param>
  <listener>
    <listener-class>
      org.springframework.web.context.ContextLoaderListener
    </listener-class>
  </listener>
  <filter>
    <filter-name>OpenEntityManagerInViewFilter</filter-name>
    <filter-class>
      org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter
    </filter-class>
  </filter>
  <filter-mapping>
    <filter-name>OpenEntityManagerInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  <servlet>
    <servlet-name>mvcTest</servlet-name>
    <servlet-class>
      org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/spring/webmvc-config.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>mvcTest</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>mvcTest</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
  <welcome-file-list>
    <welcome-file>home.jsp</welcome-file>
  </welcome-file-list>
</web-app>

applicationContext.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:aop="http://www.springframework.org/schema/aop" 
    xmlns:context="http://www.springframework.org/schema/context" 
    xmlns:jee="http://www.springframework.org/schema/jee" 
    xmlns:tx="http://www.springframework.org/schema/tx" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-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/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

    <!--
        This will automatically locate any and all property files you have
        within your classpath, provided they fall under the META-INF/spring
        directory. The located property files are parsed and their values can
        then be used within application context files in the form of
        ${propertyKey}.
    -->
    <context:property-placeholder location="classpath*:META-INF/spring/*.properties"/>
    <!--
        Turn on AspectJ @Configurable support. As a result, any time you
        instantiate an object, Spring will attempt to perform dependency
        injection on that object. This occurs for instantiation via the "new"
        keyword, as well as via reflection. This is possible because AspectJ
        is used to "weave" Roo-based applications at compile time. In effect
        this feature allows dependency injection of any object at all in your
        system, which is a very useful feature (without @Configurable you'd
        only be able to dependency inject objects acquired from Spring or
        subsequently presented to a specific Spring dependency injection
        method). Roo applications use this useful feature in a number of
        areas, such as @PersistenceContext injection into entities.
    -->
    <context:spring-configured/>
    <!--
        This declaration will cause Spring to locate every @Component,
        @Repository and @Service in your application. In practical terms this
        allows you to write a POJO and then simply annotate the new POJO as an
        @Service and Spring will automatically detect, instantiate and
        dependency inject your service at startup time. Importantly, you can
        then also have your new service injected into any other class that
        requires it simply by declaring a field for your service inside the
        relying class and Spring will inject it. Note that two exclude filters
        are declared. The first ensures that Spring doesn't spend time
        introspecting Roo-specific ITD aspects. The second ensures Roo doesn't
        instantiate your @Controller classes, as these should be instantiated
        by a web tier application context. Refer to web.xml for more details
        about the web tier application context setup services.

        Furthermore, this turns on @Autowired, @PostConstruct etc support. These 
        annotations allow you to use common Spring and Java Enterprise Edition 
        annotations in your classes without needing to do any special configuration. 
        The most commonly used annotation is @Autowired, which instructs Spring to
        dependency inject an object into your class.
    -->
    <context:component-scan base-package="com.sedi.test">
        <context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
    </context:component-scan>
    <bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
        <property name="driverClassName" value="${database.driverClassName}"/>
        <property name="url" value="${database.url}"/>
        <property name="username" value="${database.username}"/>
        <property name="password" value="${database.password}"/>
        <property name="testOnBorrow" value="true"/>
        <property name="testOnReturn" value="true"/>
        <property name="testWhileIdle" value="true"/>
        <property name="timeBetweenEvictionRunsMillis" value="1800000"/>
        <property name="numTestsPerEvictionRun" value="3"/>
        <property name="minEvictableIdleTimeMillis" value="1800000"/>
        <property name="validationQuery" value="SELECT 1"/>
    </bean>
    <bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>
    <tx:annotation-driven/>

    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

    <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>

    <bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
        <property name="persistenceUnitName" value="persistenceUnit"/>
        <property name="dataSource" ref="dataSource"/>
    </bean>
</beans>

webmvc-config.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:context="http://www.springframework.org/schema/context" 
    xmlns:mvc="http://www.springframework.org/schema/mvc" 
    xmlns:p="http://www.springframework.org/schema/p" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-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">

    <!-- The controllers are autodetected POJOs labeled with the @Controller annotation. -->
    <context:component-scan base-package="com.sedi.test" use-default-filters="false">
        <context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
    </context:component-scan>

    <!-- Turns on support for mapping requests to Spring MVC @Controller methods
         Also registers default Formatters and Validators for use across all @Controllers -->
    <mvc:annotation-driven />

    <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources -->
    <mvc:resources location="/, classpath:/META-INF/web-resources/" mapping="/resources/**"/>

    <!-- Allows for mapping the DispatcherServlet to "/" by forwarding static resource requests to the container's default Servlet -->
    <mvc:default-servlet-handler/>

    <!-- register "global" interceptor beans to apply to all registered HandlerMappings -->
    <mvc:interceptors>
        <bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor"/>
        <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" p:paramName="lang"/>
    </mvc:interceptors>

    <!-- selects a static view for rendering without the need for an explicit controller -->
    <mvc:view-controller path="/" view-name="index"/>
    <mvc:view-controller path="/uncaughtException"/>
    <mvc:view-controller path="/resourceNotFound"/>
    <mvc:view-controller path="/dataAccessFailure"/>

    <!-- Resolves localized messages*.properties and application.properties files in the application to allow for internationalization. 
        The messages*.properties files translate Roo generated messages which are part of the admin interface, the application.properties
        resource bundle localizes all application specific messages such as entity names and menu items. -->
    <bean class="org.springframework.context.support.ReloadableResourceBundleMessageSource" id="messageSource" p:basenames="WEB-INF/i18n/messages,WEB-INF/i18n/application" p:fallbackToSystemLocale="false"/>

    <!-- store preferred language configuration in a cookie -->
    <bean class="org.springframework.web.servlet.i18n.CookieLocaleResolver" id="localeResolver" p:cookieName="locale"/> 

    <!-- resolves localized <theme_name>.properties files in the classpath to allow for theme support -->
    <bean class="org.springframework.ui.context.support.ResourceBundleThemeSource" id="themeSource"/>

    <!-- store preferred theme configuration in a cookie -->
    <bean class="org.springframework.web.servlet.theme.CookieThemeResolver" id="themeResolver" p:cookieName="theme" p:defaultThemeName="standard"/>

    <!-- This bean resolves specific types of exceptions to corresponding logical - view names for error views. 
         The default behaviour of DispatcherServlet - is to propagate all exceptions to the servlet container: 
         this will happen - here with all other types of exceptions. -->
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver" p:defaultErrorView="uncaughtException">
        <property name="exceptionMappings">
            <props>
                <prop key=".DataAccessException">dataAccessFailure</prop>
                <prop key=".NoSuchRequestHandlingMethodException">resourceNotFound</prop>
                <prop key=".TypeMismatchException">resourceNotFound</prop>
                <prop key=".MissingServletRequestParameterException">resourceNotFound</prop>
            </props>
        </property>
    </bean>

    <!-- allows for integration of file upload functionality -->
    <bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver"/>
    <bean class="org.springframework.web.servlet.view.UrlBasedViewResolver" id="tilesViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView"/>
    </bean>
    <bean class="org.springframework.web.servlet.view.tiles2.TilesConfigurer" id="tilesConfigurer">
    <property name="definitions">
      <list>
        <value>/WEB-INF/layouts/layouts.xml</value>
        <!-- Scan views directory for Tiles configurations -->
        <value>/WEB-INF/views/**/views.xml</value>
      </list>
    </property>
  </bean>
</beans>

persistance.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    version="2.0" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
        http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
  <persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
            <!-- value="create" to build a new database on each run; value="update" to modify an existing database; value="create-drop" means the same as "create" but also drops tables when Hibernate closes; value="validate" makes no changes to the database -->
            <property name="hibernate.hbm2ddl.auto" value="create"/>
            <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy"/>
            <property name="hibernate.connection.charSet" value="UTF-8"/>
            <!-- Uncomment the following two properties for JBoss only -->
            <!-- property name="hibernate.validator.apply_to_ddl" value="false" /-->
            <!-- property name="hibernate.validator.autoregister_listeners" value="false" /-->
        </properties>
    </persistence-unit>
</persistence>

Here's the service that is getting called:

package com.sedi.test.service;

import java.util.List;

import javax.inject.Inject;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.sedi.test.domain.Calendar;
import com.sedi.test.repository.CalendarDao;

@Service("calendarService")
@Transactional(readOnly = false)
public class CalendarServiceImpl implements CalendarService{
    private CalendarDao calendarDao;

    @Inject
    public void setCalendarDao(CalendarDao calendarDao){
        this.calendarDao = calendarDao;
    }

    public Calendar get(Long id){
        return calendarDao.get(id);
    }

    public List<Calendar> getAll(){
        return calendarDao.getAll();
    }

    public void save(Calendar object){
        calendarDao.save(object);
    }

    public void delete(Calendar object){
        calendarDao.delete(object);
    }

    public void delete(Long id){
        delete(get(id));
    }

}

This is the DAO class that uses:

package com.sedi.test.repository;

import org.springframework.stereotype.Repository;

import com.sedi.test.domain.Calendar;
import com.sedi.util.mvc.domain.dao.GenericDaoJpa;

@Repository("calendarDao")
public class CalendarDaoJpa extends GenericDaoJpa<Calendar> implements CalendarDao{

    public CalendarDaoJpa(){
        super(Calendar.class);
    }
}

And finally, this is the GenericDao that inherits from:

package com.sedi.util.mvc.domain.dao;

import java.io.Serializable;
import java.util.Iterator;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.hibernate.search.jpa.FullTextEntityManager;
import org.hibernate.search.jpa.Search;
import org.springframework.dao.DataAccessException;

@SuppressWarnings("unchecked")
public class GenericDaoJpa<T extends Serializable> implements GenericDao<T>{

    private Class<T> type;

    protected EntityManager entityManager;

    public GenericDaoJpa(Class<T> type){
        super();
        this.type = type;
    }

    @PersistenceContext
    public void setEntityManager(EntityManager entityManager){
        this.entityManager = entityManager;
    }

    public T get(Long id){
        return (T) entityManager.find(type, id);
    }

    public List<T> getAll(){
        return entityManager.createQuery("select obj from "+type.getName()+" obj").getResultList();
    }

    public void save(T object) throws DataAccessException{
        entityManager.merge(object);
    }

    public void delete(T object) throws DataAccessException{
        entityManager.remove(object);
    }

    public void indexEntity(T object){
        FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager);
        fullTextEntityManager.index(object);
    }

    public void indexAllItems(){
        FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager);
        List<T> results = fullTextEntityManager.createQuery("from "+type.getCanonicalName()).getResultList();
        int counter = 0, numItemsInGroup = 10;
        Iterator<T> resultsIt = results.iterator();
        while (resultsIt.hasNext()) {
            fullTextEntityManager.index(resultsIt.next());
            if (counter++%numItemsInGroup==0) {
                fullTextEntityManager.flushToIndexes();
                fullTextEntityManager.clear();
            }
        }
    }

}

As I said, I've traced this out and it is hitting all the classes. I know it is hitting the database because the tables are recreated if I remove them. Eclipse (well, really Spring Tool Suite) is telling me that the service save method is advised by org.springframework.transaction.interceptor.TransactionInterceptor.invoke(org.aopalliance.intercept.MethodInvocation).

I suspect that I've done something wrong inside applicationContext.xml with regards to the tx stuff, but it looks like where I got the information from. I'm kind of tearing my hair out here. Does anyone have a clue as to what (most likely extremely obvious) mistake I'm making?

Thanks so much for your time

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

峩卟喜欢 2024-12-18 16:10:41

您是否尝试过使用不同类型的 entityManagerFactory

<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="persistenceUnit"/>
    <property name="dataSource" ref="dataSource"/>
</bean>

Spring 文档 LocalEntityManagerFactoryBean 声明:“这是在 Spring 应用程序上下文中设置共享 JPA EntityManagerFactory 的最简单方法”。尝试使用它 - 看起来出现严重错误的方法更少;-)

Have you tried using a different type of entityManagerFactory ?

<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="persistenceUnit"/>
    <property name="dataSource" ref="dataSource"/>
</bean>

The Spring doco for the LocalEntityManagerFactoryBean states: "This is the simplest way to set up a shared JPA EntityManagerFactory in a Spring application context". Try using that - it seems like there are fewer ways for it to go horribly wrong ;-)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文