ORM思想
主要目的:操作实体类就相当于操作数据库表
建立两个映射关系:
实体类和表的映射关系
实体类中属性与表中字段的映射关系
不再重点关注:sql语句
JPA规范
jpa规范,实现jpa规范,内部是由接口和抽象类组成
实体类
配置映射关系:
-
-
- 实体类和表的映射关系
- 实体类中属性和表中字段的映射关系
-
@Id :声明主键的配置
@Generated:配置主键的生成策略
strategy
GenerationType.IDENTITY:自增
*底层数据库必须支持自动增长(底层数据库支持的自动增长方式,对id自增)
GenerationType.SEQUENCE:序列,Oracle
*底层数据库必须支持序列
GenerationType.Table : jpa提供的一种机制,通过一张数据库表的形式帮助我们完成主键自增
GenerationType.AUTO: 有程序自动的帮助我们选择主键生成策略
@Column(columnDefinition = "int8")
name:数据库表中字段的名称
columnDefinition:
@Entity //声明实体类
@Table //配置实体类和表的映射关系 //name:配置数据库表的名称
@Table(name = "stdent")
package com.oceanPlatform.inner.cargo.entity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Data
@ApiModel(value = "student对象", description = "学生信息表")
@Table(name = "student")
public class StudentEntity {
/**
* @Id声明主键的配置
* @Generated(strategy = GenerationType.IDENTITY):配置主键的生成策略(自增) * @Column(columnDefinition = "int8")
* name:数据库表中字段的名称 * columnDefinition:
**/
@Id
@ApiModelProperty(value = "主键")
@Column(columnDefinition = "int8")
private Long id;
@ApiModelProperty(value = "附件路径")
@Column(columnDefinition = "varchar(255)")
private String file;
}
延迟加载(懒加载)getReference() 常用
得到的是一个动态代理对象
什么时候用,什么时候才会查询
立即加载 fine
SpringDataJpa
-
搭建环境
创建工程导入坐标
配置spring的配置文件
编写实体类,使用jpa注解配置映射关系
<!-- 数据库驱动-->
spring.datasource.driver-class-name=org.postgresql.Driver
<!-- 数据库连接-->
spring.datasource.url=jdbc:postgresql://127.0.0.1:5432/post spring.datasource.username=postgres spring.datasource.password=postgres
<!-- -->
spring.jpa.hibernate.ddl-auto=update
<!-- 是否显示SQL-->
spring.jpa.show-sql=false
<!-- 数据库方言:支持的特有语法-->
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQL9Dialect spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults = false
-
-
-
编写一个符合springDataJpa的Dao 层接口
-
-
Dao层接口规范
需要继承两个接口(JpaRepository,JpaSpecificationExecutor)
需要提供相应的泛型
JpaRepository
封装了基本的CRUD(增删改查)操作
JpaSpecificationExecutor
封装了复杂查询(分页)
@Repository
public interface StudentRepository extends JpaRepository<StudentEntity, Long>, JpaSpecificationExecutor {
@Modifying
@Query(value = "delete FROM student where id = ?1",nativeQuery = true)
void deleteAllById(long id);
Integer countById(Long id);
}
save: 保存或者更新
根据传递的对象是否存在主键id
如果没有id主键属性,保存
存在id主键,根据id查询数据库,更新数据
simpleJpaRepository
实现了JpaRepository接口,实现了JpaSpecificationExecutor接口
对基本的增删改查操作进行了封装
springdataJpa的运行过程和原理剖析
-
- 通过JDKDynamicAopProxy的invoke方法创建了一个动态代理对象
- SimpleJpaRepository当中封装了JPA的操作(借助JPA的api完成数据库的CRUD)
- 通过hibernate完成数据库操作(封装了jdbc)
@Transactional:保证getOne正常运行
findOne 与getOne
findOne:
em.find() :立即加载
getOne:
em.getReference() :延迟加载
复杂查询
- 借助接口中的定义好的方法完成查询
findOne(id):根据id查询
- jpql的查询方式
jpql:jpa query language(jpa查询语言)
特点:语法或关键字和SQL语句类似
查询的是类和类中的属性
需要将JPQL语句配置到接口方法上
-
- 特有的查询:需要在dao接口上配置方法
- 在新添加的方法上,使用注解的形式配置jpql查询语句
- 注解: @Query
代表的是进行查询
声明此方法用来进行更新操作
@Transactional
@Modifying
@Query(value = "update StudentEntity s set s.Stat = false where s.id = :id")
方法名约定:
findBy:查询
对象中的属性名(首字母大写);查询条件
findByStudentName 根据学生名查询
默认情况,使用 等于的方式查询
特殊的查询方式
在springdataJpa的运行阶段
会根据方法名进行解析 findBy from xxx(实体类)
属性名称 where studentName
Specifications动态查询
Specification:查询条件
实现Specification接口(提供泛型:查询的对象类型)
实现toPredicate方法(构造查询条件)
需要借助方法参数中的两个参数(
root:获取需要查询的两个参数
criteriaQuery
criteriaBuilder:构造查询条件,内部封装了很多的查询条件(模糊匹配,精准匹配)
equal :直接得到path对象(属性),然后进行比较即可
gt, lt, ge, like:得到path对象,然后根据path指定比较的参数类型,再去比较
指定参数类型,path.as(类型的字节码对象)
//分页参数设置
Pageable pageable = PageRequest.of(pagination.getCurrent() - 1, pagination.getPagesize(), sort);
private Specification<StudentEntity> queryCondition(StudentSearchModel queryModel) { return (Specification<StudentEntity>) (root, criteriaQuery, criteriaBuilder) -> { List<Predicate> predicates = new ArrayList<>();
//学号查询 equal:进行精准匹配(比较的属性,比较的属性的取值)
if (!StringUtils.isEmpty(queryModel.getStudentId())) { predicates.add(criteriaBuilder.equal(root.get("studentId"), queryModel.getStudentId())); }
//root.get("studentId") 获取属性
//学期开始查询
if (!StringUtils.isEmpty(queryModel.getTermStartDate())) { predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("termStartDate"), queryModel.getTermStartDate()));
}
return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
};
}
多表查询:
多表之间的关系和操作多表的操作步骤
表关系
一对一
一对多
一的一方:主表
多的一方:从表
外键:需要再从表上新建一列作为外键,它的取值来源于主表的主键
多对多
中间表:中间表中最少应该有两个字段组成,这两个字段作为外键指向两张表的主键,又组成了联合主键
实力类中的关系:
包含关系:可以通过实体类中的包含关系描述表关系
继承关系
- 一对一操作
- 多对多操作
配置一对多关系
//@Fetch(FetchMode.JOIN)
@OrderBy("sort ASC")
//CascadeType.PERSIST:级联新增(又称级联保存)
@OneToMany(cascade=CascadeType.ALL,orphanRemoval =
true,fetch=FetchType.LAZY,mappedBy="voyageId")
@NotFound(action = NotFoundAction.IGNORE)
private List<StudentEntity> studentEntities;
使用注解的形式配置多表关系
- 声明关系
@OnetoMany:配置一对多关系
targetEntity:对方对象的字节码对象
mappedBy="studentId":我的一对多映射参照对方属性,在一的一方放弃了外键的维护权
fetch=FetchType.EAGER:立即加载
fetch=FetchType.LAZY:延迟加载
配置外键(中间表)
@JoinColum:配置外键
name: 外键字段名称
referencedColumnName: 参照的主表的主键字段名称
@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="class_id")
//student_id字段作为外键
@ApiModelProperty(value = "班级id")
private ClassEntity classId;
级联
操作一个对象的同时操作他的关联对象
级联添加
案例:当我保存一个客户的同时保存他的联系人
级联删除
案例:当我删除一个客户的同时删除他的联系人
@ManyToMany
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "rp_role_menu",
//设置中间表的名字,以及中间表的字段名
joinColumns = {@JoinColumn(name="roleId")},//joinColumns, 当前对象在中间表中的外键
inverseJoinColumns = @JoinColumn(name="menuId")//inverseJoinColumns, 对方对象在中间表的外键
希望以上笔记会对你对jpa学习提供帮助