Hibernate注解開發、注解創建索引


1.注解的目的

  簡化繁瑣的ORM映射文件(*.hbm)的配置

2.JPA和hibernate的關系

  JPA:java persistence API,JPA注解是JavaEE的標准和規范。

  兩者的關系可以簡單理解為JPA是接口,Hibernate是實現,但是其功能是JPA的超集。

Hibernate如何實現與JPA的關系?

  通過hibernate-core,hibernate-entitymanager,hibernate-annotation三個組件實現。

程序開發中一般使用JPA注解,便於程序的擴展和移植。

3.Hibernate注解分類:

  類級別注解

    @Entity  表示實體類,對應DB中一張表

    @Table    表示DB中的表

    @Embeddable    嵌入類

  屬性級別注解

    

 

  映射關系注解

    

 

 

4.Hibernate注解的使用

1.導包與准備工具類:

pom包依賴:

    <dependencies>
        <!-- slf4j 依賴包 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.25</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.0-rc1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.0-rc1</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>5.0.7.Final</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.37</version>
        </dependency>
    </dependencies>

 

 

工具類:

package cn.qlq.util;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.service.ServiceRegistry;

public class HibernateUtil {

    private static SessionFactory sessionFactory;

    // 創建一個對象,一個web項目只有一個SessionFactory
    static {
        // 3.3以及之前的版本構建會話工廠對象
        // SessionFactory sessionFactory = new
        // Configuration().configure().buildSessionFactory();

        // 5.0之后獲取SessionFactory
        // 創建服務注冊對象
        ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure().build();
        // 創建會話工廠對象
        sessionFactory = new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory();
    }

    // 獲得session => 獲得全新session
    public static Session openSession() {
        return sessionFactory.openSession();
    }

    // 獲得session => 獲得與線程綁定的session
    public static Session getCurrentSession() {
        return sessionFactory.getCurrentSession();
    }

}

 

5.類注解的使用

5.1@Entity注解的使用---屬於javax包

  @Entity:映射實體類、

  @Entity(name = "tableName")

  name是可選屬性,指定數據庫的表名,如果不寫的話默認與實體類名相同。

注意:使用@Entity必須指定實體的主鍵屬性(可以在get方法上設置,也可以直接在屬性設置)

package cn.qlq.domain;

import java.util.Date;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity(name = "t_student") // 注意包名是javax
public class Student {
//    @Id
    private Integer id;
    private String name;
    private Integer age;
    private Date birthDay;
    private Character sex;
    private String address;

    @Id
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getBirthDay() {
        return birthDay;
    }

    public void setBirthDay(Date birthDay) {
        this.birthDay = birthDay;
    }

    public Character getSex() {
        return sex;
    }

