hibernate学习笔记之二(映射关系与懒加载)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: hibernate学习笔记之二(映射关系与懒加载)

hibernate 映射关系


关系型数据库中,多表之间存在三种关联关系,分别为一对一,一对多和多对多。

0fd400cd9ede4c6da3c21540be8b9aa3.png主外键的添加:


  • 一对一:在任意一方引入对方主键作为外键。
  • 一对多:在“多”的一方,添加“一”的一方的主键作为外键。
  • 多对多:产生中间关系表,引入两张表的主键作为外键,两个主键成为联合主键。


275f09217c5b432e9f0f213a5771b615.png


一对一的关系就是在本类中定义对方类型的对象,如 A 类中定义 B 类类型的属性 b,B 类中定义 A 类类型的属性 a;一对多的关系,在一个 A 类类型对应多个 B 类类型的情况下,需要在 A 类以 Set 集合的方式引入 B 类类型的对象,在 B 类中定义 A 类类型的属性 a;多对多的关系,在 A 类中定义 B 类类型的 Set 集合,在 B 类中定义 A 类类型的 Set 集合,这里用 Set 集合的目的是避免数据的重复。


一对一关系映射


场景:如我们的身份证,一个人只有一个身份证,而一个身份证也就只对应一个人。还有其他的证件也是如此。


主键关联:


即让两个对象具有相同的主键值,以表明它们之间的一一对应的关系;数据库表不会有额外的字段来维护它们之间的关系,仅通过表的主键来关联。(可以自动级联)


6d3757e184b141d9a2f1bcc11dfce058.png

9ceebf994ffd492d892947ab0b49a219.png


环境搭建:

pom.xml


<dependencies>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.20</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
    </dependency>
    <dependency>
        <groupId>c3p0</groupId>
        <artifactId>c3p0</artifactId>
        <version>0.9.1.2</version>
    </dependency>
    <!-- 添加Hibernate依赖 -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-annotations</artifactId>
        <version>3.2.1.ga</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>3.2.1.ga</version>
    </dependency>
    <!--    SLF4J-->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.32</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-nop</artifactId>
        <version>1.7.2</version>
    </dependency>
    <!-- 添加javassist -->
    <dependency>
        <groupId>javassist</groupId>
        <artifactId>javassist</artifactId>
        <version>3.12.0.GA</version>
    </dependency>
    <!-- mysql数据库的驱动包 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.6</version>
    </dependency>
</dependencies>
<build>
    <!--配置Maven 对resource文件 过滤 -->
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
                <include>**/*.xls</include>
                <include>**/*.xlsx</include>
            </includes>
            <filtering>true</filtering>
        </resource>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>


log4j.xml


### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### direct messages to file hibernate.log ###
#log4j.appender.file=org.apache.log4j.FileAppender
#log4j.appender.file.File=hibernate.log
#log4j.appender.file.layout=org.apache.log4j.PatternLayout
#log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### set log levels - for more verbose logging change 'info' to 'debug' ###
log4j.rootLogger=warn, stdout
log4j.logger.org.hibernate=info
#log4j.logger.org.hibernate=debug
### log HQL query parser activity
#log4j.logger.org.hibernate.hql.ast.AST=debug
### log just the SQL
#log4j.logger.org.hibernate.SQL=debug
### log JDBC bind parameters ###
log4j.logger.org.hibernate.type=info
#log4j.logger.org.hibernate.type=debug
### log schema export/update ###
log4j.logger.org.hibernate.tool.hbm2ddl=debug
### log HQL parse trees
#log4j.logger.org.hibernate.hql=debug
### log cache activity ###
#log4j.logger.org.hibernate.cache=debug
### log transaction activity
#log4j.logger.org.hibernate.transaction=debug
### log JDBC resource acquisition
#log4j.logger.org.hibernate.jdbc=debug
### enable the following line if you want to track down connection ###
### leakages when using DriverManagerConnectionProvider ###
#log4j.logger.org.hibernate.connection.DriverManagerConnectionProvider=trace


工具类:


package com.hibernate;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtils {
    private static SessionFactory factory;
    static {
        try {
            Configuration cfg = new Configuration().configure();
            factory = cfg.buildSessionFactory();
        }catch(Exception e) {
            e.printStackTrace();
        }
    }
    public static SessionFactory getSessionFactory() {
        return factory;
    }
    public static Session getSession() {
        return factory.openSession();
    }
    public static void closeSession(Session session) {
        if (session != null) {
            if (session.isOpen()) {
                session.close();
            }
        }
    }
}


