Tomcat 7 サーバーでスタック Spring、JPA(Hibernate impl)、および Vaadin 7 を使用する webapp があります。問題は、エンティティ マネージャがエンティティを永続化していないことです。また、エラー/例外はスローされません。この質問は答えを保持できると思いますが、よくわかりません。
Spring で Vaadin 7 を使用するには、Spring Vaadin アドオンを使用します。
ファイル数が多いため、概要は次のとおりです。
- 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 を autowires して 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)