    public void setSex(Character sex) {
        this.sex = sex;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

 

 

hibernate.cfg.xml配置注解實體類:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql:///hibernate</property>
        <property name="hibernate.connection.username">sa</property>
        <property name="hibernate.connection.password">123456</property>
        
        
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

        <!-- 使用二級緩存 -->
        <property name="hibernate.cache.use_second_level_cache">true</property>
        <!--設置緩存的類型,設置緩存的提供商 -->
        <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</property>
        
        <!-- #hibernate.show_sql true 
             #hibernate.format_sql true
        -->
        <!-- 將hibernate生成的sql語句打印到控制台 -->
        <property name="hibernate.show_sql">true</property>
        <!-- 將hibernate生成的sql語句格式化(語法縮進) -->
        <property name="hibernate.format_sql">true</property>
        <!-- 
        ## auto schema export  自動導出表結構. 自動建表
        #hibernate.hbm2ddl.auto create        自動建表.每次框架運行都會創建新的表.以前表將會被覆蓋,表數據會丟失.(開發環境中測試使用)
        #hibernate.hbm2ddl.auto create-drop 自動建表.每次框架運行結束都會將所有表刪除.(開發環境中測試使用)
        #hibernate.hbm2ddl.auto update(推薦使用) 自動生成表.如果已經存在不會再生成.如果表有變動.自動更新表(不會刪除任何數據).
        #hibernate.hbm2ddl.auto validate    校驗.不自動生成表.每次啟動會校驗數據庫中表是否正確.校驗失敗.
         -->
        <property name="hibernate.hbm2ddl.auto">create</property>
        
        <!-- 引入orm注解類         -->
        <mapping class="cn.qlq.domain.Student" />
    </session-factory>
</hibernate-configuration>

 

 

測試:

package cn.qlq.test;

import org.junit.Test;

import cn.qlq.util.HibernateUtil;

public class TestEntityAnno {

    @Test
    public void test1() {
        HibernateUtil.openSession();
    }
}

 

 

日志:

Hibernate: 
    drop table if exists t_student
2018-08-27 23:12:02 [net.sf.ehcache.util.UpdateChecker]-[DEBUG] Checking for update...
Hibernate: 
    create table t_student (
        id integer not null,
        address varchar(255),
        age integer,
        birthDay datetime,
        name varchar(255),
        sex char(1),
        primary key (id)
    )

 

SQL表:(主鍵沒有自增)

mysql> desc t_student;
+----------+--------------+------+-----+---------+-------+
| Field    | Type         | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+-------+
| id       | int(11)      | NO   | PRI | NULL    |       |
| address  | varchar(255) | YES  |     | NULL    |       |
| age      | int(11)      | YES  |     | NULL    |       |
| birthDay | datetime     | YES  |     | NULL    |       |
| name     | varchar(255) | YES  |     | NULL    |       |
| sex      | char(1)      | YES  |     | NULL    |       |
+----------+--------------+------+-----+---------+-------+

 

5.2@Table注解

@Table(name="xxx",catalog="xxx",schema="xxx")

@Entity配合使用,只能標注在實體的class處定義,表示實體對應的數據庫表的信息

name:可選映射表的名稱,不寫的話與類名稱相同

catalog:可選(目錄名稱),表示Catalog名稱,默認為Catalog("")

schema:可選的模式名稱,表示Scheme名稱,默認為Scheme("")

 

Catalog與Schema解釋:

 

 

 

自己的測試:

package cn.qlq.domain;

import java.util.Date;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

//@Entity(name = "t_student") // 注意包名是javax
@Entity
@Table(name = "t_stu", schema = "hibernate") // 注意包名是javax
public class Student {
    // @Id
    private Integer id;
    private String name;
    private Integer age;
    private Date birthDay;
    private Character sex;
    private String address;

    @Id
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getBirthDay() {
        return birthDay;
    }

    public void setBirthDay(Date birthDay) {
        this.birthDay = birthDay;
    }

    public Character getSex() {
        return sex;
    }

    public void setSex(Character sex) {
        this.sex = sex;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

 

SQL:

Hibernate: 
    drop table if exists t_stu
2018-09-06 21:50:43 [net.sf.ehcache.util.UpdateChecker]-[DEBUG] Checking for update...
2018-09-06 21:50:44 [net.sf.ehcache.util.UpdateChecker]-[DEBUG] Update check failed: java.io.IOException: Server returned HTTP response code: 403 for URL: http://www.terracotta.org/kit/reflector?kitID=ehcache.default&pageID=update.properties&id=-1062731519&os-name=Windows+8.1&jvm-name=Java+HotSpot%28TM%29+64-Bit+Server+VM&jvm-version=1.7.0_80&platform=amd64&tc-version=UNKNOWN&tc-product=Ehcache+Core+2.4.3&source=Ehcache+Core&uptime-secs=1&patch=UNKNOWN
Hibernate: 
    create table t_stu (
        id integer not null,
        address varchar(255),
        age integer,
        birthDay datetime,
        name varchar(255),
        sex char(1),
        primary key (id)
    )

 

 

5.3@Embeddable表示此類一個嵌入類,經常作為另一個類的成員屬性,在生成數據庫表的時候該類的成員會作為其主類的屬性添加到數據庫

例如如下Address是一個嵌入類:

package cn.qlq.domain;

import javax.persistence.Embeddable;

@Embeddable /** 表示此類是一個嵌入類,作為其他類 的成員屬性 **/
public class Address {

    private int addreCode;
    private String addressName;

    public int getAddreCode() {
        return addreCode;
    }

    public void setAddreCode(int addreCode) {
        this.addreCode = addreCode;
    }

    public String getAddressName() {
        return addressName;
    }

    public void setAddressName(String addressName) {
        this.addressName = addressName;
    }

}
package cn.qlq.domain;

import java.util.Date;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

//@Entity(name = "t_student") // 注意包名是javax
@Entity
@Table(name = "t_stu", schema = "hibernate") // 注意包名是javax
public class Student {
    // @Id
    private Integer id;
    private String name;
    private Integer age;
    private Date birthDay;
    private Character sex;
    private Address address;

    @Id
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getBirthDay() {
        return birthDay;
    }

    public void setBirthDay(Date birthDay) {
        this.birthDay = birthDay;
    }

    public Character getSex() {
        return sex;
    }

    public void setSex(Character sex) {
        this.sex = sex;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }
}

 

發出的SQL:

    create table t_stu (
        id integer not null,
 addreCode integer not null,
        addressName varchar(255),
        age integer,
        birthDay datetime,
        name varchar(255),
        sex char(1),
        primary key (id)
    )

 

 

6.屬性級別的注解:

  使用方法有兩種:第一種可以放在屬性的頭頂,第二種可以在屬性的getter方法前面。

主要有以下注解(紅色是重要的):

  @Id,@SequenceGenerator,@GeneratedValue,@Column,@Embedded,@EmbeddedId,@Lob,@Version,@Basic,@Transient

1.@Id注解(必須有)

  定義了映射到數據庫表的主鍵的屬性,一個實體類可以有一個或者多個屬性被映射為主鍵,如果是多個屬性為主鍵屬性,實體必須實現Serializable接口。而且String類型的ID長度不能太長,默認長度是255(超過允許的主鍵長度),所以需要結合@Column指定列的長度。

例如:(注意注解放的位置一致,都放在getter或者屬性前面)

package cn.qlq.domain;

import java.io.Serializable;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

//@Entity(name = "t_student") // 注意包名是javax
@Entity
@Table(name = "t_stu", schema = "hibernate") // 注意包名是javax
public class Student implements Serializable {

    private Integer id;
    private String name;
    private Integer age;
    private Date birthDay;
    private Character sex;
    private Address address;

    @Id
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    @Id
    @Column(length = 8)
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getBirthDay() {
        return birthDay;
    }

    public void setBirthDay(Date birthDay) {
        this.birthDay = birthDay;
    }

    public Character getSex() {
        return sex;
    }

    public void setSex(Character sex) {
        this.sex = sex;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }
}

 

 

 

SQL:


    drop table if exists t_stu

    create table t_stu (
        name varchar(8) not null,
        id integer not null,
        addreCode integer not null,
        addressName varchar(255),
        age integer,
        birthDay datetime,
        sex char(1),
        primary key (name, id)
    )

 

 

mysql> desc t_stu;
+-------------+--------------+------+-----+---------+-------+
| Field       | Type         | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+-------+
| name        | varchar(8)   | NO   | PRI | NULL    |       |
| id          | int(11)      | NO   | PRI | NULL    |       |
| addreCode   | int(11)      | NO   |     | NULL    |       |
| addressName | varchar(255) | YES  |     | NULL    |       |
| age         | int(11)      | YES  |     | NULL    |       |
| birthDay    | datetime     | YES  |     | NULL    |       |
| sex         | char(1)      | YES  |     | NULL    |       |
+-------------+--------------+------+-----+---------+-------+
7 rows in set (0.01 sec)

 

2.GeneratedValue注解---定義注解生成策略

 

 

如下測試都是基於mysql數據庫:

  •  測試int類型(Hibernate)

  Auto是利用一個表生成全局唯一ID。查詢的時候利用for udate鎖住表防止生成重復的ID,這也是生成全局唯一ID的思路。

package cn.qlq.domain;

import java.io.Serializable;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

//@Entity(name = "t_student") // 注意包名是javax
@Entity
@Table(name = "t_stu", schema = "hibernate") // 注意包名是javax
public class Student implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO) // 等價於@GeneratedValue,根據底層數據庫選擇。因為數據庫是mysql,5.0之后是利用表生成全局唯一ID
    private Integer id;
    private String name;
    private Integer age;
    private Date birthDay;
    private Character sex;
    private Address address;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getBirthDay() {
        return birthDay;
    }

    public void setBirthDay(Date birthDay) {
        this.birthDay = birthDay;
    }

    public Character getSex() {
        return sex;
    }

    public void setSex(Character sex) {
        this.sex = sex;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }
}

 

測試類:

package cn.qlq.test;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import cn.qlq.domain.Address;
import cn.qlq.domain.Student;
import cn.qlq.util.HibernateUtil;

public class TestEntityAnno {

    @Test
    public void test1() {
        Session session = HibernateUtil.openSession();
        Transaction tx = session.beginTransaction();
        
        Address a = new Address();
        a.setAddressName("地球");
        
        Student st = new Student();
        st.setAddress(a);

        session.save(st);
        
        tx.commit();
        session.close();
    }
}

 

SQL:

Hibernate: 
    drop table if exists hibernate_sequence
2018-09-06 22:57:34 [net.sf.ehcache.util.UpdateChecker]-[DEBUG] Checking for update...
Hibernate: 
    drop table if exists t_stu
2018-09-06 22:57:34 [net.sf.ehcache.util.UpdateChecker]-[DEBUG] Update check failed: java.io.IOException: Server returned HTTP response code: 403 for URL: http://www.terracotta.org/kit/reflector?kitID=ehcache.default&pageID=update.properties&id=-1062731519&os-name=Windows+8.1&jvm-name=Java+HotSpot%28TM%29+64-Bit+Server+VM&jvm-version=1.7.0_80&platform=amd64&tc-version=UNKNOWN&tc-product=Ehcache+Core+2.4.3&source=Ehcache+Core&uptime-secs=1&patch=UNKNOWN
Hibernate: 
    create table hibernate_sequence (
        next_val bigint
    )
Hibernate: 
    insert into hibernate_sequence values ( 1 )
Hibernate: 
    create table t_stu (
        id integer not null,
        addreCode integer not null,
        addressName varchar(255),
        age integer,
        birthDay datetime,
        name varchar(255),
        sex char(1),
        primary key (id)
    )
Hibernate: 
    select
        next_val as id_val 
    from
        hibernate_sequence for update
            
Hibernate: 
    update
        hibernate_sequence 
    set
        next_val= ? 
    where
        next_val=?
Hibernate: 
    insert 
    into
        t_stu
        (addreCode, addressName, age, birthDay, name, sex, id) 
    values
        (?, ?, ?, ?, ?, ?, ?)

 

總結:

hibernate5.0之后是新建一個數據表生成全局唯一的ID,每次查詢的時候利用update語句去鎖住表然后查詢到ID,然后將表的值加一,並將取出的ID使用上,這也是生成全局唯一ID的一種思路。

mysql> select * from hibernate_sequence;
+----------+
| next_val |
+----------+
|        2 |
+----------+
1 row in set (0.00 sec)

mysql> select * from t_stu;
+----+-----------+-------------+------+----------+------+------+
| id | addreCode | addressName | age  | birthDay | name | sex  |
+----+-----------+-------------+------+----------+------+------+
|  1 |         0 | 地球        | NULL | NULL     | NULL | NULL |
+----+-----------+-------------+------+----------+------+------+
1 row in set (0.06 sec)

 

 

 

我們將int型設為自增:

package cn.qlq.domain;

import java.io.Serializable;
import java.util.Date;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

//@Entity(name = "t_student") // 注意包名是javax
@Entity
@Table(name = "t_stu") // 注意包名是javax
public class Student implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String name;
    private Integer age;
    private Date birthDay;
    private Character sex;
    private Address address;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getBirthDay() {
        return birthDay;
    }

    public void setBirthDay(Date birthDay) {
        this.birthDay = birthDay;
    }

    public Character getSex() {
        return sex;
    }

    public void setSex(Character sex) {
        this.sex = sex;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }
}

 

測試類:

package cn.qlq.test;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import cn.qlq.domain.Address;
import cn.qlq.domain.Student;
import cn.qlq.util.HibernateUtil;

public class TestEntityAnno {