实体类:

the code of IdCard.java


package com.hibernate;
public class IdCard {
    private int id;
    private String cardNo;
    public String getCardNo() {
        return cardNo;
    }
    public void setCardNo(String cardNo) {
        this.cardNo = cardNo;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
}


the code of Person.java


package com.hibernate;
public class Person {
    private int id;
    private String name;
    private IdCard idCard;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public IdCard getIdCard() {
        return idCard;
    }
    public void setIdCard(IdCard idCard) {
        this.idCard = idCard;
    }
}


hibernate.cfg.xml


<!DOCTYPE hibernate-configuration PUBLIC
   "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
   "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
   <session-factory>  
   <property name="hibernate.connection.url">jdbc:mysql://localhost/hibernatelearn</property>
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
   <property name="hibernate.connection.username">root</property>
   <property name="hibernate.connection.password">root</property>
   <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
   <property name="hibernate.show_sql">true</property>
   <mapping resource="Person.hbm.xml"/>
   <mapping resource="IdCard.hbm.xml"/>
   </session-factory>
</hibernate-configuration>


测试:


@Test
public void test(){
            //读取hibernate.cfg.xml文件
        Configuration cfg=new Configuration().configure();
        SchemaExport export=new SchemaExport(cfg);
        export.create(true, true);
}


IdCard.hbm.xml


<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
   "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
   "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
 <class name="com.hibernate.IdCard" table="t_idcard">
 <id name="id">
   <generator class="native"/> 
   </id>
   <property name="cardNo"/> 
 </class>
</hibernate-mapping>


Person.hbm.xml


<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
   "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
   "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
 <class name="com.hibernate.Person" table="t_person">
     <id name="id">
         <generator class="foreign" >
             <param name="property">idCard</param>
         </generator>
     </id>
   <property name="name"/>
            <one-to-one name="idCard" class="com.hibernate.IdCard" constrained="true"/>
 </class>
</hibernate-mapping>


在上面的代码中我们需要特别注意的就是主键生成机制,以及one-to-one标签里的代码。


在one-to-one节点中对一对一关系进行申明。上面的配置中:


  1. 通过one-to-one节点,我们将User类与IdCard类相关联
  2. constrained(约束),只能在one-to-one的映射中使用,一般在主表映射中,有外键的那个表,如果constrained=true,则表明存在外键与关联表对应,并且关联表中肯定存在对应的键与其对应,另外,该选项最关键的是影响save和deleted先后顺序,如果是增加的时候,如果constrained=true则会增加关联表,然后增加本表,删除的时候是先删除本表然后删除关联的表。
  3. one-to-one的单向关联中,如果constrained=false则会在查询的时候全部取出来,用left outer join的方式 如果constrained=true,hibernate会延迟加载sql,只会把主表查询出来,等有用到关联表的时候再发出sql语句去取出来
  4. 使主键生成器与外键共享主键的值。也就是说两张表的id是一样的。


测试:


