Hibernate做级联查询时,懒加载的情况下会出现啥异常?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Hibernate做级联查询时,懒加载的情况下会出现啥异常?相关的知识,希望对你有一定的参考价值。

比如我有持久化类
public class A
private int aid;
private <Set>B bs;

public class B
private String bname;


省略了getter和setter
且在A的映射文件配置了B的懒加载
我调用A类对象
Iterator it=a.getBs().iterator();
while(it.hasNext())
B b=it.next();
System.out.println(b.getBname());


此时可能会出现什么异常?

    一般会出现Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - no Session......这个异常


懒加载概念::懒加载,运行后没有立刻访问相应的数据库,返回的是代理对象,永远不可能为空,当第一次使用该对象的时候,才去访问。


Hibernate的Lazy初始化1:n关系时,必须保证是在同一个Session内部使用这个关系集合,不然Hiernate将抛出异常。

     这是延时加载的问题,把有关联的所有pojo类,在hibernate.cfg.xml文件中。一般在many-to-one中,set标签内中设lazy="false" 

参考技术A lazy模式可以理解为,不用不查,用时再查。
"再查"的时候必须保证session没有关闭,不然会查不出来,报空指针或输出空值。
参考技术B 我看到是没看出来什么异常 参考技术C 1111

hibernate初步2

Hibernate级联设计

 

数据库表之间的关系(主要关系有一对多、一对一、多对多)主要是从如下三个方面体现出来:

1.表体设计

2.实体类的设计

3.配置文件

以下是一些重要级联设计参数属性介绍:

cascade级联操作,默认值为 none

1.none:只做级联查询

2.save-update:级联查询,级联插入和级联更新

3.delete:级联查询,级联删除

4.all:级联查询,级联插入,级联更新和级联删除

5.all-delete-orphan:基础主从表记录关系时,会把从表对应的记录一并删除

 

inverse:维护两张表之间的关系,默认值是 false,即维护从表的外键值

1.ture:不维护从表外键值

2.false:维护从表外键值

3.在 hibernate 中通过对 inverse 属性的值决定是由双向关联的哪一方来维护表和表之间的关系. inverse=false 的为主动方,inverse=true 的为被动方由主动方负责维护关联关系

4. 在没有设置 inverse=true 的情况下,父子两边都维护父子关系

5.在 1-n 关系中,将 方设为主控方将有助于性能改善

6.在 1-N 关系中,若将 方设为主控方 会额外多出 update 语句。

 

注意:cascade 和 inverse 优先考虑cascade操作,然后再考虑 inverse 操作!

 

lazy:是否延迟加载从表取出来的数据

1.true 延迟加载

2.flase 不延迟加载

 

 


 

 一对多关联关系映射(表的设计原则是:在多的一方添加外键链来描述彼此之间的关系)

 

POJO类的设计:

1.设计 OrderItem 类,它代表为“1”的一方:

 

public class OrderItem {
    private int id;
    private int amount;
    private String productName;
    private UserOrder userOrder;
public int getId() {return id;} public void setId(int id) {this.id = id;} public int getAmount() {return amount;} public void setAmount(int amount) {this.amount = amount;} public String getProductName() {return productName;} public void setProductName(String productName) {this.productName = productName;} public UserOrder getUserOrder() {return userOrder;} public void setUserOrder(UserOrder userOrder) {this.userOrder = userOrder;} }

 

2.设计 UserOrder 类,它代表为"n"的一方:

 

import java.util.HashSet;
import java.util.Set;

public class UserOrder {
    private int id;
    private int userId;
    private int status;
    private double cost;
    /**
     * 存放相关联的OrderItem对象
     */
    private Set<OrderItem> orderItems = new HashSet<OrderItem>();
    //从面向对象的角度来看,在“多”的一方使用一个集合用来保存另一个相关联的对象的信息。
    public int getId() {return id;}
    public void setId(int id) {this.id = id;}
    public int getUserId() {return userId;}
    public void setUserId(int userId) {this.userId = userId;}
    public int getStatus() {return status;}
    public void setStatus(int status) {this.status = status;}
    public double getCost() {return cost;}
    public void setCost(double cost) {this.cost = cost;}
    