    @Test
    public void test1() {
        Session session = HibernateUtil.openSession();
        Transaction tx = session.beginTransaction();
        
        Address a = new Address();
        a.setAddressName("地球");
        
        Student st = new Student();
        st.setAddress(a);

        session.save(st);
        
        tx.commit();
        session.close();
    }
}

 

SQL:

Hibernate: 
    drop table if exists t_stu
2018-09-06 23:05:19 [net.sf.ehcache.util.UpdateChecker]-[DEBUG] Checking for update...
Hibernate: 
    create table t_stu (
        id integer not null auto_increment,
        addreCode integer not null,
        addressName varchar(255),
        age integer,
        birthDay datetime,
        name varchar(255),
        sex char(1),
        primary key (id)
    )
2018-09-06 23:05:20 [net.sf.ehcache.util.UpdateChecker]-[DEBUG] Update check failed: java.io.IOException: Server returned HTTP response code: 403 for URL: http://www.terracotta.org/kit/reflector?kitID=ehcache.default&pageID=update.properties&id=-1062731519&os-name=Windows+8.1&jvm-name=Java+HotSpot%28TM%29+64-Bit+Server+VM&jvm-version=1.7.0_80&platform=amd64&tc-version=UNKNOWN&tc-product=Ehcache+Core+2.4.3&source=Ehcache+Core&uptime-secs=1&patch=UNKNOWN
Hibernate: 
    insert 
    into
        t_stu
        (addreCode, addressName, age, birthDay, name, sex) 
    values
        (?, ?, ?, ?, ?, ?)

 

 

mysql> desc t_stu;
+-------------+--------------+------+-----+---------+----------------+
| Field       | Type         | Null | Key | Default | Extra          |
+-------------+--------------+------+-----+---------+----------------+
| id          | int(11)      | NO   | PRI | NULL    | auto_increment |
| addreCode   | int(11)      | NO   |     | NULL    |                |
| addressName | varchar(255) | YES  |     | NULL    |                |
| age         | int(11)      | YES  |     | NULL    |                |
| birthDay    | datetime     | YES  |     | NULL    |                |
| name        | varchar(255) | YES  |     | NULL    |                |
| sex         | char(1)      | YES  |     | NULL    |                |
+-------------+--------------+------+-----+---------+----------------+
7 rows in set (0.00 sec)

 

 

  •  測試String類型的UUID生成值與手動設置值

(1)string類型做主鍵手動設置值:(需要結合hibernate的主鍵生成器)

package cn.qlq.domain;

import java.io.Serializable;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import org.hibernate.annotations.GenericGenerator;

//@Entity(name = "t_student") // 注意包名是javax
@Entity
@Table(name = "t_stu") // 注意包名是javax
public class Student implements Serializable {

    private Integer id;
    @Id
    @GeneratedValue(generator = "sid") // 指定生成器d名字
    @GenericGenerator(name = "sid", strategy = "assigned") // hibernate的生成器,name必須與上面一樣
    @Column(length = 40)
    private String name;
    private Integer age;
    private Date birthDay;
    private Character sex;
    private Address address;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getBirthDay() {
        return birthDay;
    }

    public void setBirthDay(Date birthDay) {
        this.birthDay = birthDay;
    }

    public Character getSex() {
        return sex;
    }

    public void setSex(Character sex) {
        this.sex = sex;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }
}

 

測試類:

package cn.qlq.test;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import cn.qlq.domain.Address;
import cn.qlq.domain.Student;
import cn.qlq.util.HibernateUtil;

public class TestEntityAnno {

    @Test
    public void test1() {
        Session session = HibernateUtil.openSession();
        Transaction tx = session.beginTransaction();

        Address a = new Address();
        a.setAddressName("地球");

        Student st = new Student();
        st.setAddress(a);
        st.setName("張三");

        session.save(st);

        tx.commit();
        session.close();
    }
}

 

SQL:

Hibernate: 
    drop table if exists t_stu
create table t_stu (
        name varchar(40) not null,
        addreCode integer not null,
        addressName varchar(255),
        age integer,
        birthDay datetime,
        id integer,
        sex char(1),
        primary key (name)
    )
insert 
    into
        t_stu
        (addreCode, addressName, age, birthDay, id, sex, name) 
    values
        (?, ?, ?, ?, ?, ?, ?)

 

 

mysql> desc t_stu;
+-------------+--------------+------+-----+---------+-------+
| Field       | Type         | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+-------+
| name        | varchar(40)  | NO   | PRI | NULL    |       |
| addreCode   | int(11)      | NO   |     | NULL    |       |
| addressName | varchar(255) | YES  |     | NULL    |       |
| age         | int(11)      | YES  |     | NULL    |       |
| birthDay    | datetime     | YES  |     | NULL    |       |
| id          | int(11)      | YES  |     | NULL    |       |
| sex         | char(1)      | YES  |     | NULL    |       |
+-------------+--------------+------+-----+---------+-------+
7 rows in set (0.00 sec)

mysql> select * from t_stu;
+------+-----------+-------------+------+----------+------+------+
| name | addreCode | addressName | age  | birthDay | id   | sex  |
+------+-----------+-------------+------+----------+------+------+
| 張三 |         0 | 地球        | NULL | NULL     | NULL | NULL |
+------+-----------+-------------+------+----------+------+------+
1 row in set (0.07 sec)

 

 (2)string類型做主鍵UUID生成值:(需要結合hibernate的主鍵生成器)

package cn.qlq.domain;

import java.io.Serializable;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import org.hibernate.annotations.GenericGenerator;

//@Entity(name = "t_student") // 注意包名是javax
@Entity
@Table(name = "t_stu") // 注意包名是javax
public class Student implements Serializable {

