如何在SpringBoot中使用Hibernate/JPA的@NaturalId?
第一步,在實體中標記你的業務欄位為@NaturalId:
@Entity public class Product implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; @NaturalId(mutable = false) @Column(nullable = false, updatable = false, unique = true, length = 50) private String code; @Override public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof Product)) { return false; } Product naturalIdProduct = (Product) o; return Objects.equals(getCode(), naturalIdProduct.getCode()); // including sku // return Objects.equals(getCode(), naturalIdProduct.getCode()) // && Objects.equals(getSku(), naturalIdProduct.getSku()); } @Override public int hashCode() { return Objects.hash(getCode()); // including sku // return Objects.hash(getCode(), getSku()); } @Override public String toString() { return "Product{" + "id=" + id + ", name=" + name + ", code=" + code + '}'; // including sku // return "Product{" + "id=" + id + ", name=" + name + ", code=" + code + ", sku=" + sku + '}'; } |
這裡的code欄位標記為@NaturalId,注意點:
對於非可變id,將列標記為@NaturalId(mutable = false)和@Column(nullable = false, updatable = false, unique = true, ...)
對於可變id,將列標記為@NaturalId(mutable = true)和@Column(nullable = false, updatable = true, unique = true, ...)
使用NaturalId重寫覆蓋equals()並hashCode()方法
第二步,需要定義@NoRepositoryBean介面(NaturalRepository),在其中定義兩個方法,命名findBySimpleNaturalId()和findByNaturalId()
@NoRepositoryBean public interface NaturalRepository<T, ID extends Serializable> extends JpaRepository<T, ID> { // use this method when your entity has a single field annotated with @NaturalId Optional<T> findBySimpleNaturalId(ID naturalId); // use this method when your entity has more than one field annotated with @NaturalId Optional<T> findByNaturalId(Map<String, Object> naturalIds); } |
第三步, 實現此介面(NaturalRepositoryImpl),其中依賴使用Hibernate, Session, bySimpleNaturalId()和 byNaturalId() 方法。
@Transactional(readOnly = true) public class NaturalRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements NaturalRepository<T, ID> { private final EntityManager entityManager; public NaturalRepositoryImpl(JpaEntityInformation entityInformation, EntityManager entityManager) { super(entityInformation, entityManager); this.entityManager = entityManager; } @Override public Optional<T> findBySimpleNaturalId(ID naturalId) { Optional<T> entity = entityManager.unwrap(Session.class) .bySimpleNaturalId(this.getDomainClass()) .loadOptional(naturalId); return entity; } @Override public Optional<T> findByNaturalId(Map<String, Object> naturalIds) { NaturalIdLoadAccess<T> loadAccess = entityManager.unwrap(Session.class).byNaturalId(this.getDomainClass()); naturalIds.forEach(loadAccess::using); return loadAccess.loadOptional(); } } |
第四步:在SpringBoot入口類中使用@EnableJpaRepositories(repositoryBaseClass = NaturalRepositoryImpl.class)註冊此實施為基類
@SpringBootApplication @EnableJpaRepositories(repositoryBaseClass = NaturalRepositoryImpl.class) public class NaturalIdApplication { |
第五步:對於實體,編寫一個經典的儲存庫:
@Repository public interface ProductRepository<T, ID> extends NaturalRepository<Product, Long>{ } |
第六步:在您的服務中注入此類並呼叫findBySimpleNaturalId()或findByNaturalId()
@SpringBootApplication @EnableJpaRepositories(repositoryBaseClass = NaturalRepositoryImpl.class) public class NaturalIdApplication { private static final Logger logger = Logger.getLogger(NaturalIdApplication.class.getName()); private final ProductRepository productRepository; public NaturalIdApplication(ProductRepository productRepository) { this.productRepository = productRepository; } public static void main(String[] args) { SpringApplication.run(NaturalIdApplication.class, args); } @Bean public ApplicationRunner init() { return args -> { // persist two products Product tshirt = new Product(); tshirt.setName("T-Shirt"); tshirt.setCode("014-tshirt-2019"); // tshirt.setSku(1L); Product socks = new Product(); socks.setName("Socks"); socks.setCode("012-socks-2018"); // socks.setSku(2L); productRepository.save(tshirt); productRepository.save(socks); Optional<Product> p1 = productRepository.findById(tshirt.getId()); // find by ID Optional<Product> p2 = productRepository.findBySimpleNaturalId(tshirt.getCode()); // find by natural ID if (p1.isPresent() && p2.isPresent()) { System.out.println("p1: " + p1.get()); System.out.println("p2: " + p2.get()); } else { System.out.println("Not found!"); } }; } } |
點選標題見原文
相關文章
- Hibernate/JPA中@OneToOne和@MapsId的使用
- 【SpringBoot Demo】MySQL + JPA + Hibernate + Springboot + Maven DemoSpring BootMySqlMaven
- SpringBoot 中 JPA 的使用Spring Boot
- 如何在Hibernate/JPA的實體和查詢中使用Java 8 Optional?Java
- SpringBoot使用JPASpring Boot
- 使用Hibernate、JPA、Lombok遇到的有趣問題Lombok
- JPA與hibernate-------JPA01
- 如何使用Hibernate/JPA的JPQL/HQL查詢提取?
- Hibernate/JPA中避免save()冗餘呼叫
- hibernate及SpringBoot整合Jpa實現對資料庫操作Spring Boot資料庫
- SpringBoot中JPA的學習Spring Boot
- 如何在Hibernate/JPA中配置具有兩個連線池的兩個資料來源
- Hibernate/JPA中如何合併實體集合?
- 淺談JPA二:聊聊Hibernate
- Spring Data JPA系列2:SpringBoot整合JPA詳細教程,快速在專案中熟練使用JPASpring Boot
- ElasticSearch與SpringBoot的整合與JPA方法的使用ElasticsearchSpring Boot
- 使用JPA和Hibernate呼叫儲存過程的最佳方法 - Vlad Mihalcea儲存過程
- 如何透過Hibernate/JPA在MySQL中儲存UTC時區?MySql
- JPA中@ElementCollection使用
- JPA和Hibernate的樂觀鎖與悲觀鎖
- springboot之jpa支援Spring Boot
- 使用JPA和Hibernate延遲載入實體屬性的最佳方法 - Vlad Mihalcea
- 如何透過Hibernate/JPA的SqlResultSetMapping生成需要資料的DTO?SQLAPP
- 多年教訓:根據DDD設計原則改變JPA/Hibernate的使用方式 - lorenzo
- SpringBoot整合Spring Data JPASpring Boot
- SpringBoot整合系列-整合JPASpring Boot
- Hibernate/JPA如何保證不生成多餘的SQL語句?SQL
- hibernate在JPA規範中在控制檯無法出現SQL語句SQL
- 使用SpringBoot JPA進行自定義的儲存及批量儲存Spring Boot
- SpringBoot資料訪問(二) SpringBoot整合JPASpring Boot
- 列舉型別在JPA中的使用型別
- 解決Spring Data JPA Hibernate的N+1問題的最佳方法Spring
- hibernate使用
- Oracle資料庫與JPA和Hibernate 結合使用時的九個高效能技巧 - vladmihalceaOracle資料庫
- 在Hibernate中關於Oracle sequence的使用KHOracle
- Hibernate之SchemaExport的使用Export
- 使用SpringBoot-JPA進行自定義的儲存及批量儲存Spring Boot
- springboot中RedisTemplate的使用Spring BootRedis