Spring - Нет EntityManager с реальной транзакцией, доступной для текущего потока - не может надежно обработать вызов "persist"
Я получаю эту ошибку при попытке вызвать метод "persist" для сохранения модели сущности в базу данных в моем веб-приложении Spring MVC. Невозможно найти какую-либо почту или страницу в Интернете, которая может относиться к этой конкретной ошибке. Кажется, что что-то не так с EntityManagerFactory bean, но я довольно новичок в программировании Spring, поэтому для меня кажется, что все инициализировано отлично и согласно различным учебным статьям в Интернете.
диспетчер-servlet.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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/data/repository
http://www.springframework.org/schema/data/repository/spring-repository-1.5.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.2.xsd">
<context:component-scan base-package="wymysl.Controllers" />
<jpa:repositories base-package="wymysl.repositories"/>
<context:component-scan base-package="wymysl.beans" />
<context:component-scan base-package="wymysl.Validators" />
<bean
class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean class="org.springframework.orm.hibernate4.HibernateExceptionTranslator"/>
<bean id="passwordValidator" class="wymysl.Validators.PasswordValidator"></bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@localhost:1521:xe" />
<property name="username" value="system" />
<property name="password" value="polskabieda1" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath:./META-INF/persistence.xml" />
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.H2Dialect" />
<property name="showSql" value="true" />
<property name="generateDdl" value="false" />
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.max_fetch_depth">3</prop>
<prop key="hibernate.jdbc.fetch_size">50</prop>
<prop key="hibernate.jdbc.batch_size">10</prop>
</props>
</property>
</bean>
<mvc:annotation-driven />
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:messages" />
</bean>
<bean name="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/jsp/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
<mvc:resources mapping="/resources/**" location="/resources/" />
<mvc:resources mapping="/resources/*" location="/resources/css/"
cache-period="31556926"/>
</beans>
RegisterController.java
@Controller
public class RegisterController {
@PersistenceContext
EntityManager entityManager;
@Autowired
PasswordValidator passwordValidator;
@InitBinder
private void initBinder(WebDataBinder binder) {
binder.setValidator(passwordValidator);
}
@RequestMapping(value = "/addUser", method = RequestMethod.GET)
public String register(Person person) {
return "register";
}
@RequestMapping(value = "/addUser", method = RequestMethod.POST)
public String register(@ModelAttribute("person") @Valid @Validated Person person, BindingResult result) {
if(result.hasErrors()) {
return "register";
} else {
entityManager.persist(person);
return "index";
}
}
Ответы
Ответ 1
У меня была та же проблема, и я аннотировал метод как @Transactional
, и он работал.
UPDATE: проверяя документацию spring, похоже, по умолчанию PersistenceContext имеет тип Transaction, поэтому метод должен быть транзакционным (http://docs.spring.io/spring/docs/current/spring-framework-reference/html/orm.html):
Аннотация @PersistenceContext имеет необязательный тип атрибута, который по умолчанию имеет значение PersistenceContextType.TRANSACTION. Это значение по умолчанию что вам нужно для получения общего прокси-сервера EntityManager. альтернатива, PersistenceContextType.EXTENDED, является полностью разное дело: это приводит к так называемому расширенному EntityManager, который не является потокобезопасным и, следовательно, не должен использоваться одновременно доступный компонент, такой как Spring управляемый синглтон bean. расширенный EntityManager должен использоваться только в компонентах stateful которые, например, находятся в сеансе, с жизненным циклом EntityManager не привязан к текущей транзакции, а скорее полностью до приложения.
Ответ 2
Я получил это исключение, пытаясь использовать специальный метод deleteBy в репозитории данных spring. Операция была предпринята из тестового класса JUnit.
Исключение не возникает при использовании аннотации @Transactional
на уровне класса JUnit.
Ответ 3
Эта ошибка заставила меня литься в течение трех дней, ситуация, с которой я столкнулась, вызвала ту же ошибку. Следуя всем советам, которые я смог найти, я играл с конфигурацией, но безрезультатно.
В конце концов я нашел его, разница, Службы, которую я выполнял, содержалась в общем банке, проблема оказалась AspectJ, не обрабатывая экземпляр службы тем же. По сути, прокси-сервер просто вызывал базовый метод без выполнения обычной магии Spring до вызова метода.
В итоге аннотация @Scope, помещенная на службу в соответствии с примером, решила проблему:
@Service
@Scope(proxyMode = ScopedProxyMode.INTERFACES)
@Transactional
public class CoreServiceImpl implements CoreService {
@PersistenceContext
protected EntityManager entityManager;
@Override
public final <T extends AbstractEntity> int deleteAll(Class<T> clazz) {
CriteriaDelete<T> criteriaDelete = entityManager.getCriteriaBuilder().createCriteriaDelete(clazz);
criteriaDelete.from(clazz);
return entityManager.createQuery(criteriaDelete).executeUpdate();
}
}
Метод, который я опубликовал, является методом удаления, но аннотации влияют на все методы сохранения таким же образом.
Я надеюсь, что этот пост поможет кому-то, кто боролся с той же проблемой при загрузке службы из банки
Ответ 4
У меня была та же ошибка, потому что я переключился с XML- на java-конфигурацию.
Дело в том, что я не перенес тег <tx:annotation-driven/>
, как предложил Стоун Фэн.
Поэтому я просто добавил @EnableTransactionManagement
, как предложено здесь
Настройка управляемых аннотациями транзакций spring в классе @Configuration, и теперь это работает
Ответ 5
У меня была та же проблема, и я добавил tx:annotation-driven
в applicationContext.xml
, и это сработало.
Ответ 6
boardRepo.deleteByBoardId(ID);
Столкнулся с той же проблемой. GOT javax.persistence.TransactionRequiredException: нет EntityManager с реальной транзакцией, доступной для текущего потока
Я разрешил это, добавив аннотацию @Transactional выше контроллера/службы.
Ответ 7
Для нас проблема сводилась к тем же настройкам контекста в нескольких файлах конфигурации. Убедитесь, что вы не дублировали следующее в нескольких файлах конфигурации.
<context:property-placeholder location="classpath*:/module.properties"/>
<context:component-scan base-package="...." />
Ответ 8
У меня была такая же ошибка при обращении к уже транзакционно-аннотированному методу из не-транзакционного метода внутри одного и того же компонента:
Before:
@Component
public class MarketObserver {
@PersistenceContext(unitName = "maindb")
private EntityManager em;
@Transactional(value = "txMain", propagation = Propagation.REQUIRES_NEW)
public void executeQuery() {
em.persist(....);
}
@Async
public void startObserving() {
executeQuery(); //<-- Wrong
}
}
//In another bean:
marketObserver.startObserving();
Я исправил ошибку, вызвав executeQuery() в компоненте с самостоятельной ссылкой:
Fixed version:
@Component
public class MarketObserver {
@PersistenceContext(unitName = "maindb")
private EntityManager em;
@Autowired
private GenericApplicationContext context;
@Transactional(value = "txMain", propagation = Propagation.REQUIRES_NEW)
public void executeQuery() {
em.persist(....);
}
@Async
public void startObserving() {
context.getBean(MarketObserver.class).executeQuery(); //<-- Works
}
}
Ответ 9
У меня был тот же код ошибки, когда я использовал @Transaction
на неправильном методе/уровне действия.
methodWithANumberOfDatabaseActions() {
methodA( ...)
methodA( ...)
}
@Transactional
void methodA( ...) {
... ERROR message
}
Я должен был разместить @Transactional
чуть выше метода methodWithANumberOfDatabaseActions()
, конечно.
Это решило сообщение об ошибке в моем случае.
Ответ 10
Я удалил режим из
<tx:annotation-driven mode="aspectj"
transaction-manager="transactionManager" />
чтобы сделать эту работу
Ответ 11
У меня была эта проблема в течение нескольких дней, и ничто из того, что я нашел где-либо в Интернете, помогло мне, я отправляю свой ответ здесь, если это помогает кому-то еще.
В моем случае я работал над микросервисом, вызванным удалением, и аннотация @Transactional на уровне сервиса не была удалена удаленным прокси.
Добавление класса делегата между словом service и dao и маркировка метода делегата как транзакционного исправления для меня.
Ответ 12
Это помогло нам, может быть, это может помочь другим в будущем. @Transaction
не работал для нас, но это сработало:
@ConditionalOnMissingClass("org.springframework.orm.jpa.JpaTransactionManager")