    private Integer id;
    @Id
    @GeneratedValue(generator = "uid") // 指定生成器d名字
    @GenericGenerator(name = "uid", strategy = "uuid") // hibernate的生成器,name必須與上面一樣
    @Column(length = 40)
    private String name;
    private Integer age;
    private Date birthDay;
    private Character sex;
    private Address address;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getBirthDay() {
        return birthDay;
    }

    public void setBirthDay(Date birthDay) {
        this.birthDay = birthDay;
    }

    public Character getSex() {
        return sex;
    }

    public void setSex(Character sex) {
        this.sex = sex;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }
}

 

測試類:

package cn.qlq.test;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import cn.qlq.domain.Address;
import cn.qlq.domain.Student;
import cn.qlq.util.HibernateUtil;

public class TestEntityAnno {

    @Test
    public void test1() {
        Session session = HibernateUtil.openSession();
        Transaction tx = session.beginTransaction();

        Address a = new Address();
        a.setAddressName("地球");

        Student st = new Student();
        st.setAddress(a);

        session.save(st);

        tx.commit();
        session.close();
    }
}

 

SQL:


    drop table if exists t_stu

    create table t_stu (
        name varchar(40) not null,
        addreCode integer not null,
        addressName varchar(255),
        age integer,
        birthDay datetime,
        id integer,
        sex char(1),
        primary key (name)
    )

    insert 
    into
        t_stu
        (addreCode, addressName, age, birthDay, id, sex, name) 
    values
        (?, ?, ?, ?, ?, ?, ?)

 

 

mysql> desc t_stu;
+-------------+--------------+------+-----+---------+-------+
| Field       | Type         | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+-------+
| name        | varchar(40)  | NO   | PRI | NULL    |       |
| addreCode   | int(11)      | NO   |     | NULL    |       |
| addressName | varchar(255) | YES  |     | NULL    |       |
| age         | int(11)      | YES  |     | NULL    |       |
| birthDay    | datetime     | YES  |     | NULL    |       |
| id          | int(11)      | YES  |     | NULL    |       |
| sex         | char(1)      | YES  |     | NULL    |       |
+-------------+--------------+------+-----+---------+-------+
7 rows in set (0.00 sec)

mysql> select * from t_stu;
+----------------------------------+-----------+-------------+------+----------
| name                             | addreCode | addressName | age  | birthDay
+----------------------------------+-----------+-------------+------+----------
| 4028818165af748f0165af749da50000 |         0 | 地球        | NULL | NULL
+----------------------------------+-----------+-------------+------+----------
1 row in set (0.00 sec)

 

3.@Column注解(簡單但是重要)

  可將屬性映射到列,使用該注解來覆蓋默認值,@Column描述了數據庫表中該字段的詳細定義,這對於根據JPA注解生成數據庫表結構的工具非常有作用。

常用屬性:

  name:可選,表示數據庫表中該字段的名稱,默認與屬性名稱一致。

  nullable:可選,表示該字段是否允許為null,默認為true

  unique:可選表示該字段是否唯一,默認false。

  length:可選,表示該字段的大小,僅對String類型的字段有效,默認值是255.(如果是主鍵不能使用默認值)

  insertable:可選,表示在ORM框架執行插入操作時,該字段是否應該出現在INSERT語句中,默認為true

  updateable:可選,表示在ORM框架執行更新操作時,該字段是否應該出現在update語句中,默認為true。對於一經創建就不可以更改的字段,該屬性非常有用,比如birthday字段。

 

 

4.@Embedded屬性注解:

  表示該成員屬性是一個嵌入類。在其類上面也要有注解@Embeddable表示此類是一個嵌入類,作為其他類的成員屬性,否則會報錯。如下:

package cn.qlq.domain;

import java.io.Serializable;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import org.hibernate.annotations.GenericGenerator;

//@Entity(name = "t_student") // 注意包名是javax
@Entity
@Table(name = "t_stu") // 注意包名是javax
public class Student implements Serializable {

    private Integer id;
    @Id
    @GeneratedValue(generator = "uid") // 指定生成器d名字
    @GenericGenerator(name = "uid", strategy = "uuid") // hibernate的生成器,name必須與上面一樣
    @Column(length = 40)
    private String name;
    private Integer age;
    private Date birthDay;
    private Character sex;
 @Embedded private Address address;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getBirthDay() {
        return birthDay;
    }

    public void setBirthDay(Date birthDay) {
        this.birthDay = birthDay;
    }

    public Character getSex() {
        return sex;
    }

    public void setSex(Character sex) {
        this.sex = sex;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }
}

 

 

package cn.qlq.domain;
import javax.persistence.Embeddable;
@Embeddable /** 表示此類是一個嵌入類,作為其他類 的成員屬性 **/
public class Address {

    private int addreCode;
    private String addressName;

    public int getAddreCode() {
        return addreCode;
    }

    public void setAddreCode(int addreCode) {
        this.addreCode = addreCode;
    }

    public String getAddressName() {
        return addressName;
    }

    public void setAddressName(String addressName) {
        this.addressName = addressName;
    }

}

 

 

 5.@EmbeddedId屬性注解:

   使用嵌入式主鍵類實現復合主鍵。

  注意:嵌入式主鍵類必須實現Serializable接口、必須有默認的public無參構造方法、必須重寫Object父類的equals方法和hashCode方法。

例如:

package cn.qlq.domain;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

import org.hibernate.annotations.GenericGenerator;

@Embeddable
public class StudentPK implements Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = 1690932463714731211L;
    @Column(length = 40)
    private String idCode;// 身份證號
    @Column(length = 40)
    private String stuNum;// 學號

    public String getIdCode() {
        return idCode;
    }

    public void setIdCode(String idCode) {
        this.idCode = idCode;
    }

    public String getStuNum() {
        return stuNum;
    }

    public void setStuNum(String stuNum) {
        this.stuNum = stuNum;
    }

    public StudentPK() {

    }

    @Override
    public int hashCode() {
        return super.hashCode();
    }

    @Override
    public boolean equals(Object obj) {
        return super.equals(obj);
    }

}

 

 

package cn.qlq.domain;

import java.io.Serializable;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.Embedded;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import org.hibernate.annotations.GenericGenerator;

//@Entity(name = "t_student") // 注意包名是javax
@Entity
@Table(name = "t_stu") // 注意包名是javax
public class Student implements Serializable {
    @EmbeddedId
    private StudentPK studentPK;
    private String name;
    private Integer age;
    private Date birthDay;
    private Character sex;
    @Embedded
    private Address address;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getBirthDay() {
        return birthDay;
    }

    public void setBirthDay(Date birthDay) {
        this.birthDay = birthDay;
    }

    public Character getSex() {
        return sex;
    }

    public void setSex(Character sex) {
        this.sex = sex;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public StudentPK getStudentPK() {
        return studentPK;
    }

    public void setStudentPK(StudentPK studentPK) {
        this.studentPK = studentPK;
    }
}

 

 

測試類:

package cn.qlq.test;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import cn.qlq.domain.Address;
import cn.qlq.domain.Student;
import cn.qlq.domain.StudentPK;
import cn.qlq.util.HibernateUtil;

public class TestEntityAnno {

