Hibernate学习笔记

497 阅读8分钟

SessionFactory

Session实例工厂,等同于JPA中的EntityManagerFactory,该对象的创建是非常昂贵的,所以,对于任意的数据库,应用程序应该只有一个SessionFactory对象与之关联,SessionFactory对象操作其他Hibernate服务通过Session,比如二级缓存,连接池,事务系统等等。

Session

单线程,短生命周期对象。代表JPA中的EntiryManager.在底层,Session包裹一个java.sql.ConnectionJDBC并作为Transaction实例对象的工厂存在。其操作一个普遍意义上的重复读在应用程序model对象的持久上下文上。

Transaction

单线程,短生命周期对象。相当于JPA中的EntiryTransaction.

Model

package com.example.po;

import java.sql.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.Table;
import javax.persistence.Index;

@Entity
@Table(
		name="customers",
		indexes=@Index(
				name="customer_mobile_idx",
				columnList="user_name, mobile",
				unique=true)
)
public class Customer {

	
	public Customer() {
		
	}
	
	
	
	public Customer(String userName, String mobile, String shopText, double amount) {
		super();
		this.userName = userName;
		this.mobile = mobile;
		this.shopText = shopText;
		this.amount = amount;
		this.createdAt = new Date(System.currentTimeMillis());
		this.updatedAt = new Date(System.currentTimeMillis());
	}
	
	@Id
	@GeneratedValue
	private long id;
	@Column(name="user_name")
	private String userName;
	@Column(name="mobile")
	private String mobile;
	@Lob
	private String shopText;
	private double amount;
	private Date createdAt;
	private Date updatedAt;
	private Date deletedAt;
	
	public long getId() {
		return id;
	}
	public void setId(long id) {
		this.id = id;
	}
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getMobile() {
		return mobile;
	}
	public void setMobile(String mobile) {
		this.mobile = mobile;
	}
	public String getShopText() {
		return shopText;
	}
	public void setShopText(String shopText) {
		this.shopText = shopText;
	}
	public double getAmount() {
		return amount;
	}
	public void setAmount(double amount) {
		this.amount = amount;
	}



	public Date getCreatedAt() {
		return createdAt;
	}



	public void setCreatedAt(Date createdAt) {
		this.createdAt = createdAt;
	}



	public Date getUpdatedAt() {
		return updatedAt;
	}



	public void setUpdatedAt(Date updatedAt) {
		this.updatedAt = updatedAt;
	}



	public Date getDeletedAt() {
		return deletedAt;
	}



	public void setDeletedAt(Date deletedAt) {
		this.deletedAt = deletedAt;
	}
	
	
	
}

1.定义索引在表级进行定义,不能再字段上直接加上Index()注释

2.String加上@Lob,会自动映射到数据库表中的Clob类型

下面介绍一个时间类型

	@Temporal(TemporalType.DATE)
	private Date createdAt;
	@Temporal(TemporalType.TIMESTAMP)
	private Date updatedAt;
	@Temporal(TemporalType.TIME)
	private Date deletedAt;

查看三个字段的不同类型结果:

CREATEDAT             UPDATEDAT                       DELETEDAT           
--------------------- ------------------------------- ---------------------
2019-09-23 14:26:46   23-9月 -19 02.26.46.327000000 下午 1970-01-01 14:26:46   
2019-09-23 14:26:46   23-9月 -19 02.26.46.340000000 下午 1970-01-01 14:26:46   
2019-09-23 14:26:46   23-9月 -19 02.26.46.348000000 下午 1970-01-01 14:26:46   
2019-09-23 14:26:46   23-9月 -19 02.26.46.372000000 下午 1970-01-01 14:26:46   
2019-09-23 14:26:46   23-9月 -19 02.26.46.386000000 下午 1970-01-01 14:26:46  

hibernate 配置文件加上 后,在所以的表操作语言上,字段名都加上引号

insert into "shoptexts" ("createdAt", "deletedAt", "shopCount", "shop_name", "updatedAt", "id", "shopAddr") values (?, ?, ?, ?, ?, ?, ?)

Generated properties

时间字段的自动生成方式:

@CreationTimestamp
	@Temporal(TemporalType.DATE)
	private Date createdAt;
	@UpdateTimestamp
	@Temporal(TemporalType.TIMESTAMP)
	private Date updatedAt;
	@Temporal(TemporalType.TIME)
	private Date deletedAt;

Entity types

JPA实体类需要遵循以下要求:

1.实体类需要使用javax.persistence.Entity注解注释。(或者使用xml映射)

2.实体类需要有一个公共的或者受保护的无参构造器。也可以定义其他的构造器。

