1. 程式人生 > >Hibernate持久層框架使用【四】hibernate的常用註解

Hibernate持久層框架使用【四】hibernate的常用註解

@DynamicInsert註解

這是一個hibernate對類的註解,用於資料的動態插入,對於持久化類中的屬性是否被賦值來動態生成sql語句

例如下面使用該註解來註解User類

@Entity(name="tb_user")
@DynamicInsert(false)
public class User {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "user_id")
	private int id;
	private String name;
	private int age;
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
}

新建一個類用於測試這個註解,例如這裡為table.class

這裡的MySessionFactory類為自定義的工具類,參考前面的博文

Hibernate持久層框架使用【二】資料新增與修改

public class table {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		MySessionFactory mySessionFactory = new MySessionFactory();
		Session session = mySessionFactory.getSession();
		
		User user = new User();
		user.setAge(5);
		//user.setName("李白");
		
		session.save(user);
		
		mySessionFactory.commit();
		mySessionFactory.close();
	}

}

這裡的MySessionFactory是前面部落格寫的工具類,參考前面的部落格。

執行後將在資料庫中生成一個tb_user表,以及儲存一條資料,檢視控制檯可以看到列印的sql語句

Hibernate: 
    insert 
    into
        tb_user
        (age, name) 
    values
        (?, ?)

儘管上面只對age進行賦值,但是hibernate還是生成了這條對age與name列的插入語句,為了提高效能,只對我們賦值的屬性進行插入,我們可以將DynamicInsert註解括號內的false改為true或者將false去掉(預設括號內值為true)

再次執行,檢視控制檯列印的sql語句,滿足需求

Hibernate: 
    insert 
    into
        tb_user
        (age) 
    values
        (?)

主鍵生成策略@GeneratedValue(strategy = GenerationType)

資料表中主鍵的生成策略有很多種方式,這裡測試一下其中的4種

第一種型別IDENTITY

這是MySQL和SqlServer的主鍵生成方式,在主鍵屬性上宣告此主鍵生成型別,每次插入資料時主鍵會自動遞增,而無需對主鍵賦值

示例程式碼:

User.class

@Entity(name="tb_user")
public class User {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;
	private String name;
	private int age;
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
}

以及一個測試類,PrimaryKey.class

public class PrimaryKey {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		MySessionFactory mySessionFactory = new MySessionFactory();
		Session session = mySessionFactory.getSession();
		
		User user = new User();
//		user.setId(1);
		user.setAge(10);
		user.setName("李牧");
		session.save(user);
		
		mySessionFactory.commit();
		mySessionFactory.close();
	}

}

執行後資料表tb_user中插入一條名稱為“李牧”的資料,主鍵為1,如果再次執行會發現插入的下一條資料主鍵自動增長為2

第二種型別SEQUENCE

@GeneratedValue(strategy = GenerationType.SEQUENCE)這個註解是對於Oracle資料庫的,因為本機沒有安裝Oracle,所以可以自行測試

第三種類型AUTO

@GeneratedValue(strategy = GenerationType.AUTO)

AUTO型別能夠自動識別你所使用的資料庫型別,再根據型別來生成主鍵策略(如使用mysql時生成mysql的主鍵自增策略,使用Oracle時使用Oracle的主鍵策略),將主鍵生成策略改為此型別,執行後生成的表插入資料同樣會自動插入主鍵

第四種類型TABLE

@GeneratedValue(strategy = GenerationType.TABLE)

把剛剛建立的tb_user表刪除,將主鍵生成策略使用TABLE型別,再次執行測試,可以看到資料庫裡多了兩張表,一張是我們建立的tb_user,一張叫做hibernate_sequences,用來儲存下一條主鍵的資訊

在執行完畢後控制檯列印了這些sql語句

Hibernate: 
    select
        sequence_next_hi_value 
    from
        hibernate_sequences 
    where
        sequence_name = 'tb_user' for update
            
Hibernate: 
    insert 
    into
        hibernate_sequences
        (sequence_name, sequence_next_hi_value) 
    values
        ('tb_user', ?)
Hibernate: 
    update
        hibernate_sequences 
    set
        sequence_next_hi_value = ? 
    where
        sequence_next_hi_value = ? 
        and sequence_name = 'tb_user'
Hibernate: 
    insert 
    into
        tb_user
        (age, name, id) 
    values
        (?, ?, ?)

從SQL語句中瞭解到,hibernater在插入資料時,會先查詢出存放下一個主鍵的這張表(hibernate_sequences)中的sequence_next_hi_value列的值,然後再插入資料,並更新hibernate_sequences表

檢視資料表,多了一條name為“李牧”的資料,Id為1

再次執行發現新插入的資料id變成了32768,這是因為Hibernate會查出hibernate_sequences表中下一個主鍵的值後,用它乘2的15次方作為主鍵,如果再插入一條資料的話,那麼主鍵應該會是65536(對於這個主鍵的生成規則,其實並不需要了解...不建議使用TABLE作為主鍵生成策略,因為在插入資料時要做這一系列操作肯定對效能會有影響)

聯合主鍵

如果一張表需要多個主鍵的話,可以為其他屬性也加上@Id註解,同時還需要實現序列化物件介面(hibernate需要將多個主鍵進行序列化來拼接主鍵)

示例程式碼:

@Entity(name="tb_user")
public class User implements Serializable{
	@Id
	private int id;
	@Id
	private String name;
	private int age;
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
}

列註解@Column

@Column(name="myname",length=99,unique=true)
private String name;

列註解有多個屬性,這裡name表示將該列的名字改為myname,length表示長度為99,unique表示唯一性約束為true

