Tomcat 上的 Spring/JPA/Vaadin - 非持久实体

标签 spring tomcat jpa vaadin

我有一个 Web 应用程序,它在 Tomcat 7 服务器上使用堆栈 Spring、JPA(Hibernate impl)和 Vaadin 7。问题是实体管理器不是持久实体的。此外,不会抛出任何错误/异常。我想this question可以掌握答案,但我不确定。

要将 Vaadin 7 与 Spring 一起使用,我使用 Spring Vaadin addon .

由于文件数量较多,这里做一个概览:

  • src/main/webapp/META-INF/context.xml
  • src/main/webapp/WEB-INF/web.xml
  • src/main/webapp/WEB-INF/application-context.xml
  • src/main/java/com/ks/places/MyUI.java(自动连接 placeService 并创建 Place 实体)
  • src/main/java/com/ks/places/model/Place.java(有问题的实体)
  • src/main/java/com/ks/places/dao/PlaceDao.java
  • src/main/java/com/ks/places/dao/PlaceDaoImpl.java
  • src/main/java/com/ks/places/service/PlaceService.java
  • src/main/java/com/ks/places/service/PlaceServiceImpl.java

这是我的代码:

WEB-INF/web.xml

<!-- Spring -->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
    <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/application-context.xml</param-value>
</context-param>