3.实体类需要是一个顶级的类

4.接口和枚举类不能作为实体类

5.实体类不能是final的。

6.如果实体类被用于远端使用,需要继承Serializable序列化接口

7.抽象类和混合类都可以设计为实体类。实体类可以继承自非实体类,或者实体类。非实体类也可以继承自实体类

8.实体的持久状态由实例变量表示,这些变量可能对应于JavaBean风格的属性。实体实例本身只能从实体的方法中直接访问实例变量。客户端只能通过实体的访问器方法(getter/setter方法)或其他业务方法获得实体的状态。

Hibernate与上面的区别是: 1.实体类需要一个无参构造器,可以使public,protected或者package级别的,可以定义其他的构造器

2.实体类不需要是最顶端的类

3.技术上讲,可以提交final类和类中包含final的变量。但是不建议这么做。会阻止使用懒加载。

4.Hibernate不限制应用程序开发人员公开实例变量并从实体类本身外部引用它们。然而,这种范式的有效性充其量是有争议的。

强烈建议,在声明类型属性的时候,使用包装类,而不是基本类型。比如 使用Long或者Integer类型

继承

虽然关系型数据库系统不提供支持继承,Hibernate提供了多种策略来利用这种面向对象特性到域模型实体:

MappedSuperclass

继承只在域模型中实现,而不反映在数据库模式中

@MappedSuperclass
public class Messages {

   public Messages() {
   	// TODO Auto-generated constructor stub
   }
   @Id
   private Integer id;
   
   @Column(length=2048)
   private String title;
   
   @Column(length=2048)
   private String summary;
   
   @Type(type="materialized_clob")
   private String content;
}




@Entity
@Table(name="globallivemsgs")
public class Global extends Messages {

   public Global() {
   	// TODO Auto-generated constructor stub
   }

   private Integer status;

   public Integer getStatus() {
   	return status;
   }

   public void setStatus(Integer status) {
   	this.status = status;
   }
   
}


desc "globallivemsgs"
名称      空值       类型                  
------- -------- ------------------- 
id      NOT NULL NUMBER(10)          
content          CLOB                
summary          VARCHAR2(2048 CHAR) 
title            VARCHAR2(2048 CHAR) 
status           NUMBER(10)          

由于@MappedSuperclass继承模型没有在数据库级进行镜像,所以在通过基类获取持久对象时,不可能使用引用@MappedSuperclass的多态查询。

Single table

域模型类层次结构被物化为一个表,其中包含属于不同类类型的实体。单表继承策略的所有子类映射到一个数据库表。 每个子类定义它自己的持久化属性。 版本和id属性被假定为可以从根类继承。

@Entity
@Inheritance(strategy= InheritanceType.SINGLE_TABLE)
public class Messages {

   public Messages() {
   	// TODO Auto-generated constructor stub
   }
   
   
   
   
   public Messages(String title, String summary, String content) {
   	super();
   	this.title = title;
   	this.summary = summary;
   	this.content = content;
   }




   @Id
   private Integer id;
   
   @Column(length=2048)
   private String title;
   
   @Column(length=2048)
   private String summary;
   
   @Type(type="materialized_clob")
   private String content;
}


@Entity
public class Global extends Messages {

   public Global() {
   	// TODO Auto-generated constructor stub
   }

   private Integer status;

   public Integer getStatus() {
   	return status;
   }

   public void setStatus(Integer status) {
   	this.status = status;
   }
   
}


@Entity
public class Kuaixun extends Messages {

   public Kuaixun() {
   	// TODO Auto-generated constructor stub
   }

   private Integer impact;

   public Integer getImpact() {
   	return impact;
   }

   public void setImpact(Integer impact) {
   	this.impact = impact;
   }
   
   
}


desc "Messages"
名称      空值       类型                  
------- -------- ------------------- 
DTYPE   NOT NULL VARCHAR2(31 CHAR)   
id      NOT NULL NUMBER(10)          
content          CLOB                
summary          VARCHAR2(2048 CHAR) 
title            VARCHAR2(2048 CHAR) 
impact           NUMBER(10)          
status           NUMBER(10) 

层次结构中的每个子类必须定义一个唯一的鉴别器值,该值用于区分属于不同子类类型的行。如果未指定,DTYPE列将用作鉴别器,存储相关的子类名称。

Joined table

