【问题标题】:Persisting JPA Entity using CrudRepository使用 CrudRepository 持久化 JPA 实体
【发布时间】:2014-06-28 18:20:34
【问题描述】:

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

此外,如果我丢弃存储库并使用实体管理器 (em),我会得到相同的结果,但是如果我调用 em.flush(),我会收到异常“Transactionrequirexception,没有进行中的事务”。

@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

【问题讨论】:

  • 您没有在save 之前打开会话。是吗?
  • 如果放置完整的堆栈跟踪非常有帮助。
  • 没有 Stacktrace。失败没有错误
  • 我认为您正在尝试 userRepository.save(user); 而不打开 Hibernate 会话和 trnsaction 至少这是您收到“No Transaction in Progress”错误的原因。
  • 我在 @Config 类中有 @EnableTransactionManagement(mode=AdviceMode.ASPECTJ) 注解。

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


【解决方案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存储库接口上)和使用accountRepositorysave(...)方法中持久化您的实体的变化。

不知道您为什么要尝试使用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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 2017-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-16
      • 2011-12-22
      • 2013-02-17
      相关资源
      最近更新 更多