1.使用开始
配置maven
1 <dependency> 2 <groupId>org.springframework.boot</groupId> 3 <artifactId>spring-boot-starter-data-jpa</artifactId> 4 </dependency>
配置properties
# database spring.datasource.url=jdbc:mysql://127.0.0.1:3306/stuadmin?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8 spring.datasource.username=root spring.datasource.password=root spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.type = com.alibaba.druid.pool.DruidDataSource spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=none spring.jpa.database-platform=org.hibernate.dialect.MySQL55Dialect
创建实体
2.一对一关系
- Teacher 教师
@Entity //表示实体 @Table(name = "t_teacher") // 表示数据库表名 // 数据库json序列化异常 @JsonIgnoreProperties(value={"hibernateLazyInitializer","handler","fieldHandler"}) public class Teacher { @Id //表示id主键 @GeneratedValue(strategy = GenerationType.IDENTITY) //自增长 @Column(name = "id", precision = 8) // 列名 总长度 private Long id; @Column(name = "name", length = 20) // length只作用于varchar类型 private String name; @Column(name = "subject", columnDefinition = "varchar(25) not null COMMENT '教授课程'") // columnDefinition 相当于添加一些细微属性操作 会拼接到数据 private String subject; }
- WorkCard 工作证
@Entity @Table(name = "t_work_card") @JsonIgnoreProperties(value={"hibernateLazyInitializer","handler","fieldHandler"}) public class WorkCard { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private Long id; @Column(name = "number", unique = true) private Long number; @Column(name = "overtime", columnDefinition = "datetime NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '过期时间'") private Date overtime; // 级联 懒加载 @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) //当前表id参照teacher表teacher_id字段 无外键(逻辑外键) @JoinColumn(name = "teacher_id", referencedColumnName = "id",foreignKey = @ForeignKey(name = "none",value = ConstraintMode.NO_CONSTRAINT)) private Teacher teacher; }
- 定义接口repository
public interface WorkCardRepository extends JpaRepository<WorkCard, Long> { }
- 使用
@Autowired WorkCardRepository workCardRepository; @GetMapping("/getteacherandworkcard") @ResponseBody public WorkCard queryWorkcardAndTeacher() { // 级联查询 WorkCard one = workCardRepository.getOne(1L); return one; }
多对一
- Classz 教室
@Entity @Table(name = "t_class") @JsonIgnoreProperties(value={"hibernateLazyInitializer","handler","fieldHandler"}) public class Classz { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private Long id; @Column(name = "name", columnDefinition = "varchar(25) not null COMMENT '班级名称'") private String name; //一对多 当前教室为1 学生为多 //当前属性映射到classz中 //懒加载 @OneToMany(mappedBy = "classz", cascade = CascadeType.ALL, fetch = FetchType.LAZY) private List<Student> studentList; }
- Student 学生
@Entity @Table(name = "t_student") @JsonIgnoreProperties(value={"hibernateLazyInitializer","handler","fieldHandler"}) public class Student { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private Long id; @Column(name = "name", columnDefinition = "varchar(25) not null COMMENT '姓名'") private String name; @Column(name = "age") private Integer age; @Column(name = "gender", columnDefinition = "varchar(2) not null default '男' COMMENT '性别'") private String gender; @Column(name = "distance", columnDefinition = "decimal(5,2) COMMENT '离校距离'") private BigDecimal distance; @ManyToOne(fetch = FetchType.LAZY) // 多对一 // class_id字段映射 Class @JoinColumn(name = "class_id", foreignKey = @ForeignKey(name = "none",value = ConstraintMode.NO_CONSTRAINT)) @JsonIgnore private Classz classz; }
- 定义repository
public interface ClasszRepository extends JpaRepository<Classz, Long> { }
- 使用
@GetMapping("/getclassz") @ResponseBody public Classz queryClassz() { //查修班级 Classz one = classzRepository.getOne(3L); return one; }
多对多
- 教室
@Entity @Table(name = "t_class") @JsonIgnoreProperties(value={"hibernateLazyInitializer","handler","fieldHandler"}) public class Classz { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private Long id; @Column(name = "name", columnDefinition = "varchar(25) not null COMMENT '班级名称'") private String name; @ManyToMany(mappedBy = "classzList", cascade = CascadeType.ALL, fetch = FetchType.LAZY) @JsonIgnore private List<Teacher> teachers; }
- 老师
@Entity @Table(name = "t_teacher") @JsonIgnoreProperties(value={"hibernateLazyInitializer","handler","fieldHandler"}) public class Teacher { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id", precision = 8) private Long id; @Column(name = "name", length = 20) private String name; @Column(name = "subject", columnDefinition = "varchar(25) not null COMMENT '教授课程'") private String subject; @ManyToMany(cascade=CascadeType.ALL, fetch = FetchType.LAZY) //Teacher是关系的维护端 //将会生成中间关联表 @JoinTable(name = "t_teacher_class_ref", joinColumns = @JoinColumn(name="teacher_id", foreignKey = @ForeignKey(name = "none",value = ConstraintMode.NO_CONSTRAINT)), inverseJoinColumns = @JoinColumn(name = "class_id", foreignKey = @ForeignKey(name = "none",value = ConstraintMode.NO_CONSTRAINT)), uniqueConstraints = {@UniqueConstraint(columnNames={"class_id", "teacher_id"})}) // class_id teacher_id 联合索引 private List<Classz> classzList;//教室 }
- 定义repository
此时定义classrepository 和 teacherrepository 都行
public interface TeacherRepository extends JpaRepository<Teacher, Long> { }
- 使用
@GetMapping("/getteachers") @ResponseBody public Teacher queryTeachers() { // 级联查询 Teacher one = teacherRepository.getOne(1L); return one; }
自定义方法名
在repository中可以定义许多方法 例如findby get等, 调用方式和之前一样
public interface UserRepository extends JpaRepository<User, Long> { List<User> findByAge(Integer age); List<User> findAllByAgeBetween(Integer start, Integer end); List<User> findUsersByAgeAndGenderLessThan(Integer age, Integer gender); @Query(nativeQuery = true, value = "select * from t_user where username = :username") List<User> findUsersByName(@Param("username") String username); }
native sql
相当于自己写sql
@Query(nativeQuery = true, value = "select * from t_user where username = :username") List<User> findUsersByName(@Param("username") String username);
jpql
对象级别的sql
@Query("select s from Student s join s.classz c where c.name = :classname and s.name like :sname%") List<Student> getStudentByName(@Param("classname") String classname, @Param("sname") String sname);
分页
继承pageAndSortRepository接口即可
public interface StudentPagingAndSortRepository extends PagingAndSortingRepository<Student, Long> { } @GetMapping("/get/studensbypage") @ResponseBody public List<Student> getStudentsByPage(@Param("page") Integer page, @Param("size") Integer size) { Pageable pageRequest = PageRequest.of(page, size); Page<Student> findStudentsByPage = studentPagingAndSortRepository.findAll(pageRequest); return findStudentsByPage.getContent(); } 或者使用JpaSpecificationExecutor 动态查询 和 pagerequest联合使用 Pageable pageable = PageRequest.of(page,size); Specification<Student> specification = new Specification<Student>() { @Override public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) { List<Predicate> predicates = new ArrayList<Predicate>(); //age Predicate age = criteriaBuilder.between(root.<Integer>get("age"), agegt, agelt); predicates.add(age); //dis Predicate distance = criteriaBuilder.equal(root.<Double>get("distance"), BigDecimal.valueOf(dis)); predicates.add(distance); //gender Predicate gender = criteriaBuilder.equal(root.<String>get("gender"), gend); predicates.add(gender); Predicate endset = criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()])); return endset; } }; // 查询 Page<Student> students = studentSpecificationRepository.findAll(specification, pageable); return students.getContent(); }
级联关系 - CascadeType
https://www.jianshu.com/p/e8caafce5445
- CascadeType.REMOVE
Cascade remove operation,级联删除操作。 删除当前实体时,与它有映射关系的实体也会跟着被删除。
- CascadeType.MERGE
Cascade merge operation,级联更新(合并)操作。 当Student中的数据改变,会相应地更新Course中的数据。
- CascadeType.DETACH
Cascade detach operation,级联脱管/游离操作。 如果你要删除一个实体,但是它有外键无法删除,你就需要这个级联权限了。它会撤销所有相关的外键关联。
- CascadeType.REFRESH
Cascade refresh operation,级联刷新操作。 假设场景 有一个订单,订单里面关联了许多商品,这个订单可以被很多人操作,那么这个时候A对此订单和关联的商品进行了修改, 与此同时,B也进行了相同的操作,但是B先一步比A保存了数据,那么当A保存数据的时候,就需要先刷新订单信息及关联的商品信息后,再将订单及商品保存。
- CascadeType.ALL
Cascade all operations,清晰明确,拥有以上所有级联操作权限。
@EntityGhpra解决n+1问题
n+1问题:一个教室对应多个学生时,jpa默认会先查询所有的教室,接着再通过每个用户的id去一条条查询每个教室的学生,这样会导致数据库执行多次sql语句,降低数据库性能;
-
1.用EntityGhpra解决n+1
@Entity @Table(name = "t_class")
@NamedEntityGraph(name = "Classz.Graph", attributeNodes = {@NamedAttributeNode("studentList")}) //注意这句,先用@NamedEntityGraph指名要加载的studentList属性 @JsonIgnoreProperties(value={"hibernateLazyInitializer","handler","fieldHandler"}) public class Classz { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private Long id; @Column(name = "name", columnDefinition = "varchar(25) not null COMMENT '班级名称'") private String name; //一对多 当前教室为1 学生为多 //当前属性映射到classz中 //懒加载 @OneToMany(mappedBy = "classz", cascade = CascadeType.ALL, fetch = FetchType.LAZY) private List<Student> studentList; }
- 2.调用方法时,指名要进行加载优化的对象
public interface ClasszRepository extends JpaRepository<Classz, Long> {
// 解决懒加载n+1问题
@EntityGraph(value = "Classz.Graph", type = EntityGraph.EntityGraphType.FETCH)
public List<Classz> findAll(); }
自定义repository
https://blog.csdn.net/chengqiuming/article/details/82531227
jpa与hibernate的关系
- JPA
JPA全称: Java Persistence API,JPA通过JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。 JPA的出现有两个原因:
1. 其一,简化现有Java EE和Java SE应用的对象持久化的开发工作;
2. 其二,Sun希望整合对ORM技术,实现持久化领域的统一。
JPA提供的技术:
- (1)ORM映射元数据
JPA支持XML和JDK 5.0注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架据此将实体对象持
久化到数据库表中;
- (2)JPA 的API
用来操作实体对象,执行CRUD操作,框架在后台替我们完成所有的事情,开发者从繁琐的JDBC和SQL代码中解
脱出来。
- (3)查询语言
通过面向对象而非面向数据库的查询语言查询数据,避免程序的SQL语句紧密耦合
- Hibernate
JPA是需要Provider来实现其功能的,Hibernate就是JPA Provider中很强的一个。
Java 8日期和时间支持 SQL片段映射 不可变的实体类型 实体过滤器 SQL片段匹配 手动冲洗模式 二级缓存查询 软删除
这些高级功能都是hibernate所拥有的。