基类和所有子类都有自己的数据库表,获取子类实体也需要与父表连接。 每个子类还可以映射到它自己的表。这也称为每子类表映射策略。通过连接超类的表检索继承的状态。此映射策略不需要discriminator列。但是,每个子类必须声明一个包含对象标识符的表列。

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Messages {

   public Messages() {
   	// TODO Auto-generated constructor stub
   }
   
   
   
   
   public Messages(String title, String summary, String content) {
   	super();
   	this.title = title;
   	this.summary = summary;
   	this.content = content;
   }




   @Id
   private Integer id;
   
   @Column(length=2048)
   private String title;
   
   @Column(length=2048)
   private String summary;
   
   @Type(type="materialized_clob")
   private String content;
}

@Entity
@PrimaryKeyJoinColumn(name = "messages_id")
public class Global extends Messages {

   public Global() {
   	// TODO Auto-generated constructor stub
   }

   private Integer status;

   public Integer getStatus() {
   	return status;
   }

   public void setStatus(Integer status) {
   	this.status = status;
   }
   
}


@Entity
@PrimaryKeyJoinColumn(name = "messages_id")
public class Kuaixun extends Messages {

   public Kuaixun() {
   	// TODO Auto-generated constructor stub
   }

   private Integer impact;

   public Integer getImpact() {
   	return impact;
   }

   public void setImpact(Integer impact) {
   	this.impact = impact;
   }
   
   
}


desc "Messages"
名称      空值       类型                  
------- -------- ------------------- 
id      NOT NULL NUMBER(10)          
content          CLOB                
summary          VARCHAR2(2048 CHAR) 
title            VARCHAR2(2048 CHAR) 

desc "Global"
名称          空值       类型         
----------- -------- ---------- 
status               NUMBER(10) 
messages_id NOT NULL NUMBER(10) 

desc "Kuaixun"
名称          空值       类型         
----------- -------- ---------- 
impact               NUMBER(10) 
messages_id NOT NULL NUMBER(10) 

Table per class

每个子类都有自己的表,其中包含子类和基类属性。第三个选项是只将继承层次结构的具体类映射到表中。这被称为按具体类别划分表格的策略。每个表定义了类的所有持久状态,包括继承状态。

在Hibernate中,没有必要显式映射这样的继承层次结构。您可以将每个类映射为单独的实体根。但是,如果您希望使用多态关联(例如,与层次结构的超类的关联),您需要使用联合子类映射。


@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Messages {

	public Messages() {
		// TODO Auto-generated constructor stub
	}
	
	
	
	
	public Messages(String title, String summary, String content) {
		super();
		this.title = title;
		this.summary = summary;
		this.content = content;
	}




	@Id
	private Integer id;
	
	@Column(length=2048)
	private String title;
	
	@Column(length=2048)
	private String summary;
	
	@Type(type="materialized_clob")
	private String content;
}

desc "Messages"
名称      空值       类型                  
------- -------- ------------------- 
id      NOT NULL NUMBER(10)          
content          CLOB                
summary          VARCHAR2(2048 CHAR) 
title            VARCHAR2(2048 CHAR) 

desc "Global"
名称      空值       类型                  
------- -------- ------------------- 
id      NOT NULL NUMBER(10)          
content          CLOB                
summary          VARCHAR2(2048 CHAR) 
title            VARCHAR2(2048 CHAR) 
status           NUMBER(10)          

desc "Kuaixun"
名称      空值       类型                  
------- -------- ------------------- 
id      NOT NULL NUMBER(10)          
content          CLOB                
summary          VARCHAR2(2048 CHAR) 
title            VARCHAR2(2048 CHAR) 
impact           NUMBER(10)   

显示或隐式多态

public interface DomainModelEntity<ID> {

   ID getId();

   Integer getVersion();
}

@Entity(name = "Event")
public static class Book implements DomainModelEntity<Long> {

   @Id
   private Long id;

   @Version
   private Integer version;

   private String title;

   private String author;

   //Getter and setters omitted for brevity
}

@Entity(name = "Blog")
@Polymorphism(type = PolymorphismType.EXPLICIT)
public static class Blog implements DomainModelEntity<Long> {

   @Id
   private Long id;

   @Version
   private Integer version;

   private String site;

   //Getter and setters omitted for brevity
}
Book book = new Book();
book.setId( 1L );
book.setAuthor( "Vlad Mihalcea" );
book.setTitle( "High-Performance Java Persistence" );
entityManager.persist( book );

Blog blog = new Blog();
blog.setId( 1L );
blog.setSite( "vladmihalcea.com" );
entityManager.persist( blog );

List<DomainModelEntity> accounts = entityManager
.createQuery(
   "select e " +
   "from org.hibernate.userguide.inheritance.polymorphism.DomainModelEntity e" )
.getResultList();

assertEquals(1, accounts.size());
assertTrue( accounts.get( 0 ) instanceof Book );