    public Set<OrderItem> getOrderItems() {
        return orderItems;
    }
    public void setOrderItems(Set<OrderItem> orderItems) {
        this.orderItems = orderItems;
    }
    @Override
    public String toString() {
        return "UserOrder [id=" + id + ", userId=" + userId + ", status=" + status + ", cost=" + cost + "]";
    }
}

 

3.建立 OrderItem 的 Hibernate 相关映射配置文件:orderitem.hbm.xml

 

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="net.togogo.onetomany.pojo.OrderItem" table="order_item" >
        <id name="id" type="int">
            <column name="id" />
            <generator class="native"></generator>
        </id>
        <property name="amount" type="int">
            <column name="amount" length="11" />
        </property>
        <property name="productName" type="string">
            <column name="productName" length="30" />
        </property>
<many-to-one name="userOrder" class="net.togogo.onetomany.pojo.UserOrder" cascade="all" column="order_id">
     </
many-to-one> </class> </hibernate-mapping>

 

4.建立 UserOrder 的 Hibernate 相关映射配置文件:userorder.hbm.xml

 

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
  <!-- POJO 数据库中的表对应的实体类 -->
<class name="net.togogo.onetomany.pojo.UserOrder" table="user_order" > <id name="id" type="int"> <column name="id" /> <generator class="native"></generator> </id> <property name="userId" type="int"> <column name="user_id" length="11" /> </property> <property name="status" type="int"> <column name="status" length="11" /> </property> <property name="cost" type="double"> <column name="cost" /> </property> <!-- many-to-one属性说明:
     * name:设定待映射的持久化类的名字。
      name="orderItems",对应UserOrder中的setOrderItems(Set<OrderItem> orderItems)方法

     column:设定和持久化类的属性对应的表的外键。

     class:设定持久化类的属性的类型。

     not-null:是否允许为空。
cascade:级联操作,默认值是none,常用的值: 1)none:只做级联查询 2)save-update:级联查询,级联插入和级联更新 3)delete:级联查询,级联删除 4)all:级联查询,级联插入,级联删除,级联更新 5)all-delete-orphan:解除主从表记录关系时,会把从表对应的记录一并删除 inverse:维护两张表之间的关系,默认是false,即维护从表的外键值 1)true:不维护从表外键值 2) false:维护从表外键值 cascade和inverse:优先考虑cascade操作,然后再考虑inverse lazy:是否延迟加载从表的数据,true,延迟加载,false,立即加载
--> <set name="orderItems" cascade="all-delete-orphan" inverse="false" lazy="true"> <!-- 从表的外键字段 --> <key column="order_id"></key> <one-to-many class="net.togogo.onetomany.pojo.OrderItem"/> </set> </class> </hibernate-mapping>

 

5.在 hibernate.cfg.xml 配置文件加入 userorder.hbm.xml orderitem.hbm.xml 相关信息:

 

<!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="dialect">
            org.hibernate.dialect.MySQLDialect
        </property>
        <property name="hibernate.connection.driver_class">
            com.mysql.jdbc.Driver
        </property>
     <!-- 所使用的数据库名 -->
<property name="hibernate.connection.url">
      
jdbc:mysql://localhost:3306/hibernate_db </property> <property name="connection.username">root</property> <property name="connection.password">root</property> <!-- 设置连接池大小 --> <property name="hibernate.connection.pool_size">10</property> <!-- 实质是调用 Statement.setFetchSize() 方法设定JDBC的Statement读取数据的时候每次从数据库中取出的记录条数。
     例如一次查询1万条记录,对于Oracle的JDBC驱动来说,是不会 1 次性把1万条取出来的,而只会取出Fetch Size条数,
     当纪录集遍历完了这些记录以后,再去数据库取Fetch Size条数据。因此大大节省了无谓的内存消耗。 Fetch Size设的越大,读数据库的次数越少,速度越快;Fetch Size越小,读数据库的次数越多,速度越慢。 Oracle数据库的JDBC驱动默认的Fetch Size=10,是一个保守的设定,根据测试,当Fetch Size=50时,性能会提升1倍之多,
     当Fetch Size=100,性能还能继续提升20%,Fetch Size继续增大,性能提升的就不显著了。 并不是所有的数据库都支持Fetch Size特性,例如MySQL就不支持。MySQL就像上面那种最坏的情况,总是一下就把1万条记录完全取出来,
     内存消耗会非常惊人!
