目录
JPA
JPA是Java Persistence API的简称,中文名为Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。
JPA包括3个方面的内容:
- 一套API标准。在javax.persistence的包下面,用来操作实体对象,执行CRUD操作,框架在后台替代程序员完成所有的事情,从而不用写JDBC和SQL代码。
- 面向对象的查询语言。Java Persistence Query Language JPQL。这是持久化操作中很重要的一个方面,通过面向对象而非面向数据库的查询语言查询数据,避免程序的SQL语句紧密耦合。
- ORM(object/relational metadata) 元数据的映射。JPA支持XML和JDK5.0注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架据此将实体对象持久化到数据库表中。
jpa 并不是一个框架,是一类框架的总称,比如持久层框架 Hibernate 是 jpa 的一个具体实现。
Spring Data
Spring Data是一个非常大的伞形项目,有很多的子项目,子项目大多都关注对不同的数据库类型进行数据持久化。
比较流行的Spring Data项目:
- Spring Data JPA :基于关系型数据库进行JPA持久化
- Spring Data MongoDB : 持久化到Mongo文档数据库
- Spring Data Neo4j : 持久化到Neo4j图数据库
- Spring Data Redis : 持久化到Redis key-value存储
- Spring Data Cassandra : 持久化到Cassandra数据库
ORM框架
对象-关系映射(Object/Relation Mapping,简称ORM)
MyBatis
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
Hibernate
Hibernate ORM使开发人员可以更轻松地编写其数据超出应用程序进程寿命的应用程序。作为对象/关系映射(ORM)框架,Hibernate关注数据持久性,因为它适用于关系数据库(通过JDBC)。
Hibernate还是Java Persistence API(JPA)规范的实现。这样,它可以轻松地在支持JPA的任何环境中使用,包括Java SE应用程序,Java EE应用程序服务器,Enterprise OSGi容器等。
Hibernate使您可以遵循自然的面向对象习惯用法(包括继承,多态性,关联,组合和Java集合框架)来开发持久类。Hibernate不需要接口或基类来用于持久类,并使任何类或数据结构都可以持久化。
Hibernate支持延迟初始化,多种获取策略以及具有自动版本控制和时间戳的乐观锁定。Hibernate不需要特殊的数据库表或字段,并在系统初始化时而不是在运行时生成大量SQL。
从开发人员的生产力和运行时性能方面来说,Hibernate始终提供优于纯JDBC代码的性能。
Spring Data JPA
可以理解为JPA规范的再次封装,底层还是使用了Hibernate的JPA实现,引用JPQL查询语言,属于Spring整个生态体系的一部分。
比较
MyBatis 也是十分优秀的框架,该框架是专注 sql 语句的,使用Spring Data JPA几乎不需要写什么SQL代码。
Spring Data JPA
主要类
Repository、CrudRepository接口
Spring Data存储库抽象中的中央接口是Repository。
它需要域类以及域类的ID类型作为类型参数来进行管理。
该接口主要用作标记接口,以捕获要使用的类型并帮助您发现扩展该接口的接口。
该CrudRepository接口为正在管理的实体类提供复杂的CRUD功能。
PagingAndSortingRepository接口
在之上CrudRepository,有一个PagingAndSortingRepository抽象,它添加了其他方法来简化对实体的分页访问:
……
更多建议去翻官网文档,
常用的基础注解
@Entity
将类声明为JPA实体,定义对象将JPA管理的实体,将映射到指定的数据库表
@Id
JPA实体的id属性需要用这个注解,以便于将其指定为数据库中唯一标识该实体的属性
定义属性为数据库的主键
@Table
指定数据库的表名
@IdClass
利用外部类的联合主键
@GeneratedValue
主键生成策略,有4个值,通过表生成主键、通过序列生成主键、采用数据库ID自增长、JPA自动选择合适的策略(默认选项)
简单案例
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.PrePersist;
import javax.persistence.Table;
import javax.validation.constraints.Digits;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import org.hibernate.validator.constraints.CreditCardNumber;
import lombok.Data;
@Data
@Entity
@Table(name="Taco_Order")
public class Order implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private Date placedAt;
@NotBlank(message="Delivery name is required")
private String deliveryName;
@NotBlank(message="Street is required")
private String deliveryStreet;
@NotBlank(message="City is required")
private String deliveryCity;
@NotBlank(message="State is required")
private String deliveryState;
@NotBlank(message="Zip code is required")
private String deliveryZip;
@CreditCardNumber(message="Not a valid credit card number")
private String ccNumber;
@Pattern(regexp="^(0[1-9]|1[0-2])([\\/])([1-9][0-9])$",
message="Must be formatted MM/YY")
private String ccExpiration;
@Digits(integer=3, fraction=0, message="Invalid CVV")
private String ccCVV;
@ManyToMany(targetEntity=Taco.class)
private List<Taco> tacos = new ArrayList<>();
public void addDesign(Taco design) {
this.tacos.add(design);
}
@PrePersist
void placedAt() {
this.placedAt = new Date();
}
}
import org.springframework.data.repository.CrudRepository;
import com.example.demo.Order;
public interface OrderRepository
extends CrudRepository<Order, Long> {
}
import com.example.demo.jdbcdata.OrderRepository;
@Controller
@RequestMapping("/orders")
@SessionAttributes("order")
public class OrderController {
private OrderRepository orderRepo;
public OrderController(OrderRepository orderRepo) {
this.orderRepo = orderRepo;
}
@GetMapping("/current")
public String orderForm() {
return "orderForm";
}
@PostMapping
public String processOrder(@Valid Order order, Errors errors, SessionStatus sessionStatus) {
if (errors.hasErrors()) {
return "orderForm";
}
orderRepo.save(order);
sessionStatus.setComplete();
return "redirect:/";
}
}