【Hibernate】浅析hibernate中的延迟加载
1 简介
在使用一些查询方法时,方法执行了,但是并没有立刻发送SQL语句查询数据库。而是在访问对象的getXxx方法时候才触发SQL执行加载对象数据。这种机制就称为延迟加载。
2 优点
延迟加载主要是为后续关联映射提供,避免查找无用的关联数据。
可以降低数据库操作的并发率,提升内存资源使用率。
3 使用
在struts2中,session.load()/query.iterator()和关联映射都使用的这种机制。
下面笔者使用session.load()方法举例:
hibernate.cfg.xml 文件
<?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <!-- Generated by MyEclipse Hibernate Tools. --> <hibernate-configuration> <session-factory> <property name="dialect"> org.hibernate.dialect.MySQLDialect </property> <property name="connection.url"> jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8 </property> <property name="connection.username">root</property> <property name="connection.password">517839</property> <property name="connection.driver_class"> com.mysql.jdbc.Driver </property> <property name="show_sql">true</property> <property name="format_sql">true</property> <!-- 加载映射描述信息 --> <mapping class="cn.test.bean.User" /> </session-factory> </hibernate-configuration>
在里面指定了在控制台打印Sql执行日志
User.java 文件
package cn.test.bean; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name="user")//表示对应的表名 public class User { @Id @Column(name="uid") private int id; @Column(name="uname") private String name; @Column(name="upass") private String password; 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 String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
接下来是测试文件:
如果我们使用如下的测试代码
Configuration conf = new Configuration(); conf.configure("hibernate.cfg.xml");//读取连接参数和映射描述信息 SessionFactory factory = conf.buildSessionFactory(); Session session = factory.openSession(); User user = (User)session.get(User.class,1); System.out.println("我在语句发送之后");
System.out.println(user.getId()+","+user.getName()+","+user.getPassword());
session.close();
可以看到控制台上打印出了信息
如果把上面的get方法换成 User user = (User)session.load(User.class,1);
通过这两次结果的对比可以看出,load方法使用延迟加载。使用load方法获取数据的方式,当程序加载到load方法时,程序并不会真正从数据库中查询语句,只有当查询的结果对象使用getXxx()方法的时候,才会在数据库中查询。
4 异常:org.hibernate.LazyInitialization:could not initialize proxy - no Session
如果使用了延迟加载,并且出现这样的错误,就是很有可能是session关早了。在session关闭后,再调用结果对象的getXxx(),这样从数据库中查询数据就会出错。在MVC开发出,如果想要使用延迟加载(使用session.load()方法或是query.iterator()方法)从数据库中取出数据到页面展现(在页面调用对象的getXxx方法),那么在数据层得到数据对象后,不要关闭session,因为关闭session后,再在页面调用getXxx()方法就会抛出异常。
要解决这种方法,要么不使用延迟加载,要么就在页面调用了getXxx()方法后,再关闭session。