这是代码:
@Repository public interface AccountRepository extends JpaRepository<Account, Long> {}
Spring Data JPA项目中的JpaRepository。
这是测试代码:
public class JpaAccountRepositoryTest extends JpaRepositoryTest { @Inject private AccountRepository accountRepository; @Inject private Account account; @Test @Transactional public void createAccount() { Account returnedAccount = accountRepository.save(account); System.out.printf("account ID is %d and for returned account ID is %d\n", account.getId(), returnedAccount.getId()); } }
结果如下:
account ID is 0 and for returned account ID is 1
这是来自CrudReporsitory.save()javadoc的:
保存给定的实体。将返回的实例用于进一步的操作,因为保存操作可能已完全更改了实体实例。
这是来自Spring Data JPA的SimpleJpaRepository的实际代码:
@Transactional public T save(T entity) { if (entityInformation.isNew(entity)) { em.persist(entity); return entity; } else { return em.merge(entity); } }
因此,问题是为什么我们需要使用返回的实例而不是原始实例?(是的,我们必须这样做,否则我们将继续使用分离的实例,但是为什么)
原始的EntityManager.persist()方法返回void,因此我们的实例附加到持久性上下文。在将帐户保存到存储库时,是否发生一些代理魔术?它是Spring Data JPA项目的架构限制吗?
该接口的save(…)方法CrudRepository应该抽象为简单地存储一个实体,而不管它处于什么状态。因此,即使该存储区(如在JPA中一样)区分要存储的新实体,也不能公开实际的特定于存储区的实现。和现有的要更新。这就是为什么该方法实际上称为save(…)not create(…)或update(…)。我们从该方法返回一个结果,以实际上允许商店实现返回一个完全不同的实例,就像JPA在merge(…)被调用时可能返回的那样。
save(…)
CrudRepository
save(…)not create(…)
update(…)
merge(…)
因此,一般来说,对于实际实施要宽容(允许,宽容)更多是API决定,因此像我们所做的那样实施JPA方法。对传递的实体没有其他的代理消息传递。