TransactionRequiredException:@Transactional 方法中没有可用的事务性 EntityManager
TransactionRequiredException: No transactional EntityManager available within @Transactional method
设计了包括@Transactional方法在内的Service方法,我遇到了"No transactional EntityManager available"的问题。
Technogoly 使用:JPA、Spring、Maven
异常堆栈跟踪
Exception in thread "main" javax.persistence.TransactionRequiredException: No transactional EntityManager available
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:273)
at com.sun.proxy.$Proxy29.merge(Unknown Source)
at com.restaurant.DAO.OrderDAOImpl.saveOrder(OrderDAOImpl.java:24)
at com.restaurant.services.DeliveryStaffServiceImpl.changeStatusOfOrder(DeliveryStaffServiceImpl.java:37)
at com.restaurant.entities.Main.main(Main.java:161)
我在main中调用服务的方式:
DeliveryStaffService del = context.getBean(DeliveryStaffService.class);
List<Order> listOfOrders = del.getListOfOrders();
尝试找出问题所在:
- 检查 pom.xml 中 Spring 的版本;
- 检查是否所有的@transactional方法都是public;
- 加入beans.xml
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
此外,在同一个项目中有一些使用@transactional 方法的服务,可以正常工作。
这是我的 persistence.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
xmlns="http://java.sun.com/xml/ns/persistence" version="2.0" >
<persistence-unit name="Restaurant" transaction-type="RESOURCE_LOCAL">
<provider>
org.eclipse.persistence.jpa.PersistenceProvider
</provider>
<properties>
<property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver" />
<property name="javax.persistence.jdbc.url" value="jdbc:derby:..//RestaurantDB1;create=true" />
<property name="eclipselink.ddl-generation.output-mode" value="database" />
<property name="eclipselink.weaving" value="static" />
</properties>
</persistence-unit>
</persistence>
Beans.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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan base-package="com.restaurant"/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="packagesToScan" value="com.restaurant"/>
<property name="dataSource" ref="dataSource"/>
<property name="persistenceUnitName" value="Restaurant"/>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect"/>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
<property value="true" name="showSql"/>
<property value="true" name="generateDdl"/>
<property name="databasePlatform" value="org.eclipse.persistence.platform.database.DerbyPlatform"/>
</bean>
</property>
<property name="jpaPropertyMap">
<map>
<entry key="eclipselink.weaving" value="false" />
</map>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.apache.derby.jdbc.EmbeddedDriver"/>
<property name="url" value="jdbc:derby:..//RestaurantDB1;create=true" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<tx:annotation-driven proxy-target-class="true"/>
</beans>
服务实施
@Named
public class KitchenStaffServiceImpl implements KitchenStaffService {
@Inject
private ItemDAO itemDAO;
@Inject
private OrderDAO orderDAO;
@Override
public List<Item> viewItems() {
return itemDAO.viewItems();
}
@Override
@Transactional
public void processItem(Item item) {
int i=item.getQuantity();
while(i>0){
try {
Thread.sleep(1000);
--i;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
item.setIsCooked(true);
itemDAO.saveItem(item);
System.out.println(item.getId());
List<Item> list = item.getOrder().getListOfDishes();
if(list.stream().allMatch(t -> t.getIsCooked()==true)){
Order ord = item.getOrder();
ord.setStatus(StatusOfDelivery.READY_FOR_SHIPMENT);
orderDAO.saveOrder(ord);
}
}
}
DAO 实现
@Repository
public class ItemDAOImpl implements ItemDAO{
@PersistenceContext
private EntityManager em;
@Override
public void saveItem(Item item){
if(item.getId()==0){
em.persist(item);
}else
em.merge(item);
}
}
使用方法 saveOrder(Order order) 的 OrderDAO 实现与 ItemDAO 相同 (persist()/merge())
提前感谢任何提议
您正在呼叫
OrderDAOImpl.saveOrder();
来自方法
DeliveryStaffServiceImpl.changeStatusOfOrder();
但在示例中,您显示 @Transactional
注释放在不相关的方法 KitchenStaffServiceImpl.processItem()
上。很可能,您需要 DeliveryStaffServicleImpl
上的 @Transactional
注释。
设计了包括@Transactional方法在内的Service方法,我遇到了"No transactional EntityManager available"的问题。 Technogoly 使用:JPA、Spring、Maven
异常堆栈跟踪
Exception in thread "main" javax.persistence.TransactionRequiredException: No transactional EntityManager available
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:273)
at com.sun.proxy.$Proxy29.merge(Unknown Source)
at com.restaurant.DAO.OrderDAOImpl.saveOrder(OrderDAOImpl.java:24)
at com.restaurant.services.DeliveryStaffServiceImpl.changeStatusOfOrder(DeliveryStaffServiceImpl.java:37)
at com.restaurant.entities.Main.main(Main.java:161)
我在main中调用服务的方式:
DeliveryStaffService del = context.getBean(DeliveryStaffService.class);
List<Order> listOfOrders = del.getListOfOrders();
尝试找出问题所在:
- 检查 pom.xml 中 Spring 的版本;
- 检查是否所有的@transactional方法都是public;
- 加入beans.xml
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
此外,在同一个项目中有一些使用@transactional 方法的服务,可以正常工作。
这是我的 persistence.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
xmlns="http://java.sun.com/xml/ns/persistence" version="2.0" >
<persistence-unit name="Restaurant" transaction-type="RESOURCE_LOCAL">
<provider>
org.eclipse.persistence.jpa.PersistenceProvider
</provider>
<properties>
<property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver" />
<property name="javax.persistence.jdbc.url" value="jdbc:derby:..//RestaurantDB1;create=true" />
<property name="eclipselink.ddl-generation.output-mode" value="database" />
<property name="eclipselink.weaving" value="static" />
</properties>
</persistence-unit>
</persistence>
Beans.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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan base-package="com.restaurant"/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="packagesToScan" value="com.restaurant"/>
<property name="dataSource" ref="dataSource"/>
<property name="persistenceUnitName" value="Restaurant"/>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect"/>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
<property value="true" name="showSql"/>
<property value="true" name="generateDdl"/>
<property name="databasePlatform" value="org.eclipse.persistence.platform.database.DerbyPlatform"/>
</bean>
</property>
<property name="jpaPropertyMap">
<map>
<entry key="eclipselink.weaving" value="false" />
</map>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.apache.derby.jdbc.EmbeddedDriver"/>
<property name="url" value="jdbc:derby:..//RestaurantDB1;create=true" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<tx:annotation-driven proxy-target-class="true"/>
</beans>
服务实施
@Named
public class KitchenStaffServiceImpl implements KitchenStaffService {
@Inject
private ItemDAO itemDAO;
@Inject
private OrderDAO orderDAO;
@Override
public List<Item> viewItems() {
return itemDAO.viewItems();
}
@Override
@Transactional
public void processItem(Item item) {
int i=item.getQuantity();
while(i>0){
try {
Thread.sleep(1000);
--i;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
item.setIsCooked(true);
itemDAO.saveItem(item);
System.out.println(item.getId());
List<Item> list = item.getOrder().getListOfDishes();
if(list.stream().allMatch(t -> t.getIsCooked()==true)){
Order ord = item.getOrder();
ord.setStatus(StatusOfDelivery.READY_FOR_SHIPMENT);
orderDAO.saveOrder(ord);
}
}
}
DAO 实现
@Repository
public class ItemDAOImpl implements ItemDAO{
@PersistenceContext
private EntityManager em;
@Override
public void saveItem(Item item){
if(item.getId()==0){
em.persist(item);
}else
em.merge(item);
}
}
使用方法 saveOrder(Order order) 的 OrderDAO 实现与 ItemDAO 相同 (persist()/merge())
提前感谢任何提议
您正在呼叫
OrderDAOImpl.saveOrder();
来自方法
DeliveryStaffServiceImpl.changeStatusOfOrder();
但在示例中,您显示 @Transactional
注释放在不相关的方法 KitchenStaffServiceImpl.processItem()
上。很可能,您需要 DeliveryStaffServicleImpl
上的 @Transactional
注释。