Hibernate学习笔记

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 配置文件加上
<property
name="hibernate.globally_quoted_identifiers"
value="true"
/>
后,在所以的表操作语言上,字段名都加上引号

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 );
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容