    @Test
    public void test1() {
        Session session = HibernateUtil.openSession();
        Transaction tx = session.beginTransaction();

        Address a = new Address();
        a.setAddressName("地球");

        StudentPK sp = new StudentPK();
        sp.setIdCode("123456789987654321");
        sp.setStuNum("s001");

        Student st = new Student();
        st.setAddress(a);
        st.setStudentPK(sp);

        session.save(st);

        tx.commit();
        session.close();
    }
}

 

SQL:

drop table if exists t_stu
create table t_stu (
        idCode varchar(40) not null,
        stuNum varchar(40) not null,
        addreCode integer not null,
        addressName varchar(255),
        age integer,
        birthDay datetime,
        name varchar(255),
        sex char(1),
        primary key (idCode, stuNum)
    )
insert 
    into
        t_stu
        (addreCode, addressName, age, birthDay, name, sex, idCode, stuNum) 
    values
        (?, ?, ?, ?, ?, ?, ?, ?)

 

 

mysql> desc t_stu;
+-------------+--------------+------+-----+---------+-------+
| Field       | Type         | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+-------+
| idCode      | varchar(40)  | NO   | PRI | NULL    |       |
| stuNum      | varchar(40)  | NO   | PRI | NULL    |       |
| addreCode   | int(11)      | NO   |     | NULL    |       |
| addressName | varchar(255) | YES  |     | NULL    |       |
| age         | int(11)      | YES  |     | NULL    |       |
| birthDay    | datetime     | YES  |     | NULL    |       |
| name        | varchar(255) | YES  |     | NULL    |       |
| sex         | char(1)      | YES  |     | NULL    |       |
+-------------+--------------+------+-----+---------+-------+
8 rows in set (0.00 sec)

mysql> select * from t_stu\G
*************************** 1. row ***************************
     idCode: 123456789987654321
     stuNum: s001
  addreCode: 0
addressName: 地球
        age: NULL
   birthDay: NULL
       name: NULL
        sex: NULL
1 row in set (0.00 sec)

 

 

6.@Transient注解

  表示該屬性不會映射到數據庫中,ORM框架會忽略該屬性,如果一個屬性不是數據庫的映射必須添加這個注解,否則ORM框架會自動將其注解為@Basic.

import java.io.Serializable;
import java.util.Date;

import javax.persistence.Embedded;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Transient;

//@Entity(name = "t_student") // 注意包名是javax
@Entity
@Table(name = "t_stu") // 注意包名是javax
public class Student implements Serializable {
    @EmbeddedId
    private StudentPK studentPK;
    private String name;
    private Integer age;
    private Date birthDay;
    private Character sex;
 @Transient private Double salary;
    @Embedded
    private Address address;
    ....
}

 

7.@Lob注解

  映射為mysql的longtext類型和oracle的clob類型。而且Lob字段不能添加索引.我們直接在數據庫對text字段添加索引會報錯:

BLOB/TEXT column 'description' used in key specification without a key length

 

 

  如下代碼只創字段不加索引:

    @Lob
    @Index(name="description")
    private String description;

 

 

 

 

7.關聯關系級別的注解

實體之間的映射關系:

一對一:一個人一個身份證號

一對多(多對一):一個人與銀行賬號

多對多:一個學生有多個老師,一個老師教多個學生。

1.一對一單向外鍵關聯(一個人對一個身份證號)

兩個重要的注解:

@OneToOne(cascade = CascadeType.ALL) 
@JoinColumn(name = "IdCardPid", unique = true, referencedColumnName="pid")
    name:在本表中外鍵的名稱,unique是否唯一,referencedColumnName外鍵列(默認是另一個實體的主鍵),columnDefinition:列類型的定義

例如:

package cn.qlq.AnnotationRelation.One2One;

import java.io.Serializable;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;

import org.hibernate.annotations.Cascade;

@Entity
public class Student implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private Integer age;
    private Character sex;
    private Double salary;

    // 關聯的身份證
    @OneToOne(cascade = CascadeType.ALL) 
    @JoinColumn(name = "IdCardPid", unique = true, referencedColumnName = "pid")
    private IdCard idCard;

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Double getSalary() {
        return salary;
    }

    public void setSalary(Double salary) {
        this.salary = salary;
    }

    public Character getSex() {
        return sex;
    }

    public void setSex(Character sex) {
        this.sex = sex;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public IdCard getIdCard() {
        return idCard;
    }

    public void setIdCard(IdCard idCard) {
        this.idCard = idCard;
    }
}

 

 

package cn.qlq.AnnotationRelation.One2One;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

import org.hibernate.annotations.GenericGenerator;

@Entity
public class IdCard {
    @Id
    @Column(length = 40)
    @GeneratedValue(generator = "uid")
    @GenericGenerator(name = "uid", strategy = "uuid")
    private String pid;
    private String sname;
    private Date birthDay;

    public String getPid() {
        return pid;
    }

    public void setPid(String pid) {
        this.pid = pid;
    }

    public String getSname() {
        return sname;
    }

    public void setSname(String sname) {
        this.sname = sname;
    }

    public Date getBirthDay() {
        return birthDay;
    }

    public void setBirthDay(Date birthDay) {
        this.birthDay = birthDay;
    }
}

 

 

測試:

package cn.qlq.test;

import java.util.Date;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import cn.qlq.AnnotationRelation.One2One.IdCard;
import cn.qlq.AnnotationRelation.One2One.Student;
import cn.qlq.util.HibernateUtil;

public class TestEntityAnno {

    @Test
    public void test1() {
        Session session = HibernateUtil.openSession();
        Transaction tx = session.beginTransaction();

        Student st = new Student();
        st.setSalary(7500d);
        IdCard idCard = new IdCard();
        idCard.setSname("qlq");
        idCard.setBirthDay(new Date());

        st.setIdCard(idCard);
        
        session.save(idCard);
        session.save(st);

        tx.commit();
        session.close();
    }
}

 

 

SQL:

alter table Student 
        drop 
        foreign key FKo88r74j7fjtuhwfra81068y61

    drop table if exists IdCard
drop table if exists Student

    create table IdCard (
        pid varchar(40) not null,
        birthDay datetime,
        sname varchar(255),
        primary key (pid)
    )
   create table Student (
        id bigint not null auto_increment,
        age integer,
        salary double precision,
        sex char(1),
        IdCardPid varchar(40),
        primary key (id)
    )

    alter table Student 
        add constraint UK_pn1nraxgy15mgjcvs474bl5bd unique (IdCardPid)

    alter table Student 
        add constraint FKo88r74j7fjtuhwfra81068y61 
        foreign key (IdCardPid) 
        references IdCard (pid)

    insert 
    into
        IdCard
        (birthDay, sname, pid) 
    values
        (?, ?, ?)

    insert 
    into
        Student
        (age, IdCardPid, salary, sex) 
    values
        (?, ?, ?, ?)

 

結果:

mysql> desc student;
+-----------+-------------+------+-----+---------+----------------+
| Field     | Type        | Null | Key | Default | Extra          |
+-----------+-------------+------+-----+---------+----------------+
| id        | bigint(20)  | NO   | PRI | NULL    | auto_increment |
| age       | int(11)     | YES  |     | NULL    |                |
| salary    | double      | YES  |     | NULL    |                |
| sex       | char(1)     | YES  |     | NULL    |                |
| IdCardPid | varchar(40) | YES  | UNI | NULL    |                |
+-----------+-------------+------+-----+---------+----------------+
5 rows in set (0.01 sec)

mysql> desc idcard;
+----------+--------------+------+-----+---------+-------+
| Field    | Type         | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+-------+
| pid      | varchar(40)  | NO   | PRI | NULL    |       |
| birthDay | datetime     | YES  |     | NULL    |       |
| sname    | varchar(255) | YES  |     | NULL    |       |
+----------+--------------+------+-----+---------+-------+
3 rows in set (0.01 sec)

mysql> select * from student;
+----+------+--------+------+----------------------------------+
| id | age  | salary | sex  | IdCardPid                        |
+----+------+--------+------+----------------------------------+
|  1 | NULL |   7500 | NULL | 4028818165b73b770165b73b8ffe0000 |
+----+------+--------+------+----------------------------------+
1 row in set (0.00 sec)

mysql> select * from idcard;
+----------------------------------+---------------------+-------+
| pid                              | birthDay            | sname |
+----------------------------------+---------------------+-------+
| 4028818165b73b770165b73b8ffe0000 | 2018-09-08 11:30:59 | qlq   |
+----------------------------------+---------------------+-------+
1 row in set (0.00 sec)

 

2.一對一對雙向外鍵關聯 (一方維護關系,另一方放棄維護關系)

主控方的配置與上面一樣,只是被控方增加一個配置。(Student是主控方,IdCard是被控方)

@OneToOne(mappedBy = "idCard")

