TransactionRequiredException: транзакции с Spring Data JPA не выполняются - PullRequest
1 голос
/ 14 января 2012

I посмотрел вокруг на похожие проблемы, но не смог найти решение для этого:

У меня есть приложение Spring Data JPA , которое всякий раз, когда я пытаюсь совершать сделки, я получаю javax.persistence.TransactionRequiredException: no transaction is in progress.

Я полагаю, что это как-то связано с Менеджером транзакций или Фабрикой менеджеров сущностей, но не могу это понять.

Файлы контекста здесь (последние зарегистрированные здесь ), но вот часть, которая имеет значение:

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSourceMySQL" />
    <property name="persistenceUnitName" value="spring-jpa" />
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="generateDdl" value="true" />
            <property name="showSql" value="true" />
            <property name="database" value="MYSQL" />
        </bean>
    </property>
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
    <property name="dataSource" ref="dataSourceMySQL"/>
</bean>

<bean id="dataSourceMySQL" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/dbname"/>
    <property name="username" value="user"/>
    <property name="password" value="pass"/>
</bean>

<jpa:repositories base-package="com.simplecash.dal.repository" />

Пример репозитория здесь , а затем создал фабрику репозитариев здесь , в которой я не уверен, если мне нужно ... Затем используйте его здесь (строка 34).

public void populateWithTestData() {

    Bank bank = new Bank();
    bank.setName("ContentName");
    bank.setCode("ContentCode");

    RepositoryFactory.getEntityManager().getTransaction().begin();
    BankRepository bankRepository = RepositoryFactory.getRepository(BankRepository.class);
    bankRepository.save(bank);
    bankRepository.flush();
    RepositoryFactory.getEntityManager().getTransaction().commit();
}

пара вещей выше, но я пытался это исправить и не могу:

  1. Транзакции Begin и Commit являются явными.
  2. bankRepository должно быть @Autowired, но когда я это делаю, я получаю null. Тем не менее, в этот тестовый сценарий это Autowired и работает.

Кто-нибудь сталкивался с подобной проблемой и знает, что происходит? Спасибо большое за то, что нашли время, чтобы прочитать это. Надеюсь, что ответ на этот вопрос поможет другим людям.

Ответы [ 4 ]

3 голосов
/ 14 января 2012

Оба ответа, представленные здесь, предлагают хорошие моменты (использование инъекций для получения прокси-компонентов и использование транзакций-аннотаций), однако я уверен, что для работы транзакций, управляемых аннотациями (@Transactional), необходимо добавитьСледующее в вашей xml-конфигурации:

<tx:annotation-driven transaction-manager="transactionManager"/>

Также убедитесь, что добавили пространство имен tx в ваш bean-тег:

<beans
  <!-- SNIP, other namespaces -->
xmlns:tx="http://www.springframework.org/schema/tx"
  xsi:schemaLocation="
  <!-- SNIP, other locations -->
  http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
2 голосов
/ 10 марта 2013

У меня была похожая проблема при объединении spring-batch и spring-jpa. В моем пакетном XML у меня была эта строка:

<bean id="transactionManager" class="org.springframework.batch.support.transaction.ResourcelessTransactionManager"/>

, что вызвало ошибку, поскольку JPA требуется PlatformTransactionManager.

2 голосов
/ 14 января 2012
  • Явные транзакции Begin и Commit являются явными.

Что Spring делает с вашими компонентами репозитория (например, BankRepository), он создает прокси вокруг него итогда он готов быть введенным другим соавторам, что в вашем случае DatabaseManagerDAO.Однако, если вы создаете объект самостоятельно, как и вы:

BankRepository bankRepository = RepositoryFactory.getRepository(BankRepository.class);

Вместо ожидаемого прокси-сервера Spring (который уже выполняет управление транзакциями для вас), вы получаете простой объект, который ничего не знает за его пределами.немедленное объявление.

Вместо этого вам нужно довериться Spring , чтобы выполнить сантехнику за вас, и просто ввести боб bankRepository в DatabaseManagerDAO (хотя я этого не делаюдействительно думаю, что вам нужны и DAO, и Repository, поскольку эти термины действительно означают одно и то же:)

  • Фабрика репозитория здесь, в которой я не уверен, если мне нужно ...

Нет необходимости в другой абстракции.Просто вставьте его как компонент в любой компонент, в котором он нуждается.

  • bankRepository должно быть @Autowired, но когда я это делаю, я получаю null.Тем не менее, в этом тестовом примере он имеет автоматическую связь и работает.

В случае, если работает , вы запускаете тест с AbstractTransactionalJUnit4SpringContextTests,который знает о bean-компоненте bankRepository, следовательно, автоматически связывает его.В вашем DatabaseManagerDAO я не вижу ни автоматического подключения, ни установщика для bankRepository, фактически вы создаете его вручную с завода.

РЕДАКТИРОВАТЬ, чтобы отвечать на комментарии

Что jpa:repositories в вашей конфигурации XML действительно делает => он сканирует пакет и создает бины Spring для каждого компонента, который либо аннотирован как @Repository, либо реализует интерфейс Repository.

Имея это в видудля использования BankRepository в вашем DatabaseManagerDAO репозитории необходимо ввести его.Вы можете сделать это через «autowiring»:

@Service
public class DatabaseManagerDAO {

    @Autowired
    BankRepository bankRepository;
    ... 
}

вместо того, чтобы вручную создавать его на своем заводе.

Опять же, DatabaseManagerDAO в вашем случае, вероятно, является услугой (@Service), а не DAO, но я оставлю на ваше усмотрение решение по этому вопросу.

Обратите внимание, что * Spring должен также загружать DatabaseManagerDAO, чтобы работала автоматическая разводка, поэтому убедитесь, что у него есть одна из аннотаций Spring (@Service / @Component) при сканировании пакета (например, <context:component-scan base-package="org.example"/>)).

1 голос
/ 14 января 2012

Я думаю, что в вашей настройке транзакции управляются JTA, поэтому вы не можете явно запускать / останавливать их (т.е. em.getTransaction (). Begin () не будет работать).Попробуйте сообщить Spring, что вы хотите, чтобы определенный метод был частью транзакции (управляемой JTA) с помощью аннотации, например:

@Transactional
public void populateWithTestData() {
   //...    
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...