    @Test
    public void testSave1(){
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            IdCard idCard=new IdCard();
            idCard.setCardNo("8888888888");
//            session.save(idCard);
            Person person=new Person();
            person.setName("zs");
            person.setIdCard(idCard);
            session.save(person);
            Person person1=new Person();
            person1.setName("lis1");
            person1.setIdCard(idCard);
            //一对一主键关联影射中,默认了cascade属性 所以不会出现TransientObjectException异常
            // session.save(person1);
            session.getTransaction().commit();
        }catch(Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally {
            HibernateUtils.closeSession(session);
        }
    }


上面的测试代码中需要特别注意没有对idCard进行存储。那么会发什么呢。这里我们session.save(idCard);打个断点,发现执行完save语句后。hibernate发送了一条insert语句。


9fb961b1830048d3b1e46d6680b030b8.png


也就是说在此处hibernate想数据库添加了一条数据。(constrained=true则会增加关联表,然后增加本表。)接着事件提交后hibernate就会想数据库中插入本表的数据。

查询:


public void testLoad1(){
    Session session = null;
    try {
        session = HibernateUtils.getSession();
        session.beginTransaction();
        Person person=(Person)session.load(Person.class,21);
        System.out.println ("person.name="+person.getName());
        System.out.println ("idCard.cardNo="+person.getIdCard().getCardNo());
        session.getTransaction().commit();
    }catch(Exception e) {
        e.printStackTrace();
        session.getTransaction().rollback();
    }finally {
        HibernateUtils.closeSession(session);
    }
}


2289e3747f5c47fb82a3dd4df0049fab.png

唯一外键关联:


外键关联,本来是用于多对一的配置,但是加上唯一约束条件之后(采用标签来映射,指定多的一端unique为true,这样就限制了多的一端的多重性为一),也可以用来表示一对一关联关系,其实它就是多对一的特殊情况。


User.hbm.xml修改如下


<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
  "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
  <class name="com.bjsxt.hibernate.Person" table="t_person">
    <id name="id">
      <generator class="native"/>
    </id>
    <property name="name"/>
    <many-to-one name="idCard" unique="true"/>
  </class>
</hibernate-mapping>


unique=“true” 唯一约束,这样就同样做到了one-to-one的效果。

我们发现上面的都是单向的一对一关系,也就是说可以通过user来查找到IDcard,但是反过来就不行了。


双向一对一关联映射


b1fe7546f1fc4cf2b6f3085aa8bbd0ca.png


双向一对一主键映射关键映射代码——在IdCard端新加入如下标签映射:


<one-to-one name="person"/>


双向一对一唯一外键映射关键映射代码——在IdCard端新加入如下标签映射:


<one-to-one name="person" property-ref="idCard"/>


注意:一对一唯一外键关联双向采用标签映射,必须指定标签中的property-ref属性为关系字段的名称


一对多的映射关系


单向


一对多关联映射在系统实现中非常常见。例如我们的学生和老师的关系,如一个老师有多个学生。这样在系统的设计中就反映出一对多的关联。


22e07ddcd00845ec931b0ddb8087c976.png


注意:它与多对一的区别是维护的关系不同

*多对一维护的关系是:多指向一的关系,有了此关系,加载多的时候可以将一加载上来

*一对多维护的关系是:一指向多的关系,有了此关系,在加载一的时候可以将多加载上来

关键代码:


@Getter
@Setter
public class Classes {
private int id;
private String name;
private Set students; 
}


@Setter
@Getter
public class Student {
private int id;
private String name;
}
<hibernate-mapping package="com.bjsxt.hibernate">
   <class name="Classes" table="t_classes">
      <id name="id">
         <generator class="native"/>
      </id>
      <property name="name"/>
      <set name="students">
         <key column="classesid"  />
         <one-to-many class="Student"/>
      </set>
   </class>
</hibernate-mapping>
<hibernate-mapping>
   <class name="com.bjsxt.hibernate.Student" table="t_student">
      <id name="id">
         <generator class="native"/>
      </id>
      <property name="name"/>
   </class>
</hibernate-mapping>

测试:


public void testSave1() {
   Session session = null;
   try {
      session = HibernateUtils.getSession();
      session.beginTransaction();
      Student student1 = new Student();
      student1.setName("zhangsan");
      session.save(student1);
      Student student2 = new Student();
      student2.setName("lisi");
      session.save(student2);
      Set students = new HashSet();
      students.add(student1);
      students.add(student2);
      Classes classes = new Classes();
      classes.setName("zte");
      classes.setStudents(students);
     session.save(classes);
      session.getTransaction().commit();
   }catch(Exception e) {
      e.printStackTrace();
      session.getTransaction().rollback();
   }finally {
      HibernateUtils.closeSession(session);
   }
}  


截图:

5c8cfb54178a4902a9688adecaedb07b.png

966e868a36344371b5d631b6310541d6.png


这里我们可以看到,hibernate是先创建两张表然后再对表t_students添加外键


ab7611f5b7f948599fe8c412fd7e8aee.png


上面的运行中我们看到每执行一条save控制台就输出一条select语句,把对象所对应的数据存入数据库。但此时出了少的一方(t_class表)中的id是确定的其他的两条数据中打的id是null.

42fe4ea22b21401193cac6b8886aedb8.png


提交事务后再对,student表中的id做修改,也就是说在数据没有提交时id数据是为null的。一提交事务在对表中的id进行修改。我们发现update语句只有对student表的修改,也就是说变class表中的id是已经确定的。使两张表产生关联。


这里关系的维持是在少的一方,在添加主外键的时候hibernate更具set标签在生成。classes.hb.xml中name对应Classes类中students属性,key对应表中的域(classesid),one-to-many告诉hibernate要和那张表关联。当事务提交时,hibernate属性students所对应域(外键classid)来找到t_classes表中的主键所对应的值。再把t_students表中的外键值更新(update)。


双向


采用一对多双向关联映射的目的主要是为了主要是为了解决一对多单向关联的缺陷而不是需求驱动的。比如,为了让老师也可以找到学生们。


一对多双向关联的映射方式:、