  必須設置mapperedBy屬性。因為雙向關聯只能交給一方去控制,不可能在雙方都保存外鍵關系,否則會導致雙方都保存不進去。

如下:

Student.java與上面一樣:

 

 IdCard.java修改配置:

package cn.qlq.AnnotationRelation.One2One;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;

import org.hibernate.annotations.GenericGenerator;

@Entity
public class IdCard {
    @Id
    @Column(length = 40)
    @GeneratedValue(generator = "uid")
    @GenericGenerator(name = "uid", strategy = "uuid")
    private String pid;
    private String sname;
    private Date birthDay;
    @OneToOne(mappedBy = "idCard")
    private Student student;

    public String getPid() {
        return pid;
    }

    public void setPid(String pid) {
        this.pid = pid;
    }

    public String getSname() {
        return sname;
    }

    public void setSname(String sname) {
        this.sname = sname;
    }

    public Date getBirthDay() {
        return birthDay;
    }

    public void setBirthDay(Date birthDay) {
        this.birthDay = birthDay;
    }

    public Student getStudent() {
        return student;
    }

    public void setStudent(Student student) {
        this.student = student;
    }

    @Override
    public String toString() {
        return "IdCard [pid=" + pid + ", sname=" + sname + ", birthDay=" + birthDay + ", student=" + student + "]";
    }
}

 

 

  上面SQL生成的與上面的一樣,不會再IdCard表中維護Student的外鍵,否則會導致雙方都保存不進去。

測試查詢SQL:

    @Test
    public void test2() {
        Session session = HibernateUtil.openSession();
        Transaction tx = session.beginTransaction();

        String hql = "from IdCard";
        Query query = session.createQuery(hql);
        List list = query.list();
        System.out.println(list);
        tx.commit();
        session.close();
    }

 

結果:(會自動映射Student信息到IDCard類中)

Hibernate: 
    select
        idcard0_.pid as pid1_0_,
        idcard0_.birthDay as birthDay2_0_,
        idcard0_.sname as sname3_0_ 
    from
        IdCard idcard0_
Hibernate: 
    select
        student0_.id as id1_1_1_,
        student0_.age as age2_1_1_,
        student0_.IdCardPid as IdCardPi5_1_1_,
        student0_.salary as salary3_1_1_,
        student0_.sex as sex4_1_1_,
        idcard1_.pid as pid1_0_0_,
        idcard1_.birthDay as birthDay2_0_0_,
        idcard1_.sname as sname3_0_0_ 
    from
        Student student0_ 
    left outer join
        IdCard idcard1_ 
            on student0_.IdCardPid=idcard1_.pid 
    where
        student0_.IdCardPid=?

 

3.多對一單向外鍵關聯

多方持有一方的引用,比如多個學生對一個班級,學生中有班級的引用。例如:

Student.java

package cn.qlq.AnnotationRelation.ManyToOne;

import java.io.Serializable;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;

@Entity
public class Student implements Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = -624145366487777133L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private Integer age;
    private Character sex;
    private Double salary;
    @ManyToOne(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER)
    @JoinColumn(name = "classId")
    private ClassRoom classRoom;

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Double getSalary() {
        return salary;
    }

    public void setSalary(Double salary) {
        this.salary = salary;
    }

    public Character getSex() {
        return sex;
    }

    public void setSex(Character sex) {
        this.sex = sex;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public ClassRoom getClassRoom() {
        return classRoom;
    }

    public void setClassRoom(ClassRoom classRoom) {
        this.classRoom = classRoom;
    }

}

 

ClssRoom.class

package cn.qlq.AnnotationRelation.ManyToOne;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

import org.hibernate.annotations.GenericGenerator;

/**
 * 班級類
 * 
 * @author liqiang
 *
 */
@Entity
public class ClassRoom {
    @Id
    @Column(length = 40)
    @GeneratedValue(generator = "uid")
    @GenericGenerator(name = "uid", strategy = "uuid")
    private String cid;
    private String className;

    public String getCid() {
        return cid;
    }

    public void setCid(String cid) {
        this.cid = cid;
    }

    public String getClassName() {
        return className;
    }

    public void setClassName(String className) {
        this.className = className;
    }

}

 

測試代碼:

    @Test
    public void test1() {
        Session session = HibernateUtil.openSession();
        Transaction tx = session.beginTransaction();

        Student st1 = new Student();
        st1.setSalary(7500d);

        Student st2 = new Student();
        st2.setSalary(17500d);

        ClassRoom c = new ClassRoom();
        c.setClassName("大軟一");

        st1.setClassRoom(c);
        st2.setClassRoom(c);

        session.save(c);
        session.save(st1);
        session.save(st2);

        tx.commit();
        session.close();
    }

 

結果:

mysql> desc student;
+---------+-------------+------+-----+---------+----------------+
| Field   | Type        | Null | Key | Default | Extra          |
+---------+-------------+------+-----+---------+----------------+
| id      | bigint(20)  | NO   | PRI | NULL    | auto_increment |
| age     | int(11)     | YES  |     | NULL    |                |
| salary  | double      | YES  |     | NULL    |                |
| sex     | char(1)     | YES  |     | NULL    |                |
| classId | varchar(40) | YES  | MUL | NULL    |                |
+---------+-------------+------+-----+---------+----------------+
5 rows in set (0.01 sec)

mysql> desc classroom;
+-----------+--------------+------+-----+---------+-------+
| Field     | Type         | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+-------+
| cid       | varchar(40)  | NO   | PRI | NULL    |       |
| className | varchar(255) | YES  |     | NULL    |       |
+-----------+--------------+------+-----+---------+-------+
2 rows in set (0.01 sec)

mysql> select * from classroom;
+----------------------------------+-----------+
| cid                              | className |
+----------------------------------+-----------+
| 4028818165b95ddb0165b95df06d0000 | 大軟一    |
+----------------------------------+-----------+
1 row in set (0.01 sec)

mysql> select * from student;
+----+------+--------+------+----------------------------------+
| id | age  | salary | sex  | classId                          |
+----+------+--------+------+----------------------------------+
|  1 | NULL |   7500 | NULL | 4028818165b95ddb0165b95df06d0000 |
|  2 | NULL |  17500 | NULL | 4028818165b95ddb0165b95df06d0000 |
+----+------+--------+------+----------------------------------+
2 rows in set (0.00 sec)

 

 

4.一對多的單向外鍵關聯(注意:一對多的時候多方的抓取策略設置為EAGER,一方設置為lazy)

