溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

SpringBoot?JPA常用注解如何使用

發(fā)布時間:2023-05-10 17:43:08 來源:億速云 閱讀:158 作者:iii 欄目:開發(fā)技術

這篇文章主要講解了“SpringBoot JPA常用注解如何使用”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“SpringBoot JPA常用注解如何使用”吧!

    1. 簡介

    Jpa 是一套ORM 的規(guī)范
    hibernate 不就是一個 ORM 框架也提供了對于 JPA 的實現(xiàn)

    JPA(Java Persistence API):java 持久化 API

    2. 常用注解

    2.1 @Entity

    標注當前類為實體類,將映射到指定的數(shù)據(jù)庫表中

    @Entity
    public class Users {
    		
    }

    2.2 @Table

    一般與 @Entity 注解一起使用,如果數(shù)據(jù)庫表名和類名一致時不使用 @Table 注解也是可以的,
    否則需要使用 @Table 注解來指定表名

    @Entity
    @Table(name="t_users")
    public class Users {
    		
    }

    2.3 @Id 、@GeneratedValue、@SequenceGenerator、@Column

    2.3.1 @Id

    用于將實體類的屬性映射為主鍵

    2.3.2 @GeneratedValue

    指定主鍵生成策略

    package javax.persistence;
    /**
     * 策略類型
     */
    public enum GenerationType {
      /**
       * 通過表產生主鍵,框架借由表模擬序列產生主鍵,使用該策略可以使應用更易于數(shù)據(jù)庫移植
       */
      TABLE,
      /**
       * 通過序列產生主鍵,通過 @SequenceGenerator 注解指定序列名
       * MySql 不支持這種方式
       * Oracle 支持
       */
      SEQUENCE,
      /**
       * 采用數(shù)據(jù)庫 ID自增長的方式來自增主鍵字段
       * Oracle 不支持這種方式;
       */
      IDENTITY,
      /**
       * 缺省值,JPA 根據(jù)數(shù)據(jù)庫自動選擇
       */
      AUTO;
    
      private GenerationType() {
      }
    }
    2.3.3 @SequenceGenerator
    2.3.4 @Column

    當實體類屬性名和數(shù)據(jù)庫列名不一致時必須要使用此注解

    @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

    表示當前屬性無需映射到數(shù)據(jù)庫中

    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 的 SessionFactory

    4. EntityManager 實體的四種狀態(tài)

    新建狀態(tài): 新創(chuàng)建還未擁有持久性主鍵持久化狀態(tài): 已經擁有持久性主鍵并和持久化建立了上下文關系游離狀態(tài): 擁有持久性主鍵,但沒有和持久化建立上下文關系刪除狀態(tài): 擁有持久性主鍵,并且和持久化建立了上下文關系,但是從數(shù)據(jù)庫中刪除了

    4.1 find(Class entityClass, Object primaryKey)

    類似于 hibernate 中 session 的 get()

    find 如果沒有查詢到會返回 null

    4.2 getReference(Class entityClass, Object primaryKey)

    類似與 hibernate 中 session 的 load()
    只有當真正獲取對象中的屬性時,才會去執(zhí)行查詢的 sql 語句,getReference() 只是返回了一個代理對象

    getReference 如果沒有查詢到不會返回 null , 會拋出 EntityNotFoundException

    注意:使用此方法可能出現(xiàn)懶加載異常的情況,也就是我們還沒有去獲取實體類中的屬性值,結果 EntityManager 就已經被關閉了

    4.3 persist

    類似與 hibernate 中 session 的 save()

    注意:執(zhí)行方法時傳入的對象不能為主鍵設置值會拋出異常

    4.4 remove

    類似與 hibernate 中 session 的 delete()

    注意:該方法只能刪除持久化對象,而不能刪除游離狀態(tài)的對象(hibernate 可以)

    	/**
    	 * 刪除游離態(tài)(失?。?
    	 */
    	public void testRemove(){
    		Users user = new Users();
    		Users.setUserId(1);
    		entityManager.remove(customer);
    	}
    	
    	/**
    	 * 刪除持久化狀態(tài)(成功)
    	 */
    	public void testRemove(){
    		Users user = entityManager.find(Users.class, 1);
    		entityManager.remove(user);
    	}

    4.5 merge(T entity)

    類似與 hibernate 中 session 的 saveOrUpdate()

    	// 新建狀態(tài)
    	public void testMerge	(){
    		Users user= new Users();
    		// 省略一系列的set
    		// user.set.....
    		Users newUser = entityManager.merge(user);
    		// user.getUserId() == null  ==> true
    		// newUser.getUserId() == null ==> false
    	}

    SpringBoot?JPA常用注解如何使用

    4.6 flush()

    類似與 hibernate 中 session 的 flush()

    將上下文中所有未保存的實體保存到數(shù)據(jù)庫中

    4.6 refresh()

    類似與 hibernate 中 session 的 refresh()

    刷新所有實體的屬性值

    5. EntityTransaction

    EntityManager.getTransaction()

    5.1 begin

    5.2 commit

    5.3 rollback

    6. 映射關系

    6.1 單向一對多

    以用戶和訂單之間的關系為例,一個用戶有多個訂單,一個訂單只屬于一個用戶
    對于一對多關系的 insert,無論是先插入多的一方還是一的一方都會產生額外的 update 語句,因為多的一端在 insert 時不會插入外鍵的列

    /**
     * 訂單和用戶是多對一的關系
     */
    @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 單向多對一

    以用戶和訂單之間的關系為例,一個用戶有多個訂單,一個訂單只屬于一個用戶
    對于多對一關系的 insert,最好先保存一的一端然后在保存多的一端。
    如果先保存多的一端再保存一的一端,為了維護外鍵的關系,需要對多的一端進行額外的update的操作

    /**
     * 訂單和用戶是多對一的關系
     */
    @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 和 @ManyToOne

    /**
     * 用戶和訂單是一對多的關系
     */
    @Entity
    @Table(name="t_users")
    public class User {
    	// 如果兩側都要描述關聯(lián)關系的話,維護關聯(lián)關系的任務要交給多的一方
    	// 使用 @OneToMany 了 mappedBy 的代表不維護關聯(lián)關系,也就是不會產生額外的update語句
    	// @OneToMany 和 @JoinColumn 不能同時使用會報錯
    	@OneToMany(mappedBy="user")
    	private Set<Orders> orders;
    }
    
    /**
     * 訂單和用戶是多對一的關系
     */
    @Entity
    @Table(name="t_orders")
    public class Order {
    	// lazy為懶加載,默認為eager立即查詢
    	@ManyToOne(fetch=FetchType.Lazy)
    	// @JoinColumn標注字段是一個類,userId為該類的主鍵
    	@JoinColumn(name="user_id")
    	private Users user;
    }

    SpringBoot?JPA常用注解如何使用

    6.4 雙向一對一

    以學校和校長之間的關系為例,一個學校只有一個校長,一個校長也只屬于一個學校
    一方使用 @OneToMany + @JoinColumn,另一方使用 @OneToOne(mappedBy=“xx”)
    具體由哪一方維護關聯(lián)關系都可以,這里我們以學校一端維護關聯(lián)關系為例
    保存時先保存不維護關聯(lián)關系的一方(也就是使用@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 {
    	// 不維護關聯(lián)關系要使用 mappedBy
    	@OneToOne(mappedBy="schoolMaster")
    	private School school;
    }

    6.5 雙向多對多

    以學生和課程之間的關系為例,一個學生可以選多門課,一個課程也有多個學生,多對多需要一個中間表,也就是選課表
    維護關聯(lián)關系的一方需要使用 @JoinTable
    關聯(lián)關系也是只有一方維護即可,這里我們由學生表進行維護

    /**
     * 學生
     */
    @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 為與中間表與當前表所關聯(lián)的字段的名稱,referencedColumnName 為當前表中與中間表關聯(lián)的字段的名稱
    			joinColumns={@JoinColumn(name="student_id", referencedColumnName="student_id")},
    			// name 為與中間表與多對多另一方表所關聯(lián)的字段的名稱,referencedColumnName 為多對多另一方與中間表關聯(lián)的字段的名稱
    			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;
    }

    7. 二級緩存

    開啟了二級緩存之后,緩存是可以跨越 EntityManager 的,
    默認是一級緩存也就是在一個 EntityManager 中是有緩存的
    二級緩存可以實現(xiàn),關閉了 EntityManager 之后緩存不會被清除
    使用 @Cacheable(true) 開啟二級緩存

    8. JPQL

    8.1 查詢接口

    8.1.1 createQuery
    	public void testCreateQuery(){
    		// 這里我們使用了一個 new Student,因為我們是查詢 Student 中的部分屬性,如果不適用 new Student 查詢返回的結果就不是 Student 類型而是一個 Object[] 類型的 List
    		// 也可以在實體類中創(chuàng)建對應的構造器,然后使用如下這種 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();
    	}
    8.1.2 createNamedQuery

    需要在類上使用 @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();
    	}
    8.1.3 createNativeQuery
    	public void testCreateNativeQuery(){
    		// 本地sql的意思是只能在數(shù)據(jù)庫中執(zhí)行的sql語句
    		String sql = "SELECT age FROM t_student WHERE student_id = ?";
    		Query query = entityManager.createNativeQuery(sql).setParameter(1, 18);
    		Object result = query.getSingleResult();
    	}

    8.2 關聯(lián)查詢

    存在一對多關系時,當我們查詢一的一端時,默認多的一端是懶加載。此時我們如果想要一次性查詢出所有的數(shù)據(jù)就需要使用關聯(lián)查詢

    注意: 下面 sql 中的重點就是要加上 fetch u.orders,表示要查詢出用戶所關聯(lián)的所有訂單

    	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常用注解如何使用”的內容了,經過本文的學習后,相信大家對SpringBoot JPA常用注解如何使用這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

    向AI問一下細節(jié)

    免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經查實,將立刻刪除涉嫌侵權內容。

    AI