  • 在一的一端的集合上采用标签,在多的一端加入一个外键
  • 在多的一端采用标签
    注意:标签和标签加入的字段保持一直,否则会产生数据混乱
    关键映射代码:


@Setter
@Getter
public class Student {
private int id;
private String name;
private Classes classes;
}


 @Setter
 @Getter
 public class Classes {   
   private int id;   
   private String name;   
   private Set students;    
}


<hibernate-mapping>
   <class name="com.bjsxt.hibernate.Student" table="t_student">
      <id name="id">
         <generator class="native"/>
      </id>
      <property name="name"/>
      <many-to-one name="classes" column="classesid"/>
   </class>
</hibernate-mapping>


<hibernate-mapping package="com.bjsxt.hibernate">
   <class name="Classes" table="t_classes">
      <id name="id">
         <generator class="native"/>
      </id>
      <property name="name"/>
      <set name="students" inverse="true" cascade="all">
         <key column="classesid"/>
         <one-to-many class="Student"/>
      </set>
   </class>
</hibernate-mapping>


通过对比单向发现:在少的一方添加了private Classes classes;字段,hbm中set里添加了属性inverse和cascade。并且多的一方hbm文件中添加了。


注意:


inverse属性可以用在一对多和多对多双向关联上,inverse属性默认为false,为false表示本端可以维护关系,如果inverse为true,则本端不能维护关系,会交给另一端维护关系,本端失效。所以一对多关联映射我们通常在多的一端维护关系,让一的一端失效。


inverse是控制方向上的反转,只影响存储


hibernate创建表以及数据库中表的结构也是和之前单向是一样的。


6a98b148e73443f8833cb1de713538e1.png

f9e32b53ecb64fe08ca6806172d7008f.png

然而对数据的存储时发现提交事务后只有三条


f1f996fc763e4bf4a1d727513cacc09b.png


多对多映射关系,


hibernate关联关系中相对比较特殊的就是多对多关联,多对多关联与一对一和一对不同,他需要借助中间别来完成多对多映射关系的保存。


由于多对多关联的性能不佳(由于引入了中间表,一次读取操作需要反复数次查询),因此在设计中应避免大量使用。同时在多对多关系中,应根据情况采取延迟加载机制来避免无所谓的性能开销。


单向


上面的场景中,为了实现老师可以找到学生们,就可以用多对多的关系实现。不过还需要添加一张表就是。


94d30eff92f04d1bb7a2abdc995f6e68.png


@Setter
@Getter
public class Role {
private int id;
private String name;
}


@Getter
@Setter
public class User {
private int id;
private String name;
private Set roles; 
}


<hibernate-mapping>
   <class name="com.bjsxt.hibernate.Role" table="t_role">
      <id name="id">
         <generator class="native"/>
      </id>
      <property name="name"/>
   </class>
</hibernate-mapping>


<hibernate-mapping>
   <class name="com.bjsxt.hibernate.User" table="t_user">
      <id name="id">
         <generator class="native"/>
      </id>
      <property name="name"/>
      <set name="roles" table="t_user_role">
         <key column="userid"/>
         <many-to-many class="com.bjsxt.hibernate.Role" column="roleid"/>
      </set>
   </class>
</hibernate-mapping>

4885ed1cde90413b89b9438d1f2f1796.png


把hbm代码代码放在一起展示发现,比之前的其他代码关系的代码似乎更加简洁。


接下来我们生成一下表,发现hibernate给我们生成了三张表,


02e0c006e60d43498cb27d393f17225b.png


fa51d73a74f94225960f316c65961786.png


添加数据关键代码:


