@PersistenceContext无法找到记录

时间:2019-04-24 08:42:10

标签: hibernate spring-data-jpa

我有一个简单的PoC来测试JPA实施。

@Entity
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Getter private Long id;
    private String firstName;

    @Getter @Setter private String lastName;

    protected Customer() {
    }

    public Customer(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}

@Repository
public class ConcreteCustomerRepository {

    @PersistenceContext
    protected EntityManager entityManager;

    void save(Customer customer) {
        entityManager.persist(customer);
    }

    List<Customer> findByLastName(String lastName) {
        return entityManager.createQuery("from Customer c where c.lastName = :name")
                .setParameter("name", lastName).getResultList();
    }

    void saveWithIdInTheObjectAndOldLastName(Customer customer, String oldName) {
        Query query = entityManager.createQuery(
                "update Customer c set c.lastName = :ln where c.id = :id and c.lastName = :oln")
                .setParameter("ln", customer.getLastName())
                .setParameter("id", customer.getId())
                .setParameter("oln", oldName);

        if (query.executeUpdate() == 0)
        {
            throw new NoRowUpdatedException();
        }
    }
}

具有如下配置:

@Configuration
@EnableTransactionManagement
@PropertySource("classpath:application.properties")
public class TestConfig {

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource, Environment env) {
        LocalContainerEntityManagerFactoryBean em
                = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource);
        em.setPackagesToScan(new String[] { "com.company.dao.hello.model" });

        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();

        em.setJpaVendorAdapter(vendorAdapter);
        em.setJpaProperties(additionalProperties(env));

        return em;
    }

    @Bean
    public DataSource dataSource(@Value("${database.driver}") String dsDriverClassName,
                                 @Value("${database.url}") String dsUrl,
                                 @Value("${database.username}") String dsUsername,
                                 @Value("${database.password}") String dsPassword){
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(dsDriverClassName);
        dataSource.setUrl(dsUrl);
        dataSource.setUsername(dsUsername);
        dataSource.setPassword(dsPassword);
        return dataSource;
    }

    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(emf);

        return transactionManager;
    }

    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
        return new PersistenceExceptionTranslationPostProcessor();
    }

    Properties additionalProperties(Environment env) {
        Properties properties = new Properties();
        properties.setProperty(AvailableSettings.HBM2DDL_AUTO, "create-drop");
        properties.setProperty(AvailableSettings.DIALECT, env.getRequiredProperty("database.vendorTypeRaw"));
        properties.setProperty(AvailableSettings.SHOW_SQL, "true");
        properties.setProperty(AvailableSettings.FORMAT_SQL, "true");

        return properties;
    }

    @Bean
    public PropertySourcesPlaceholderConfigurer configurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }

    @Bean
    public ConcreteCustomerRepository repository() {
        return new ConcreteCustomerRepository();
    }
}

以下测试因抛出NoRowUpdatedException而失败:

@ContextConfiguration(classes = {TestConfig.class})
@RunWith(SpringJUnit4ClassRunner.class)
@Transactional
public class SimpleRepositoryTest {

    @Autowired
    private ConcreteCustomerRepository repository;

    @Test
    public void shouldBeAbleToUpdateWithAdditionalAttribute() throws InterruptedException {
        Customer c = new Customer("M", "Ichsan");
        repository.save(c);

        Customer retrieved = repository.findByLastName("Ichsan").get(0);
        retrieved.setLastName("Jackson");
        repository.saveWithIdInTheObjectAndOldLastName(retrieved, "Ichsan"); // Fails here!

        retrieved = repository.findByLastName("Jackson").get(0);
        assertThat(retrieved.getLastName(), equalTo("Jackson"));
    }
}

但是,如果我使存储库使用@PersistentUnit而不是@PersistenceContext,它会起作用:

@Repository
public class ConcreteCustomerRepository {

    @PersistenceUnit
    private EntityManagerFactory emf;

    void save(Customer customer) {
        EntityManager entityManager = emf.createEntityManager();
        entityManager.getTransaction().begin();

        entityManager.persist(customer);

        entityManager.getTransaction().commit();
    }

    List<Customer> findByLastName(String lastName) {
        EntityManager entityManager = emf.createEntityManager();
        return entityManager.createQuery("from Customer c where c.lastName = :name")
                .setParameter("name", lastName).getResultList();
    }

    void saveWithIdInTheObjectAndOldLastName(Customer customer, String oldName) {
        EntityManager entityManager = emf.createEntityManager();
        entityManager.getTransaction().begin();

        Query query = entityManager.createQuery(
                "update Customer c set c.lastName = :ln where c.id = :id and c.lastName = :oln")
                .setParameter("ln", customer.getLastName())
                .setParameter("id", customer.getId())
                .setParameter("oln", oldName);

        if (query.executeUpdate() == 0)
        {
            throw new NoRowUpdatedException();
        }

        entityManager.getTransaction().commit();
    }
}

我听说建议使用@PersistentContext,但遗憾的是它不起作用。这是怎么回事?

0 个答案:

没有答案