Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Spring数据-实体未更新_Java_Hibernate_Jpa_Spring Data_Dirty Checking - Fatal编程技术网

Java Spring数据-实体未更新

Java Spring数据-实体未更新,java,hibernate,jpa,spring-data,dirty-checking,Java,Hibernate,Jpa,Spring Data,Dirty Checking,我有一个实体Customer和Spring数据接口CustomerRepository,如下所示: public interface CustomerRepository extends JpaRepository<Customer,Long> { Customer findCustomerByName(String name); } 我不明白为什么它会打印:Customer(id=1,name=John,姓氏=Smith) 据我所知,Hibernate使用脏检查机制来更新

我有一个实体
Customer
和Spring数据接口
CustomerRepository
,如下所示:

public interface CustomerRepository extends JpaRepository<Customer,Long> {
    Customer findCustomerByName(String name);
}
我不明白为什么它会打印:Customer(id=1,name=John,姓氏=Smith

据我所知,Hibernate使用
脏检查
机制来更新处于持久状态的实体。因此,在事务结束时,更改后的姓氏应该传播到数据库中(但事实并非如此——即使我将此代码分为两个
@Transactional
方法)。我做错什么了吗?每次更改后,我真的需要手动保存对象吗?为什么数据库中的姓氏字段未更新

@RunWith(SpringRunner.class)
@SpringBootTest
public class CustomerRepoTest {
    @Autowired
    private CustomerRepository customerRepository;

    @Test
    //NOTE: No @Transactional
    public void testSaveFails() throws Exception {
        customerRepository.save(new Customer("John", "Smith"));
        Customer john = customerRepository.findCustomerByName("John");
        john.setSurname("Barton");
        customerRepository.flush();
        customerRepository.findAll().forEach(System.out::println);
    }

    @Test
    @Transactional
    public void testSaveWorks() throws Exception {
        customerRepository.save(new Customer("John", "Smith"));
        Customer john = customerRepository.findCustomerByName("John");
        john.setSurname("Barton");
        //customerRepository.flush(); Flush is not necessary
        customerRepository.findAll().forEach(System.out::println);
    }

}
解释: Hibernate保留它在事务期间加载的对象的缓存。 执行find方法时,将新加载对象的id与此缓存中对象的id进行比较,如果找到,则使用缓存版本

  • 这就是为什么带有
    @Transactional
    的版本可以工作的原因
  • 此外,它还解释了为什么不需要刷新—它只强制在事务结束之前写入值
如果错过了
@Transactional
(假设底层事务自动提交,最有可能是这种情况):

  • 在一个事务中保存实体
  • 使用findCustomerByName重新加载它,但它会立即分离
  • 修改分离的实体-不保存
  • 您在另一个事务中重新加载条目,但看不到更新

因为您从不使用barton保存,也不创建2个对象,请注意@Transactional仅在公共方法上有效。
@RunWith(SpringRunner.class)
@SpringBootTest
public class CustomerRepoTest {
    @Autowired
    private CustomerRepository customerRepository;

    @Test
    //NOTE: No @Transactional
    public void testSaveFails() throws Exception {
        customerRepository.save(new Customer("John", "Smith"));
        Customer john = customerRepository.findCustomerByName("John");
        john.setSurname("Barton");
        customerRepository.flush();
        customerRepository.findAll().forEach(System.out::println);
    }

    @Test
    @Transactional
    public void testSaveWorks() throws Exception {
        customerRepository.save(new Customer("John", "Smith"));
        Customer john = customerRepository.findCustomerByName("John");
        john.setSurname("Barton");
        //customerRepository.flush(); Flush is not necessary
        customerRepository.findAll().forEach(System.out::println);
    }

}