   Session session = null;
   try {
      session = HibernateUtils.getSession();
      session.beginTransaction();
      Role r1 = new Role();
      r1.setName("aaaa");
      session.save(r1);
      Role r2 = new Role();
      r2.setName("bbbb");
      session.save(r2);
      Role r3 = new Role();
      r3.setName("cccc");
      session.save(r3);
      User u1 = new User();
      u1.setName("zhangsan");
      Set u1Roles = new HashSet();
      u1Roles.add(r1);
      u1Roles.add(r2);
      u1.setRoles(u1Roles);
      session.save(u1);
      User u2 = new User();
      u2.setName("lisi");
      Set u2Roles = new HashSet();
      u2Roles.add(r2);
      u2Roles.add(r3);
      u2.setRoles(u2Roles);
      session.save(u2);
      User u3 = new User();
      u3.setName("wangwu");
      Set u3Roles = new HashSet();
      u3Roles.add(r1);
      u3Roles.add(r2);
      u3Roles.add(r3);
      u3.setRoles(u3Roles);
      session.save(u3);
      session.getTransaction().commit(); 


运行截图:


45734bb71c604c89bfed0b35fbb6729a.png


查找数据:


session = HibernateUtils.getSession();
session.beginTransaction();
User user = (User)session.load(User.class, 3);
System.out.println(user.getName());
for (Iterator iter=user.getRoles().iterator(); iter.hasNext();) {
   Role role = (Role)iter.next();
   System.out.println(role.getName());
}


双向


双向的目的就是为了两端都能将对方加载上来,和单向多对多的区别就是双向需要在两端都加入标签映射,需要注意的是:


* 生成的中间表名称必须一样

* 生成的中间表中的字段必须一样


a507da29ad334506bbd0ae804fbf5755.png


关键代码:


@Getter
@Setter
public class User {
   private int id;
   private String name;
   private Set roles; 
}
@Getter
@Setter
public class Role {
   private int id;
   private String name;
   private Set users;
}
<hibernate-mapping>
   <class name="com.bjsxt.hibernate.User" table="t_user">
      <id name="id">
         <generator class="native"/>
      </id>
      <property name="name"/>
      <set name="roles" table="t_user_role">
         <key column="userid"/>
         <many-to-many class="com.bjsxt.hibernate.Role" column="roleid"/>
      </set>
   </class>
</hibernate-mapping>
<hibernate-mapping>
   <class name="com.bjsxt.hibernate.Role" table="t_role">
      <id name="id">
         <generator class="native"/>
      </id>
      <property name="name"/>
      <set name="users" table="t_user_role" order-by="userid">
         <key column="roleid"/>
         <many-to-many class="com.bjsxt.hibernate.User" column="userid"/>
      </set>
   </class>
</hibernate-mapping>


继承映射

1、理解如何映射

因为类继承树肯定是对应多个类,要把多个类的信息存放在一张表中,必须有某种机制来区分哪些记录是属于哪个类的。

这种机制就是,在表中添加一个字段,用这个字段的值来进行区分。用ibernate实现这种策略的时候,有如下步骤:


  1. 父类用普通的标签定义
  2. 在父类中定义一个discriminator,即指定这个区分的字段的名称和类型 如:
  3. 子类使用标签定义,在定义subclass的时候,需要注意如下几点:


  1. Subclass标签的name属性是子类的全路径名
  2. 在Subclass标签中,用discriminator-value属性来标明本子类的discriminator字段(用来区分不同类的字段)的值
  3. Subclass标签,既可以被class标签所包含(这种包含关系正是表明了类之间的继承关系),也可以与class标签平行。 当subclass标签的定义与class标签平行的时候,需要在subclass标签中,添加extends属性,里面的值是父类的全路径名称。子类的其它属性,像普通类一样,定义在subclass标签的内部。


2、理解如何存储

存储的时候hibernate会自动将鉴别字段值插入到数据库中,在加载数据的时候,hibernate能根据这个鉴别值

正确的加载对象

多态查询:在hibernate加载数据的时候能鉴别出正真的类型(instanceOf)


get支持多态查询

load只有在lazy=false,才支持多态查询

hql支持多态查询


有如下的继承关系:


407f28b2711d4f1d8ede036457d0ddd4.png

ce7510f0fa1f4164b435e46d8c296151.png


hbm关键代码如下:


<hibernate-mapping package="com.bjsxt.hibernate">
   <class name="Animal" table="t_animal" lazy="true">
      <id name="id">
         <generator class="native"/>
      </id>
      <discriminator column="type" type="string"/>
      <property name="name"/>
      <property name="sex"/>
      <subclass name="Pig" discriminator-value="P">
         <property name="weight"/>
      </subclass>
      <subclass name="Bird" discriminator-value="B">
         <property name="height"/>
      </subclass>
   </class>
</hibernate-mapping>


注意:

lazy="true": 代码输出的是no


Animal animal = (Animal)session.load(Animal.class, 1);
//因为load默认支持lazy,因为我们看到的是Animal的代理对象
//所以通过instanceof是反应不出正真的对象类型的
//因此load在默认情况下是不支持多态查询的
if (animal instanceof Pig) {
   System.out.println(animal.getName());
}else {
   System.out.println("no");
}


lazy="false": 代码输出的是实际的类型名

hibernate默认懒加载是开启的。


说明:


所谓的懒加载可以定义为:

1、延时加载,即当对象需要用到的时候再去加载。其实就是所谓的重写对象的get方法,

2、当系统或者开发者调用对象的get方法时,再去加载对象。


懒加载


什么是懒加载?


懒加载其实就是延时加载,即当对象需要用到的时候再去加载

有如下的主要代码:


@Getter
@Setter
public class Group {
private int id;
private String name;
}


<hibernate-mapping>
   <class name="com.bjsxt.hibernate.Group" table="t_group" lazy="true">
      <id name="id">
         <generator class="native"/>
      </id>
      <property name="name"/>
   </class>
</hibernate-mapping>


注意:hibernate默认懒加载是开启的。


针对于开启懒加载后,对数据库进行查询,会出现一下的情况:


//不会发出sql
Group group = (Group)session.load(Group.class, 1);
//不会发出sql
System.out.println("group.id=" + group.getId());
//会发出sql
System.out.println("group.name=" + group.getName());


并且:hibernate支持lazy策略只有在session打开状态下有效,当session关闭后,不能正确输出,抛出LazyInitializationException 异常,因为session已经关闭。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
2月前
|
Java 数据库连接 API
解锁高效开发秘籍:深入探究 Hibernate 如何优雅处理一对多与多对多关系,让数据映射再无烦恼!
【9月更文挑战第3天】Hibernate 是 Java 领域中最流行的 ORM 框架之一,广泛用于处理实体对象与数据库表之间的映射。尤其在处理复杂关系如一对多和多对多时,Hibernate 提供了丰富的 API 和配置选项。本文通过具体代码示例,展示如何使用 `@OneToMany`、`@JoinColumn`、`@ManyToMany` 和 `@JoinTable` 等注解优雅地实现这些关系,帮助开发者保持代码简洁的同时确保数据一致性。
52 4
|
3月前
|
Java 数据库连接 数据库
AI 时代风起云涌,Hibernate 实体映射引领数据库高效之路,最佳实践与陷阱全解析!
【8月更文挑战第31天】Hibernate 是一款强大的 Java 持久化框架,可将 Java 对象映射到关系数据库表中。本文通过代码示例详细介绍了 Hibernate 实体映射的最佳实践,包括合理使用关联映射(如 `@OneToMany` 和 `@ManyToOne`)以及正确处理继承关系(如单表继承)。此外,还探讨了常见陷阱,例如循环依赖可能导致的无限递归问题,并提供了使用 `@JsonIgnore` 等注解来避免此类问题的方法。通过遵循这些最佳实践,可以显著提升开发效率和数据库操作性能。
84 0
|
3月前
|
数据库 开发者 Java
Hibernate映射注解的魔力:实体类配置的革命,让你的代码量瞬间蒸发!
【8月更文挑战第31天】Hibernate 是一款出色的对象关系映射框架,简化了 Java 应用与数据库的交互。其映射注解让实体类配置变得直观简洁。本文深入剖析核心概念与使用技巧,通过示例展示如何简化配置。
45 0
|
5月前
|
Oracle Java 关系型数据库
[学习笔记] 在Eclipse中使用Hibernate,并创建第一个Demo工程,数据库为Oracle XE
[学习笔记] 在Eclipse中使用Hibernate,并创建第一个Demo工程,数据库为Oracle XE
|
SQL XML 存储
Hibernate框架【五】——基本映射——多对多映射
Hibernate框架【五】——基本映射——多对多映射
191 0
|
6月前
|
Java 关系型数据库 数据库连接
Hibernate学习笔记(一)快速入门
Hibernate学习笔记(一)快速入门
|
6月前
|
缓存 Java 数据库连接
Hibernate或MyBatis:ORM映射、缓存机制等知识讲解梳理
Hibernate或MyBatis:ORM映射、缓存机制等知识讲解梳理
129 0
|
6月前
|
Java 数据库连接 数据库
Hibernate5中实体映射命名策略
Hibernate5中实体映射命名策略
134 0
|
6月前
|
SQL 存储 Java
Hibernate - 继承关联关系映射
Hibernate - 继承关联关系映射
71 0
|
6月前
|
SQL Java 关系型数据库
Hibernate - Java 类型, Hibernate 映射类型及 SQL 类型之间的对应关系
Hibernate - Java 类型, Hibernate 映射类型及 SQL 类型之间的对应关系
63 0