  一方持有多方的集合

  例如:一個班級對應多個學生

多方:

 

 一方:

 

 

 

 測試代碼:

    @Test
    public void test1() {
        Session session = HibernateUtil.openSession();
        Transaction tx = session.beginTransaction();

        Student st1 = new Student();
        st1.setSalary(7500d);

        Student st2 = new Student();
        st2.setSalary(17500d);

        ClassRoom c = new ClassRoom();
        c.setClassName("大軟一");

        c.getStudents().add(st1);
        c.getStudents().add(st2);

        session.save(st1);
        session.save(st2);
        session.save(c);

        tx.commit();
        session.close();
    }

 

 結果:

mysql> desc classroom;
+-----------+--------------+------+-----+---------+-------+
| Field     | Type         | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+-------+
| cid       | varchar(40)  | NO   | PRI | NULL    |       |
| className | varchar(255) | YES  |     | NULL    |       |
+-----------+--------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

mysql> desc student;
+-------------+-------------+------+-----+---------+----------------+
| Field       | Type        | Null | Key | Default | Extra          |
+-------------+-------------+------+-----+---------+----------------+
| id          | bigint(20)  | NO   | PRI | NULL    | auto_increment |
| age         | int(11)     | YES  |     | NULL    |                |
| salary      | double      | YES  |     | NULL    |                |
| sex         | char(1)     | YES  |     | NULL    |                |
| classroomId | varchar(40) | YES  | MUL | NULL    |                |
+-------------+-------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)

mysql> select * from student;
+----+------+--------+------+----------------------------------+
| id | age  | salary | sex  | classroomId                      |
+----+------+--------+------+----------------------------------+
|  1 | NULL |   7500 | NULL | 4028818165b96ce90165b96d0c970000 |
|  2 | NULL |  17500 | NULL | 4028818165b96ce90165b96d0c970000 |
+----+------+--------+------+----------------------------------+
2 rows in set (0.00 sec)

mysql> select * from classroom;
+----------------------------------+-----------+
| cid                              | className |
+----------------------------------+-----------+
| 4028818165b9697c0165b96998ab0000 | 大軟一    |
| 4028818165b96ce90165b96d0c970000 | 大軟一    |
+----------------------------------+-----------+
2 rows in set (0.00 sec)

 

 

 5.多對一的雙向外鍵關聯關系(數據庫仍然是一的一方存多的一方的外鍵)

 多的一方持有一的一方的引用:

    @ManyToOne(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER)
    @JoinColumn(name = "classroomId")

 

 

一的一方持有多的一方的集合:

    // 一方持有多方的集合
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "classroomId") // 定義在student添加的外鍵的列名

 

 

 例如:

 

 

 

測試代碼:

    @Test
    public void test1() {
        Session session = HibernateUtil.openSession();
        Transaction tx = session.beginTransaction();

        Student st1 = new Student();
        st1.setSalary(7500d);

        Student st2 = new Student();
        st2.setSalary(17500d);

        ClassRoom c = new ClassRoom();
        c.setClassName("大軟一");

        c.getStudents().add(st1);
        c.getStudents().add(st2);
        st1.setClassRoom(c);
        st2.setClassRoom(c);

        session.save(st1);
        session.save(st2);
        session.save(c);

        tx.commit();
        session.close();
    }

 

結果:

mysql> desc student;
+-------------+-------------+------+-----+---------+----------------+
| Field       | Type        | Null | Key | Default | Extra          |
+-------------+-------------+------+-----+---------+----------------+
| id          | bigint(20)  | NO   | PRI | NULL    | auto_increment |
| age         | int(11)     | YES  |     | NULL    |                |
| salary      | double      | YES  |     | NULL    |                |
| sex         | char(1)     | YES  |     | NULL    |                |
| classroomId | varchar(40) | YES  | MUL | NULL    |                |
+-------------+-------------+------+-----+---------+----------------+
5 rows in set (0.02 sec)

mysql> desc classroom;
+-----------+--------------+------+-----+---------+-------+
| Field     | Type         | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+-------+
| cid       | varchar(40)  | NO   | PRI | NULL    |       |
| className | varchar(255) | YES  |     | NULL    |       |
+-----------+--------------+------+-----+---------+-------+
2 rows in set (0.01 sec)

mysql> select * from student;
+----+------+--------+------+----------------------------------+
| id | age  | salary | sex  | classroomId                      |
+----+------+--------+------+----------------------------------+
|  1 | NULL |  17500 | NULL | 4028818165b971c90165b971e4920000 |
|  2 | NULL |   7500 | NULL | 4028818165b971c90165b971e4920000 |
+----+------+--------+------+----------------------------------+
2 rows in set (0.00 sec)

mysql> select * from classroom;
+----------------------------------+-----------+
| cid                              | className |
+----------------------------------+-----------+
| 4028818165b971c90165b971e4920000 | 大軟一    |
+----------------------------------+-----------+
1 row in set (0.00 sec)

 

 

6.多對多的單向外鍵關聯關系

典型的應用:教師和學生之間是多對多的關系。

  學生實體類有教師實體類的集合

@Entity
public class Student implements Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = -624145366487777133L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private Integer age;
    private Character sex;
    private Double salary;
    @ManyToMany
    @JoinTable(name = "teacher_student", joinColumns = { @JoinColumn(name = "studentId") }, inverseJoinColumns = {
            @JoinColumn(name = "teacherId") })
    private Set<Teacher> teachers = new HashSet();
...
}

 

  JoinTable的name屬性是中間表的名字,@JoinColumn是本實體類在中間表的外鍵列名字,inverseJoinColumns是設置對應的教師在中間表的列信息。

 

@Entity
public class Teacher {
    @Id
    @Column(length = 40)
    @GeneratedValue(generator = "uid")
    @GenericGenerator(name = "uid", strategy = "uuid")
    private String teacherId;
    private String teacherName;
。。。
}

 

測試代碼:

    @Test
    public void test1() {
        Session session = HibernateUtil.openSession();
        Transaction tx = session.beginTransaction();

        Student st1 = new Student();
        st1.setSalary(7500d);

        Student st2 = new Student();
        st2.setSalary(17500d);

        Teacher t1 = new Teacher();
        t1.setTeacherName("張三");

        Teacher t2 = new Teacher();
        t2.setTeacherName("李四");

        st1.getTeachers().add(t1);
        st1.getTeachers().add(t2);

        st2.getTeachers().add(t1);
        st2.getTeachers().add(t2);

        session.save(t1);
        session.save(t2);
        session.save(st1);
        session.save(st2);

        tx.commit();
        session.close();
    }

 

結果:

mysql> desc student;
+--------+------------+------+-----+---------+----------------+
| Field  | Type       | Null | Key | Default | Extra          |
+--------+------------+------+-----+---------+----------------+
| id     | bigint(20) | NO   | PRI | NULL    | auto_increment |
| age    | int(11)    | YES  |     | NULL    |                |
| salary | double     | YES  |     | NULL    |                |
| sex    | char(1)    | YES  |     | NULL    |                |
+--------+------------+------+-----+---------+----------------+
4 rows in set (0.03 sec)

mysql> desc teacher;
+-------------+--------------+------+-----+---------+-------+
| Field       | Type         | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+-------+
| teacherId   | varchar(40)  | NO   | PRI | NULL    |       |
| teacherName | varchar(255) | YES  |     | NULL    |       |
+-------------+--------------+------+-----+---------+-------+
2 rows in set (0.01 sec)

