初识Spring Data与JPA Repository
来源:互联网 发布:vmware14运行ubuntu 编辑:程序博客网 时间:2024/06/05 02:11
1.JPA Repository
Java持久化API(JPA,JavaPersistenceAPI)是将Java对象持久化到关系型数据库的标准方式。
JPA包含两部分:用户将类匹配到关系表的映射模块以及访问对象、定义和执行查询等功能的EntityManager API。
Spring Data JPA 模块实现了Spring Data通用的Repository抽象从而进一步简化了存储的实现,这样在大多数场景无需手动实现存储类。
2.代码示例
我们领域模型中所有实体的基础类就是AbstractEntity,它使用了@MappedSuperclass来表示它本身并不是受管理的实体类,而是会由
其他的实体类进行扩展。也可以使用org.springframework.data.jpa.domain.AbstractPersistable来声明一个Long类型的id并告知持久化
提供商自动选择最合适的策略来生成主键。除此通过检查id属性实现了equals()和hashCode()方法,这样具有相同id的同种类型的实体会
被视为相等。
@MappedSuperclasspublic class AbstractEntity { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; public Long getId() { return id; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (this.id == null || obj == null || !(this.getClass().equals(obj.getClass()))) { return false; } AbstractEntity that = (AbstractEntity) obj; return this.id.equals(that.getId()); } @Override public int hashCode() { return id == null ? 0 : id.hashCode(); }}@Entity注解的普通类,如果为基础属性则不需要添加额外的注解,持久化商会自动将它们匹配到表的列上,如果需要自定义属性要到
持久化的列名,可以使用@Column注解
@Entitypublic class Address extends AbstractEntity { private String street, city, country; public Address(String street, String city, String country) { Assert.hasText(street, "Street must not be null or empty!"); Assert.hasText(city, "City must not be null or empty!"); Assert.hasText(country, "Country must not be null or empty!"); this.street = street; this.city = city; this.country = country; }}@Embeddable注解,会导致持久化供应商会将其属性放到包含它的类所对应的表中
@Embeddablepublic class EmailAddress { private static final String EMAIL_REGEX = "^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$"; private static final Pattern PATTERN = Pattern.compile(EMAIL_REGEX); @Column(name = "email") private String value; public EmailAddress(String emailAddress) { Assert.isTrue(isValid(emailAddress), "Invalid email address!"); this.value = emailAddress; } protected EmailAddress() { } public static boolean isValid(String candidate) { return candidate == null ? false : PATTERN.matcher(candidate).matches(); } @Override public String toString() { return value; }}@Column注解,unique=true来保证唯一性不能被多次利用。
@OneToMany注解来指明一个Customer可以拥有多个Address,在这个注解中,我们将级联类型(cascade)设置成了CascadeType.ALL
并为Address启用了子对象移除
@JoinColumn这会导致持久化厂商为Address对象后端所对应的表添加另外一列,这一列会来引用Customer,从而实现表的关联
@Entitypublic class Customer extends AbstractEntity { private String firstname, lastname; @Column(unique = true) private EmailAddress emailAddress; @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) @JoinColumn(name = "customer_id") private Set<Address> addresses = new HashSet<Address>(); public Customer(String firstname, String lastname) { Assert.hasText(firstname); Assert.hasText(lastname); this.firstname = firstname; this.lastname = lastname; } protected Customer() { } public void add(Address address) { Assert.notNull(address); this.addresses.add(address); }}@Column注解其目的是将其定义为强制性的属性,添加一个Map,它会用来存储额外的属性,不同产品之间这些属性有可能不同
@Entitypublic class Product extends AbstractEntity { @Column(nullable = false) private String name; private String description; @Column(nullable = false) private BigDecimal price; @ElementCollection private Map<String, String> attributes = new HashMap<String, String>();}
引入LineItem,它会持有对Product的引用以及Product的数量和购买价格,匹配Product属性时,我们使用了@ManyToOne注解,
会转化成LineItem对应表中的product_id列,这一列会用来指向Product
@Entitypublic class LineItem extends AbstractEntity { @ManyToOne private Product product; @Column(nullable = false) private BigDecimal price; private int amount;}LineItem的映射与前面看到的Customer和Address之间映射类似。Order会自动对LineItem实例进行级联持久化操作。因此没有必要单独管理
LineItem的持久化生命周期,其他属性都是已经讨论过的多对一的关系。
下面是Order表的定义
@ManyToOne(optional = false)这能够保证方法传递进来的Address实例如果发生变化的话,不会关联影响到已经存在的订单
@Entity@Table(name = "Orders")public class Order extends AbstractEntity { @ManyToOne(optional = false) private Customer customer; @ManyToOne private Address billingAddress; @ManyToOne(optional = false, cascade = CascadeType.ALL) private Address shippingAddress; @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) @JoinColumn(name = "order_id") private Set<LineItem> lineItems = new HashSet<LineItem>();}3.再来看下Spring Data
首先看下Spring Data如何为领域模型实现数据访问层,通过Spring DataRepository方式会创建一个CustomerRepository实例
下面是使用JPA来持久化前述的实体,来针对我们的存储的实现
public interface CustomerRepository extends Repository<Customer, Long> { Customer findOne(Long id); Customer save(Customer customer); Customer findByEmailAddress(EmailAddress emailAddress);}findOne()和save()方法都依靠SimpleJpaRepository来实现,实际上就是这个类的实例支撑了SpringData基础设施所创建的代理
findByEmailAddress()这是Spring Data JPA启动时就需要探查这个方法并试图根据它来衍生出查询。
ProductRepository
public interface ProductRepository extends CrudRepository<Product, Long> { /** * Returns a {@link Page} of {@link Product}s having a description which contains the given snippet. * * @param description * @param pageable * @return */ Page<Product> findByDescriptionContaining(String description, Pageable pageable); /** * Returns all {@link Product}s having the given attribute. * * @param attribute * @return */ @Query("select p from Product p where p.attributes[?1] = ?2") List<Product> findByAttributeAndValue(String attribute, String value);}
- 初识Spring Data与JPA Repository
- Spring Data jpa Repository
- Spring Data JPA Repository
- Spring Data Jpa ---- repository
- 测试Spring Data JPA的repository
- 初识spring boot和spring data jpa
- Spring技术内幕之Spring Data JPA-自定义Repository实现
- spring data jpa 与 jpa的区别
- Spring Data JPA: 为所有Repository添加自定义方法
- Spring Data JPA: 为单个Repository添加自定义方法
- Spring Data JPA Entity Repository 多路径配置
- Spring Data JPA: 为所有Repository添加自定义方法
- Spring Data Jpa 自定义 Repository EntityManager is null
- Spring Data JPA(1)--Repository和CrudRepository接口
- data.jpa.repository 数据库查询
- Spring Data JPA初探(开发与配置)
- Spring Data JPA初探(开发与配置)
- Spring Data JPA 与 MyBatis简单对比
- 某公司iOS开发笔试题
- oracle数据库listener开启和关闭trace文件的方法
- 脱壳_esp定律原理
- 虚拟机类加载机制
- Mac小技巧之zip加密
- 初识Spring Data与JPA Repository
- 我国关税
- NSUnknownKeyException
- SQL Server函数大全(三)----Union与Union All的区别
- 创建SessionFactory的方式
- 数据结构实验之链表六:有序链表的建立
- 使用Webpack打包单页应用的正确姿势
- ZCMU-1162-松哥的素数
- 改变ogg抽取进程检查点文件中的检查点