使用CrudRepository保留JPA实体

时间:2014-06-28 18:20:34

标签: mysql hibernate spring-mvc jpa-2.0 spring-data

通过CrudRepository保存JPA实体时遇到问题。它似乎返回传递给它的原始对象,而不将对象持久化到数据库。我知道这不是正确的方法,但出于测试目的,如果我在保存之前放置一个TransactionSynchronizationManager实例,它似乎仍然正确。这让我觉得交易管理器可能存在问题吗?

此外,如果我丢弃存储库并使用实体管理器(em),我会得到相同的结果,但是如果我调用em.flush(),我会得到异常" Transactionrequiredexception,No Transaction in Progress&#34 ;。

@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;
        }

    }

我上传了一个隔离异常的小项目。压缩并运行AccountTester.class http://www14.zippyshare.com/v/81636273/file.html

2 个答案:

答案 0 :(得分: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);

}

Original for reference

您需要使用@Repository(不是您的服务)标记Spring Data JPA存储库。 See here

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);
    }

}

Original for reference

请注意从服务中删除@Repository的更改(需要在Spring Data JPA存储库界面上)并使用accountRepository在您的save(...)方法中保留实体。< / p>

不确定为什么要尝试使用EntityManagerFactory创建新的EntityManager(如果您确实需要EntityManager个实例,则应该注入已配置的EntityManager,不是工厂)。这也恰好是您TransactionRequiredException的原因。

Anyhoo,当你可以使用你的存储库来保存你的实体时,为什么还要烦恼呢。 现在运行AccountTester会产生所需的功能:

...
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

答案 1 :(得分:0)

事实证明,应用程序中有多个@EnableTransactionManagement(mode = AdviceMode.ASPECTJ)注释。这是导致问题的原因,在删除Neo4j @Configuration Class中的问题后,问题就消失了。