定义
- JPA:Java Persistence API, 一套规范, 用于对象持久化的API. 内部由接口和抽象类组成 (通过 JDK 5.0 注解描述对象和表的映射关系),底层需要 Hibernate 作为其实现类完成数据持久化工作.
- Hibernate是一套成熟的 ORM 开放源代码的对象关系映射框架,将 POJO 与数据库表建立映射关系,而且 Hibernate 实现了 JPA 规范,所以也可以称 Hibernate 为 JPA的一种实现方式,我们使用 JPA 的 API 编程,意味着站在更高的角度上看待问题(面向接口编程)。Hibernate 可以自动生成 SQL 语句,自动执行,使得 Java 程序员可以随心所欲的使用对象编程思维来操纵数据库
- Spring Data JPA是 Spring 提供的一套对 JPA 操作更加高级的封装,是在 JPA 规范下的专门用来进行数据持久化的解决方案
使用
-
扫描 Entity 类、Repository 类会被自动扫描到并注册到 Spring 容器, 此时无需额外配置. 当不在同一包或不在子包下时, 需要分别通过在启动类上加注解 @EntityScan(basePackages = {“xxx.xxx”}) 允许多处有交集、@EnableJpaRepositories(basePackages = {“xxx.xxx”}) 允许多处不能交集 来分别指定 Entity、Repository 类的包名 -
JPA 不用 @Repository
- Spring 通过扩展 Repository 接口来识别存储库, 接口仅仅是一个标识, 表明任何继承它的均为仓库接口类
- @NoRepositoryBean 注释是为了防止 Spring 将 Repository 扩展接口(如 CrudRepository) 视为存储库
- 最好搭配 @Resource 注解注入
spring 有两种方式识别dao层,一种是注解的 @Repository,一种是继承 Repository 接口. 然而, 大多数框架都有自己的一套扫描规则, 实际不用使用 @Repository, 如 Mybatis 有@MapperScanner 扫描后自动注入
实体类注解
- @Entity:指定当前类为实体类
- @Table:指定实体类与数据库表映射关系
- schema:数据库名
- name:数据库表名
以上两个可以简写为: @Entity(“table_name”)
实体类属性
- @Id:当前主键字段
- @GeneratedValue:
- strategy:主键生成策略
- GenerationType.AUTO:auto_increment
- GenerationType.IDENTITY:表自增长,不支持Oracle
- GenerationType.SEQUENCE:序列生成主键,不支持MySQL
- GenerationType.TABLE:数据库表生成主键,框架借由表模拟序列生成主键
- @Column:建立实体类属性与数据库表字段映射关系,无此字段也会将字段映射到表列。当实体的属性与其映射的数据库表的列不同名时需要使用 @Column 标注说明
- name:指定映射的数据库表字段
- unique:是否唯一
- nullable:是否为空
- insertable:是否可插入
- updatable:是否可更新
- @Convert(converter = UserStatus.class):Entity中将任意对象映射为一个数据库字段
JPA命名查询原理
- 方法名解析原理:方法名中除了保留字(findBy、top、within等)外的部分以 and 为分隔符提取出条件单词,然后解析条件获取各个单词并看是否和 Entity 中的属性对应(不区分大小写进行比较)
get/find 与 by之间的字段会被忽略:getNameById == getById,会根据 id 查出整个Entity而不会只查 name 字段
JPA的 select 操作
Repository 中 @Query
JPA的 update 操作
Repository 中 @Modifying + @Query
JpaRepository
findOne()与getOne():findOne立即加载;getOne延迟加载
表关系
- 一对一:@OneToOne
- 一对多:@OneToMany
@OneToMany(targetEntity = LinkMan.class)
@JoinColumn(name = "外键名称" referencedColumnName = "cust_id")
private Set<LinkMan> linkMans = new HashSet<>();
@ManyToOne(targetEntity = Customer.class)
@JoinColumn(name = "外键名称" referencedColumnName = "cust_id")
private Customer customer;
@JoinColumn/@PrimaryKeyJoinColumn、@MapsId
-
@JoinColumn用来指定外键,其name属性指定该注解所在Entity对应的表的一个列名 -
外键属性不是主键的场景(第一种),用 @OneToOne/@ManyToOne + @JoinColumn 即可,为了简洁推荐不用@MapIds,示例见上面的school_id关联school id设置 -
外键属性是主键的场景(第二种),用 @OneToOne + @JoinColumn + @MapsId ,示例见上面的student id关联user id设置 -
在一对多或一对一的关系映射中,如果不表明mappedBy属性,默认是由本方维护外键。 -
将维护权交给多的一方. 在一的一方配置上 mappedBy 属性,将维护权交给多的一方来维护
条件查询
对于单字段的可以直接在方法名加Containing
@Query("select s from SchoolEntity s where s.customerId=?1 and (?2 is null or s.name like %?2% or s.bz like %?2% ) ")
List<User> getByUserId(String userId, Pageable pageable);
@Query( "select * from student where id in ?1", nativeQuery=true)
List<StudentEntity> myGetByIdIn(Collection<String> studentIds );
List<StudentEntity> getByIdIn( Collection<String> studentIds );
级联操作
用于有依赖关系的实体间(@OneToMany、@ManyToOne、@OneToOne)的级联操作:当对一个实体进行某种操作时,若该实体加了与该操作相关的级联标记,则该操作会传播到与该实体关联的实体(即对被级联标记的实体施加某种与级联标记对应的操作时,与该实体相关联的其他实体也会被施加该操作)。包括:
@OneToMany(targetEntity = LinkMan.class, cascade = CascadeType.ALL)
@JoinColumn(name = "外键名称" referencedColumnName = "cust_id")
private Set<LinkMan> linkMans = new HashSet<>();
- CascadeType.PERSIST:持久化,即保存
- CascadeType.REMOVE:删除当前实体时,关联实体也将被删除
- CascadeType.MERGE:更新或查询
- CascadeType.REFRESH:级联刷新,即在保存前先更新别人的修改:如Order、Item被用户A、B同时读出做修改且B的先保存了,在A保存时会先更新Order、Item的信息再保存。
- CascadeType.DETACH:级联脱离,如果你要删除一个实体,但是它有外键无法删除,你就需要这个级联权限了。它会撤销所有相关的外键关联
- CascadeType.ALL:上述所有
注:级联应该标记在One的一方 。如对于 @OneToMany的Person 和 @ManyToOne的Phone,若将- CascadeType.REMOVE标记在Phone则删除Phone也会删除Person,显然是错的。慎用CascadeType.ALL,应该根据业务需求选择所需的级联关系,否则可能酿成大祸
|