mysql> desc teacher_student;
+-----------+-------------+------+-----+---------+-------+
| Field     | Type        | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| id        | bigint(20)  | NO   | PRI | NULL    |       |
| teacherId | varchar(40) | NO   | PRI | NULL    |       |
+-----------+-------------+------+-----+---------+-------+
2 rows in set (0.10 sec)

mysql> select * from student;
Empty set (0.01 sec)

mysql> select * from student;desc ^C
mysql> desc student;
+--------+------------+------+-----+---------+----------------+
| Field  | Type       | Null | Key | Default | Extra          |
+--------+------------+------+-----+---------+----------------+
| id     | bigint(20) | NO   | PRI | NULL    | auto_increment |
| age    | int(11)    | YES  |     | NULL    |                |
| salary | double     | YES  |     | NULL    |                |
| sex    | char(1)    | YES  |     | NULL    |                |
+--------+------------+------+-----+---------+----------------+
4 rows in set (0.03 sec)

mysql> desc teacher;
+-------------+--------------+------+-----+---------+-------+
| Field       | Type         | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+-------+
| teacherId   | varchar(40)  | NO   | PRI | NULL    |       |
| teacherName | varchar(255) | YES  |     | NULL    |       |
+-------------+--------------+------+-----+---------+-------+
2 rows in set (0.01 sec)

mysql> desc teacher_student;
+-----------+-------------+------+-----+---------+-------+
| Field     | Type        | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| studentId | bigint(20)  | NO   | PRI | NULL    |       |
| teacherId | varchar(40) | NO   | PRI | NULL    |       |
+-----------+-------------+------+-----+---------+-------+
2 rows in set (0.01 sec)

mysql> select * from teacher;
+----------------------------------+-------------+
| teacherId                        | teacherName |
+----------------------------------+-------------+
| 4028818165b9a53b0165b9a55ae80000 | 張三        |
| 4028818165b9a53b0165b9a55b470001 | 李四        |
+----------------------------------+-------------+
2 rows in set (0.06 sec)

mysql> select * from student;
+----+------+--------+------+
| id | age  | salary | sex  |
+----+------+--------+------+
|  1 | NULL |   7500 | NULL |
|  2 | NULL |  17500 | NULL |
+----+------+--------+------+
2 rows in set (0.00 sec)

mysql> select * from teacher_student;
+-----------+----------------------------------+
| studentId | teacherId                        |
+-----------+----------------------------------+
|         1 | 4028818165b9a53b0165b9a55ae80000 |
|         2 | 4028818165b9a53b0165b9a55ae80000 |
|         1 | 4028818165b9a53b0165b9a55b470001 |
|         2 | 4028818165b9a53b0165b9a55b470001 |
+-----------+----------------------------------+
4 rows in set (0.00 sec)

 

 

7.多對多的雙向外鍵關聯(一方維護關系,另一方放棄維護關系)

雙方都有另一方的集合對象。其中一方的設置主要是一方維護映射關系,另一方配置維護關系由對方維護。下面的例子是Student維護關系,Teacher放棄維護關系

@Entity
public class Student implements Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = -624145366487777133L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private Integer age;
    private Character sex;
    private Double salary;
 @ManyToMany @JoinTable(name = "teacher_student", joinColumns = { @JoinColumn(name = "studentId") }, inverseJoinColumns = {
            @JoinColumn(name = "teacherId") })
    private Set<Teacher> teachers = new HashSet();
...
}

 

 

@Entity
public class Teacher {
    @Id
    @Column(length = 40)
    @GeneratedValue(generator = "uid")
    @GenericGenerator(name = "uid", strategy = "uuid")
    private String teacherId;
    private String teacherName;
    @ManyToMany(mappedBy = "teachers") // 表示關系是多對多,且維護關系交給student的teachers屬性
    private Set<Student> students = new HashSet();
..
}

 

 

測試代碼:

    @Test
    public void test2() {
        Session session = HibernateUtil.openSession();
        Transaction tx = session.beginTransaction();

        String hql = "from Teacher";
        Query query = session.createQuery(hql);
        List<Teacher> list = query.list();
        for (Teacher t : list) {
            System.out.println(t.getTeacherName());
            System.out.println(t.getStudents().size());
        }

        String hql1 = "from Student";
        Query query1 = session.createQuery(hql1);
        List<Student> list1 = query1.list();
        for (Student t : list1) {
            System.out.println(t.getSalary());
            System.out.println(t.getTeachers().size());
        }
        tx.commit();
        session.close();
    }

 

結果:

張三
2
李四
2
7500.0
2
17500.0
2

 

補充:

1.對於hibernate5.0之后的cascade屬性默認為空,所以如果我們想級聯操作需要手動配置:例如下面學生設置級聯屬性

 

 

 

 

測試代碼:

    @Test
    public void test1() {
        Session session = HibernateUtil.openSession();
        Transaction tx = session.beginTransaction();

        Student st1 = new Student();
        st1.setSalary(7500d);

        Student st2 = new Student();
        st2.setSalary(17500d);

        Teacher t1 = new Teacher();
        t1.setTeacherName("張三");

        Teacher t2 = new Teacher();
        t2.setTeacherName("李四");

        st1.getTeachers().add(t1);
        st1.getTeachers().add(t2);

        st2.getTeachers().add(t1);
        st2.getTeachers().add(t2);

        session.save(st1);
        session.save(st2);
//        session.save(t1);//設置級聯操作保存學生會級聯保存教師
//        session.save(t2);//設置級聯操作保存學生會級聯保存教師


        tx.commit();
        session.close();
    }

 

 

2.Hibernate注解也可以添加索引

(1)第一種方式:

    @Column(unique = true) // 默認值是false,為true會添加索引
    private Double salary;

 

 

 

mysql> show create table student\G
*************************** 1. row ***************************
       Table: student
Create Table: CREATE TABLE `student` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `age` int(11) DEFAULT NULL,
  `salary` double DEFAULT NULL,
  `sex` char(1) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `UK_jr6uyypqhsuj4nf8lw2w5ninn` (`salary`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8
1 row in set (0.01 sec)

 

 

 (2)第二種方式:(使用hibernate包的Index注解)

    @Index(name = "sexIndex")//該注解來自Hibernate包
    private Character sex;

 

 

mysql> show create table student\G
*************************** 1. row ***************************
       Table: student
Create Table: CREATE TABLE `student` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `age` int(11) DEFAULT NULL,
  `salary` double DEFAULT NULL,
  `sex` char(1) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `UK_jr6uyypqhsuj4nf8lw2w5ninn` (`salary`),
  KEY `sexIndex` (`sex`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

 

 

(3)第三種方式:(建議這種,方便而且可以建立組合索引)

 

@Entity
@Table(indexes = { @Index(name = "sexSalaryIndex", columnList = "sex,salary"),
        @Index(name = "sexIndex", columnList = "sex", unique = true) })
public class Student implements Serializable {

 

mysql> show create table student\G
*************************** 1. row ***************************
       Table: student
Create Table: CREATE TABLE `student` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `age` int(11) DEFAULT NULL,
  `salary` double DEFAULT NULL,
  `sex` char(1) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `UK_jr6uyypqhsuj4nf8lw2w5ninn` (`salary`),
  KEY `sexIndex` (`sex`),
  KEY `sexSalaryIndex` (`sex`,`salary`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM