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 关系中,将 n 方设为主控方将有助于性能改善
6.在 1-N 关系中,若将 1 方设为主控方 会额外多出 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做级联查询时,懒加载的情况下会出现啥异常?的主要内容,如果未能解决你的问题,请参考以下文章