Jpa는 ORM 사양의 집합입니다.
hibernate는 ORM 프레임워크일 뿐만 아니라 JPA 구현도 제공합니다.
JPA(Java Persistence API) : java persistence API
은 현재 클래스를 지정된 데이터베이스 테이블에 매핑되는 엔터티 클래스로 표시합니다.
@Entity public class Users { }
은 일반적으로 @Entity와 함께 사용됩니다. 데이터베이스 테이블 이름과 클래스 이름이 일치할 때 @Table 주석을 사용하지 않아도 괜찮다면, 그렇지 않으면
@Table 주석을 사용하여 테이블 이름
@Entity @Table(name="t_users") public class Users { }2.3 @Id를 지정해야 합니다. @GeneratedValue, @SequenceGenerator, @Column2.3.1 @Id 엔터티 클래스의 속성을 기본 키에 매핑하는 데 사용됩니다2.3.2 @GeneratedValue기본 키 생성 전략 지정
package javax.persistence; /** * 策略类型 */ public enum GenerationType { /** * 通过表产生主键,框架借由表模拟序列产生主键,使用该策略可以使应用更易于数据库移植 */ TABLE, /** * 通过序列产生主键,通过 @SequenceGenerator 注解指定序列名 * MySql 不支持这种方式 * Oracle 支持 */ SEQUENCE, /** * 采用数据库 ID自增长的方式来自增主键字段 * Oracle 不支持这种方式; */ IDENTITY, /** * 缺省值,JPA 根据数据库自动选择 */ AUTO; private GenerationType() { } }2.3.3 @SequenceGenerator2.3.4 @Column엔터티 클래스 속성 이름과 데이터베이스 열 이름이 일치하지 않는 경우 이 주석을 사용해야 합니다.
@Entity @Table(name="t_users") public class Users { @Id @Column(name = "user_id") @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_seq") @SequenceGenerator(name = "user_seq", sequenceName = "user_seq") private Long userId; }2.4 @Transient는 현재 속성을 데이터베이스에 매핑할 필요가 없음을 나타냅니다. 2.5 @Temproal은 주로 Date 유형 속성에 사용되며 이 주석을 통해 시간의 정밀도를 지정할 수 있습니다.
@Entity @Table(name="t_users") public class Users { @Temporal(TemporalType.DATE) private Date time1; @Temporal(TemporalType.TIME) private Date time2; @Temporal(TemporalType.TIMESTAMP) private Date time3; }3 EntityManagerFactory
는 hibernate의 SessionFactory4와 유사합니다. 엔터티
새 상태: 새로 생성된 항목에는 아직 영구 기본 키가 없습니다. 지속 상태: 이미 영구 기본 키가 있고 지속됩니다. 컨텍스트 관계가 설정되었습니다. 자유 상태: 영구 기본 키가 있지만 지속성과 컨텍스트 관계를 설정하지 않음 삭제된 상태: 영구 기본 키를 가지며 지속성과 컨텍스트 관계를 설정하지만 데이터베이스에서 삭제됩니다.
4.1 find(ClassentityClass, Object PrimaryKey)세션과 유사 최대 절전 모드의 get()find는 쿼리가 없으면 null을 반환합니다.4.2 getReference(ClassentityClass, Object PrimaryKey)
최대 절전 모드와 유사합니다. 세션의 load()getReference는 쿼리되지 않으면 null을 반환하지 않으며 EntityNotFoundException는 다음과 같은 경우에만 쿼리의 SQL 문을 실행합니다. 객체의 속성은 실제로 획득됩니다. getReference()는 프록시 객체만 반환합니다
을 발생시킵니다. 참고: 이를 사용할 때 지연 로딩 예외가 발생할 수 있습니다. 즉, 아직 엔터티 클래스의 속성 값을 얻지 못했고 결과적으로 EntityManager가 닫혔습니다.
注意:使用此方法可能出现懒加载异常的情况,也就是我们还没有去获取实体类中的属性值,结果 EntityManager 就已经被关闭了
类似与 hibernate 中 session 的 save()
注意:执行方法时传入的对象不能为主键设置值会抛出异常
类似与 hibernate 中 session 的 delete()
注意:该方法只能删除持久化对象,而不能删除游离状态的对象(hibernate 可以)
4.3 persist
참고: 메소드 실행 시 전달된 객체는 기본 키 값으로 설정할 수 없으며 예외가 발생합니다.
4.4 Remove
4.5 merge(T 엔터티)
참고: 이 방법은 영구 객체만 삭제할 수 있지만 자유 객체는 삭제할 수 없습니다(최대 절전 모드 가능)
/** * 删除游离态(失败) */ public void testRemove(){ Users user = new Users(); Users.setUserId(1); entityManager.remove(customer); } /** * 删除持久化状态(成功) */ public void testRemove(){ Users user = entityManager.find(Users.class, 1); entityManager.remove(user); }
// 新建状态 public void testMerge (){ Users user= new Users(); // 省略一系列的set // user.set..... Users newUser = entityManager.merge(user); // user.getUserId() == null ==> true // newUser.getUserId() == null ==> false }
4.6 플러시()
는 최대 절전 모드 세션의 플러시()와 유사합니다컨텍스트에 저장되지 않은 모든 항목을 데이터베이스에 저장합니다.
6. 매핑 관계
6.1 단방향 일대다
관계를 예로 들어 보겠습니다. 사용자는 여러 개의 주문을 가지고 있고 하나의 주문만 있습니다. 다대일 관계를 삽입하려면 한쪽 끝을 먼저 저장한 다음 다 끝을 저장하는 것이 가장 좋습니다./** * 订单和用户是多对一的关系 */ @Entity @Table(name="t_order") public class Order { // lazy为懒加载,默认为eager立即查询 @ManyToOne(fetch=FetchType.Lazy) // @JoinColumn标注字段是一个类,userId为该类的主键 @JoinColumn(name="user_id") private Users user; }
6.2 사용자와 주문 간의 관계를 기반으로 한 단방향 다대일
사용자와 주문 간의 관계 관계를 예로 들어 보겠습니다. 사용자는 여러 주문을 갖고 있고 하나의 주문은 한 명의 사용자에게만 속합니다. 양방향 다대일은 @OneToMany를 사용하여 위의 두 가지를 조합한 것입니다. @ManyToOne과 동시에/** * 订单和用户是多对一的关系 */ @Entity @Table(name="t_order") public class Order { // lazy为懒加载,默认为eager立即查询 @ManyToOne(fetch=FetchType.Lazy) // @JoinColumn标注字段是一个类,userId为该类的主键 @JoinColumn(name="user_id") private Users user; }6.3 양방향 다대일
以学校和校长之间的关系为例,一个学校只有一个校长,一个校长也只属于一个学校
一方使用 @OneToMany + @JoinColumn,另一方使用 @OneToOne(mappedBy=“xx”)
具体由哪一方维护关联关系都可以,这里我们以学校一端维护关联关系为例
保存时先保存不维护关联关系的一方(也就是使用@OneToOne(mappedBy=“xx”)的一方),否则会产生额外的 update 语句
/** * 学校 */ @Entity @Table(name="t_school") public class School { // 默认为eager立即查询 @OneToOne // 添加唯一约束 @JoinColumn(name="school_master_id", unique = true) private SchoolMaster schoolMaster; } /** * 校长 */ @Entity @Table(name="t_school_master") public class SchoolMaster { // 不维护关联关系要使用 mappedBy @OneToOne(mappedBy="schoolMaster") private School school; }
以学生和课程之间的关系为例,一个学生可以选多门课,一个课程也有多个学生,多对多需要一个中间表,也就是选课表
维护关联关系的一方需要使用 @JoinTable
关联关系也是只有一方维护即可,这里我们由学生表进行维护
/** * 学生 */ @Entity @Table(name="t_student") public class Student { @GeneratedValue @Id private Long student_id; // 要使用 set 集合接收 // 默认为lazy懒加载 @ManyToMany // name 为中间表的表名 @JoinTable(name="t_student_choose_course", // name 为与中间表与当前表所关联的字段的名称,referencedColumnName 为当前表中与中间表关联的字段的名称 joinColumns={@JoinColumn(name="student_id", referencedColumnName="student_id")}, // name 为与中间表与多对多另一方表所关联的字段的名称,referencedColumnName 为多对多另一方与中间表关联的字段的名称 inverseJoinColumns={@JoinColumn(name="course_id", referencedColumnName="course_id")}) private Set<Course> courses; } /** * 课程 */ @Entity @Table(name="t_course") public class Course { @GeneratedValue @Id private Long course_id; // 要使用 set 集合接收 // 默认为lazy懒加载 @ManyToMany(mappedBy="courses") private Set<Student> students; }
开启了二级缓存之后,缓存是可以跨越 EntityManager 的,
默认是一级缓存也就是在一个 EntityManager 中是有缓存的
二级缓存可以实现,关闭了 EntityManager 之后缓存不会被清除
使用 @Cacheable(true) 开启二级缓存
public void testCreateQuery(){ // 这里我们使用了一个 new Student,因为我们是查询 Student 中的部分属性,如果不适用 new Student 查询返回的结果就不是 Student 类型而是一个 Object[] 类型的 List // 也可以在实体类中创建对应的构造器,然后使用如下这种 new Student 的方式,来把返回结果封装为Student 对象 String jpql = "SELECT new Student(s.name, s.age) FROM t_student s WHERE s.student_id > ?"; // setParameter 时下标是从1开始的 List result = entityManager.createQuery(jpql).setParameter(1, 1).getResultList(); }
需要在类上使用 @NamedQuery 注解,事先声明 sql 语句
@NamedQuery(name="testNamedQuery", query="select * from t_student WHERE student_id = ?") @Entity @Table(name="t_student") public class Student { @GeneratedValue @Id private Long student_id; @Column private String name; @Column private int age; }
public void testCreateNamedQuery(){ Query query = entityManager.createNamedQuery("testNamedQuery").setParameter(1, 3); Student student = (Student) query.getSingleResult(); }
public void testCreateNativeQuery(){ // 本地sql的意思是只能在数据库中执行的sql语句 String sql = "SELECT age FROM t_student WHERE student_id = ?"; Query query = entityManager.createNativeQuery(sql).setParameter(1, 18); Object result = query.getSingleResult(); }
存在一对多关系时,当我们查询一的一端时,默认多的一端是懒加载。此时我们如果想要一次性查询出所有的数据就需要使用关联查询
注意: 下面 sql 中的重点就是要加上 fetch u.orders,表示要查询出用户所关联的所有订单
public void testLeftOuterJoinFetch(){ String jpql = "FROM t_users u LEFT OUTER JOIN FETCH u.orders WHERE u.id = ?"; Users user = (Users) entityManager.createQuery(jpql).setParameter(1, 123).getSingleResult(); }
위 내용은 SpringBoot JPA 공통 주석을 사용하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!