--> <property name="hibernate.jdbc.fetch_size">50</property> <!-- 设定对数据库进行批量删除,批量更新和批量插入的时候的批次大小,类似于设置缓冲区大小的意思。Batch Size越大,
      批量操作的向数据库发送sql的次数越少,速度就越快。测试结果是当Batch Size=0的时候,使用Hibernate对Oracle
      数据库删除1万条记录需要25秒,Batch Size = 50的时候,删除仅仅需要5秒!  Oracle数据库 Batch Size = 30 的时候比较合适
--> <property name="hibernate.jdbc.batch_size">50</property> <!-- 显示底层的sql语句,开发阶段设为true,项目发布阶段设为false --> <property name="show_sql">true</property> <property name="format_sql">false</property> <property name="use_sql_comments">false</property> <!-- 在启动和停止时自动地创建,更新或删除数据库模式。取值 create | update | create-drop | validate,
    推荐使用update,update值表示如果之前有表,就用之前的表,否则创建新的表
--> <property name="hbm2ddl.auto">update</property> <mapping resource="net/togogo/onetomany/pojo/userorder.hbm.xml"/> <mapping resource="net/togogo/onetomany/pojo/orderitem.hbm.xml"/> </session-factory> </hibernate-configuration>

 


 

 

一对一级联关系映射(表的设计原则是:存在主从关系,主可以没有从,但从不能没有主。在从表中将主键链(默认拥有唯一约束和非空约束)声明成外键约束即可。---------也就是说,有一列既是主键列又是外键链。)

 

POJO类的设计

1.设计 Boy 类,它代表为"1"的一方:

 

public class Boy {
    private int id;
    private String name;
    private Girl girl;
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 Girl getGirl() {return girl;} public void setGirl(Girl girl) {this.girl = girl;} }

 

2.设计 Girl 类,它代表为"1"的另一方:

 

public class Girl {
    private int id;
    private String name;
    private Boy boy;
    
    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 Boy getBoy() {return boy;}
    public void setBoy(Boy boy) {this.boy = boy;}
}

 

3.建立 Boy 的 Hibernate 相关映射配置文件:boy.hbm.xml

 

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Mapping file autogenerated by MyEclipse Persistence Tools -->
<hibernate-mapping>
    <class name="net.togogo.onetoone.pojo.Boy" table="boy">
        <id name="id" type="int">
            <column name="id" />
            <generator class="native"></generator>
        </id>
        <property name="name" type="string">
            <column name="name" length="30" />
        </property>

        <many-to-one name="girl" cascade="all" lazy="false"
            class="net.togogo.onetoone.pojo.Girl" unique="true" column="g_id"></many-to-one>
    </class>

</hibernate-mapping>

 

4.建立 Girl 的 Hibernate 相关映射配置文件:girl.hbm.xml

 

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Mapping file autogenerated by MyEclipse Persistence Tools -->
<hibernate-mapping>
    <class name="net.togogo.onetoone.pojo.Girl" table="girl">
        <id name="id" type="int">
            <column name="id" />
            <generator class="native"></generator>
        </id>
        <property name="name" type="string">
            <column name="name" length="30" />
        </property>

        <one-to-one name="boy" cascade="all" lazy="false"
            class="net.togogo.onetoone.pojo.Boy">           
        </one-to-one>
    </class>
</hibernate-mapping>

 

5.在 hibernate.cfg.xml 配置文件加入 boy.hbm.xml girl.hbm.xml 相关信息:

 

<!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="dialect">
            org.hibernate.dialect.MySQLDialect
        </property>
        <property name="hibernate.connection.driver_class">
            com.mysql.jdbc.Driver
        </property>
        <property name="hibernate.connection.url">
            jdbc:mysql://localhost:3306/hibernate_db
        </property>
        <property name="connection.username">root</property>
        <property name="connection.password">root</property>
                
        <!-- 设置连接池大小 -->
        <property 以上是关于Hibernate做级联查询时,懒加载的情况下会出现啥异常?的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate总结

三大框架 之 Hibernate查询(一对多多对多查询关系)

Hibernate JPA 关联关系

关于Hibernate中立即加载和懒加载的区别

association实现懒加载分布级联查询

懒加载(延迟加载)