<!-- Vaadin servlet -->
<servlet>
    <servlet-name>Vaadin Application Servlet</servlet-name>
    <servlet-class>ru.xpoft.vaadin.SpringVaadinServlet</servlet-class>
    <init-param>
        <description>Vaadin UI to display</description>
        <param-name>beanName</param-name>
        <param-value>myUI</param-value>
    </init-param>
    <init-param>
        <param-name>systemMessagesBeanName</param-name>
        <param-value>DEFAULT</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>Vaadin Application Servlet</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>Vaadin Application Servlet</servlet-name>
    <url-pattern>/VAADIN/*</url-pattern>
</servlet-mapping>

<!-- Vaadin Production/debug mode -->
<context-param>
    <description>Vaadin production mode</description>
    <param-name>productionMode</param-name>
    <param-value>false</param-value>
</context-param>

<!-- JNDI datasource -->
<resource-ref>
    <description>JNDI Datasource</description>
    <res-ref-name>jdbc/placesPU</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
</resource-ref>

WEB-INF/application-config.xml (Spring 配置)

<!-- component scan for @Component, @Repositry, @Service -->
<context:component-scan base-package="com.ks.places" />

<!-- Activates various annotations to be detected in bean classes for eg @Autowired -->
<context:annotation-config />

<jee:jndi-lookup id="jndiDataSource" jndi-name="jdbc/placesPU" resource-ref="true" expected-type="javax.sql.DataSource" />

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="placesPU" />
    <property name="dataSource" ref="jndiDataSource" />
    <property name="packagesToScan" value="com.ks.places.model" />

    <!-- this is important to connect JPA and JdbcTemplate transaction control -->
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="database" value="MYSQL" />
            <property name="showSql" value="true" />
        </bean>
    </property>

</bean>

<bean id="hibernateJpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />

<!-- Transaction manager for a single JPA EntityManagerFactory (alternative to JTA) -->
<bean id='transactionManager' class='org.springframework.orm.jpa.JpaTransactionManager'>
    <property name='entityManagerFactory' ref='entityManagerFactory' />
    <property name="jpaDialect" ref="hibernateJpaDialect" />
</bean>

<!-- enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager" proxy-target-class="true" />

<!-- Spring's exception translation -->
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>

<!-- Spring container will act as a JPA container and inject an EnitityManager from your EntityManagerFactory -->
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

<bean class="ru.xpoft.vaadin.VaadinMessageSource" />

META-INF/context.xml(Tomcat 上下文文件)

<Context antiJARLocking="true" path="/Places">

<Resource   name="jdbc/placesPU" 
            auth="Container"
            type="javax.sql.DataSource" 
            driverClassName="com.mysql.jdbc.Driver"
            url="jdbc:mysql://192.168.1.36:3306/places"
            username="root"
            password="pass" 
            removeAbandoned="true" 
            removeAbandonedTimeout="90"
            logAbandoned="true" 
            maxActive="20" 
            maxIdle="10" 
            maxWait="-1" />

</Context>

PlaceDao.java

public interface PlaceDao {

    public void save(Place place);

}

PlaceDaoImpl.java

@Repository("placeDao")
public class PlaceDaoImpl implements PlaceDao {

    // @PersistenceContext(unitName="placesPU") // also tried this
    private EntityManager entityManager;

    public EntityManager getEntityManager() {
        return entityManager;
    }

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

    @Override
    public void save(Place place) {
        entityManager.persist(place);
        entityManager.flush(); <- gives an TransactionRequiredException exception
    }

}

PlaceService.java

public interface PlaceService {

    void save(Place place);

}

PlaceServiceImpl.java

//@Transactional(propagation = Propagation.REQUIRED, readOnly = false) // also tried this
@Service("placeService")    
public class PlaceServiceImpl implements PlaceService {

    @Autowired
    private PlaceDao placeDao;

    //@Transactional // also tried this
    @Transactional(propagation= Propagation.REQUIRED, readOnly=false)
    @Override
    public void save(Place place) {
        placeDao.save(place);
    }

}

MyUI.java

@Component
@Scope("prototype")
public class MyUI extends UI implements Serializable {

    private static final long serialVersionUID = 1L;

    @Autowired
    private PlaceService placeService;

    @Override
    protected void init(VaadinRequest request) {
        final VerticalLayout layout = new VerticalLayout();
        layout.setMargin(true);
        setContent(layout);

        Button button = new Button("Click Me");
        button.addClickListener(new Button.ClickListener() {

        private static final long serialVersionUID = 1L;

        public void buttonClick(ClickEvent event) {

                Place place = new Place();
                place.setName("vandaag");

                placeService.save(place);

                // No entity was added to the database...

            }
        });
        layout.addComponent(button);
    }

}

交易

当我保留 Place 实体(MyUI.java 中的 placeService.save())时,我没有收到任何错误或异常。但是,当我手动尝试刷新 entityManager 时,我确实收到错误消息:

Caused by: javax.persistence.TransactionRequiredException: no transaction is in progress
at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:983)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:366)
at $Proxy16.flush(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:241)
at $Proxy16.flush(Unknown Source)
at com.ks.places.dao.PlaceDaoImpl.save(PlaceDaoImpl.java:44)

最佳答案

异常清楚地表明,您的 @Transactional根本不考虑注释。

我建议您删除 mode="aspectj"来自 <tx:annotation-driven ... /> :

<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />

默认modeproxy .对于 aspectj您需要完整的 AspectJ 支持(目前我看不出您应该需要它的原因)。 AspectJ 织入需要类路径上的 spring-aspects.jar,以及启用加载时织入(或编译时织入)。

(顺便说一下,您不需要 proxy-target-class="true",因为您有服务接口(interface)。)

关于Tomcat 上的 Spring/JPA/Vaadin - 非持久实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14865603/

相关文章:

spring-data-neo4j v6 : No converter found capable of converting from type [MyDTO] to type [org. neo4j.driver.Value]

java - 如何忽略 Spring RequestMapping 中的特定 URI 模式?

java - Spring Security配置访问

java - 无法在 IntelliJ 上使用 2.2.1.BUILD-SNAPSHOT 运行 Spring Initializr

java - 如何在端口 8080 上运行时发布 tomcat webapp?

java - Faces Servlet - ClassNotFound 异常

mysql - 还需要用 MySQL 5 在 J2EE 6 中编写连接池类吗?

java - Hibernate 复合类映射

hibernate - 如何在具有ManyToOne映射的字段上编写 hibernate session 查询JOIN不相关实体

java - Spring-jpa-数据 : more than one DataSource and one single Spring config