除此之外,還有其他屬性

如:

-precision:有效位數

-insertable:是否允許插入

-updatable:是否執行修改

-nullable:非空約束

-scale:小數點的位數

-columnDefinition:列的定義

columnDefinition示例:

@Column(name="myname",columnDefinition="int(66) not null")
private String name;

嵌入式主鍵

嵌入式主鍵即以一個實體類作為主鍵,這個類中的屬性作為表的列

例如下面的程式碼(需要實現序列化介面),其中有id和name兩個屬性

public class IdAndName implements Serializable{
	private int id;
	
	private String name;
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}

再將這個類作為主鍵,使用@EmbeddedId這個註解,這樣id和name就是聯合主鍵了

示例程式碼:

@Entity(name="tb_user")
public class User{
	
	@EmbeddedId
	private IdAndName idAndName;
	
	public IdAndName getIdAndName() {
		return idAndName;
	}
	public void setIdAndName(IdAndName idAndName) {
		this.idAndName = idAndName;
	}
	private int age;
	
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
}

測試類程式碼:

public class PrimaryKey {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		MySessionFactory mySessionFactory = new MySessionFactory();
		Session session = mySessionFactory.getSession();
		
		User user = new User();
		IdAndName idAndName = new IdAndName();
		idAndName.setId(1);
		idAndName.setName("ts");
		user.setIdAndName(idAndName);
		user.setAge(10);
		session.save(user);
		
		mySessionFactory.commit();
		mySessionFactory.close();
	}

}

執行後檢視資料庫可以看到資料表中有id、name、age三個列,這是因為Hibernate將IdAndName中的屬性析出來作為資料列了

如果想要對IdAndName類中的屬性進行別名或者使用其他限制時,除了可以直接在IdAndName類中對屬性進行註解外,還可以使用@AttributeOverrides註解進行復合屬性的註解

@AttributeOverrides屬性重寫

在上一個註解的基礎上,使用@AttributeOverrides進行屬性的重寫,程式碼如下:

將IdAndName類中的id屬性進行列別名,別名為"my_id",還可以指定長度等其他屬性,其他屬性參考上面的列註解

將IdAndName類中的name屬性進行列別名,別名為"my_name",長度為99

@Entity(name="tb_user")
@DynamicUpdate(false)
public class User{
	@Id
	@Embedded
	@AttributeOverrides({@AttributeOverride(name="id",[email protected](name="my_id",length=11))
	,@AttributeOverride(name="name",[email protected](name="my_name",length=99))})
	private IdAndName idAndName;
	private int age;
	
	public IdAndName getIdAndName() {
		return idAndName;
	}
	public void setIdAndName(IdAndName idAndName) {
		this.idAndName = idAndName;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
}

測試程式碼:

public class PrimaryKey {

	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		MySessionFactory mySessionFactory = new MySessionFactory();
		Session session = mySessionFactory.getSession();
		
		User user = new User();
		user.setAge(10);
		
		IdAndName idAndName = new IdAndName();
		idAndName.setId(1);
		idAndName.setName("王翦");
		
		user.setIdAndName(idAndName);
		
		session.save(user);
		
		mySessionFactory.commit();
		mySessionFactory.close();
	}

}

大的二進位制或文字註解@Lob

這個註解用來儲存一些大的二進位制或文字資料,例如圖片(一般web專案推薦只儲存圖片的路徑名,通過路徑名來找到圖片,而不是直接儲存圖片)

示例程式碼:

@Entity(name="tb_user")
@DynamicUpdate(false)
public class User{
	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	private int id;
	private String name;
	private int age;
	
	@Lob
	private byte[] image;
	
	public byte[] getImage() {
		return image;
	}
	public void setImage(byte[] image) {
		this.image = image;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
}

其中Image屬性用來儲存圖片

測試程式碼:

public class PrimaryKey {

	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		MySessionFactory mySessionFactory = new MySessionFactory();
		Session session = mySessionFactory.getSession();
		
		User user = new User();
		user.setId(2);
		user.setAge(10);
		user.setName("李牧");
		 
		InputStream is = PrimaryKey.class.getResourceAsStream("a2.png");
		byte[] image = new byte[is.available()];
		is.read(image);
		is.close();
		
		user.setImage(image);
		
		session.save(user);
		
		mySessionFactory.commit();
		mySessionFactory.close();
	}

}

取測試類PrimaryKey同目錄下的a2.png圖片寫到位元組數組裡,呼叫save方法儲存,儲存成功後可以將資料表中的這一列資料儲存出來,儲存為png格式,開啟圖片正常顯示

日期格式註解@Temporal

-TemporalType.DATE:yyyy-MM-dd 顯示日期

-TemporalType.TIME:HH:mm:ss 只顯示時間

-TemporalType.TIMESTAMP:yyyy-MM-dd HH:mm:ss 全日期顯示

示例程式碼:

@Entity(name="tb_user")
public class User{
	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	private int id;
	private String name;
	private int age;
	
	@Temporal(TemporalType.TIMESTAMP)
	private Date date;
	
	public Date getDate() {
		return date;
	}
	public void setDate(Date date) {
		this.date = date;
	}
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
}

測試類程式碼:

public class PrimaryKey {

	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		MySessionFactory mySessionFactory = new MySessionFactory();
		Session session = mySessionFactory.getSession();
		
		User user = new User();
		user.setAge(10);
		user.setName("李牧");
		user.setDate(new Date());
		session.save(user);
		
		mySessionFactory.commit();
		mySessionFactory.close();
	}

}

完成