Сохраняющийся объект JPA с использованием CrudRepository

#mysql #hibernate #spring-mvc #jpa-2.0 #spring-data

#mysql #спящий режим #spring-mvc #jpa-2.0 #spring-данные

Вопрос:

Возникли проблемы с сохранением объекта JPA через CrudRepository. Кажется, что он возвращает исходный объект, который был передан ему, без сохранения объекта в базе данных. Я знаю, что это неправильный способ сделать это, но для целей тестирования, если я помещаю экземпляр TransactionSynchronizationManager перед сохранением, кажется, что он сохраняется правильно. Это наводит меня на мысль, что, возможно, есть проблема с менеджером транзакций?

Кроме того, если я удаляю репозиторий и использую Entity Manager (em), я получаю тот же результат, однако, если я вызываю em.flush(), я получаю исключение «Transactionrequiredexception, транзакция не выполняется».

 @Transactional
public class UserServiceImpl implements UserService{

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private EntityManagerFactory emf;

    @Override
    @Transactional(readOnly=false)
    public User save(User user) {

//  EntityManager em = emf.createEntityManager();
    //Object persists when adding following line
//  TransactionSynchronizationManager.bindResource(emf , new EntityManagerHolder(em)); 
        return  userRepository.save(user);
    }

}


@ComponentScan(basePackages = {"..."})
@Import(value={DataContextConfig.class,SecurityConfig.class})
public class AppConfig{
}

@Configuration
@ComponentScan(basePackages = {".."})
@Import(DataConfig.class)
public class DataContextConfig {

}

@Configuration
@EnableTransactionManagement(mode=AdviceMode.ASPECTJ)
@EnableJpaRepositories(value={"com.repository"}, entityManagerFactoryRef="entityManagerFactory", transactionManagerRef="transactionManager")
@PropertySource("classpath:data.properties")
public class DataConfig {
... 
    @Bean
    public PlatformTransactionManager transactionManager() { 
        JpaTransactionManager txManager = new JpaTransactionManager(); 
        txManager.setEntityManagerFactory((EntityManagerFactory) entityManagerFactory());
        return txManager; 
    }
    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {      
        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
        factory.setPackagesToScan("...");
        factory.setJpaPropertyMap(jpaProperties());
        factory.setDataSource(dbSource());
        return factory; 
    }


        @Bean
        public DriverManagerDataSource dbSource(){  
            DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
            driverManagerDataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
            driverManagerDataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
            driverManagerDataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
            driverManagerDataSource.setPassword(environment.getRequiredProperty("jdbc.password"));      
            return driverManagerDataSource;
        }

    }
  

Я загрузил небольшой проект, который изолирует исключение. Zip и запустить AccountTester.class http://www14.zippyshare.com/v/81636273/file.html

Комментарии:

1. Вы не открывали сеанс раньше save . а ты?

2. Очень полезно, если поставить полную трассировку стека.

3. Нет трассировки стека. Сбой без ошибок

4. Я думаю, что вы пытаетесь userRepository.save(user); без открытия сеанса гибернации и trnsaction, по крайней мере, по этой причине вы получаете ошибку `Транзакция не выполняется`.

5. У меня есть @EnableTransactionManagement(mode =AdviceMode. ASPECTJ) Аннотации внутри класса @Config.

Ответ №1:

Согласно вашему образцу проекта. Ниже приведены единственные классы, измененные, чтобы избежать вашей TransactionRequiredException: no transaction is in progress проблемы и успешно вставить учетную запись:

 package com.jpa.base.repository;

import com.jpa.base.entity.Account;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

@Repository
public interface AccountRepository extends CrudRepository<Account, Long> {

    public Account findByEmailAddress(@Param(value = "emailAddress") String emailAddress);

    public Account findByAccountId(@Param(value = "accountId") Long accountId);

}
  

Оригинал для справки

Вам нужно пометить свой репозиторий Spring Data JPA @Repository (не ваш сервис). Смотрите здесь

 package com.jpa.base.service.impl;

import com.jpa.base.entity.Account;
import com.jpa.base.repository.AccountRepository;
import com.jpa.base.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service("accountService")
public class AccountServiceImpl implements AccountService {

    @Autowired
    private AccountRepository accountRepository;

    @Override
    @Transactional(readOnly = true)
    public Account findByAccountId(Long accountId) {
        return accountRepository.findByAccountId(accountId);
    }

    @Override
    @Transactional(readOnly = true)
    public Account findByEmailAddress(String emailAddress) {
        return accountRepository.findByEmailAddress(emailAddress);
    }

    @Override
    @Transactional
    public Account save(Account account) {
        return accountRepository.save(account);
    }

}
  

Оригинал для справки

Обратите внимание на изменения, связанные с удалением @Repository из службы (должно быть в вашем интерфейсе хранилища Spring Data JPA) и использованием accountRepository для сохранения вашей сущности в вашем save(...) методе.

Не уверен, почему вы пытались использовать EntityManagerFactory для создания нового EntityManager (если вам действительно нужен EntityManager экземпляр, вы должны просто ввести настроенный EntityManager , а не заводской). Это также является причиной вашего TransactionRequiredException .

В любом случае, зачем беспокоиться обо всем этом, когда вы можете просто использовать свой репозиторий для сохранения своей сущности. Запуск вашего AccountTester now обеспечивает желаемую функциональность:

 ...
Hibernate: insert into account (email_address, name, version) values (?, ?, ?)
INFO : com.jpa.base.entity.AccountTester - Account Saved: Account Id: 3, Email Address:james.brown@outlook.com, Name: James Brown, Version: 0
  

Ответ №2:

Оказывается, было несколько @EnableTransactionManagement(mode=AdviceMode.ASPECTJ) аннотации внутри приложения. Это было причиной проблемы, после удаления объекта в классе Neo4j @Configuration проблема исчезла.