博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
hibernate加载策略之lazy
阅读量:4291 次
发布时间:2019-05-27

本文共 14500 字,大约阅读时间需要 48 分钟。

hibernate的加载策略有两种:

1)即时加载:get加载

      使用get加载数据,会立即查找,先到缓存中找,找不到再去数据库中找。

2)延迟加载(也叫懒加载lazy):laod加载

      不会立即查找,当需要的时候才会查找。

      容易造成异常:org.hibernate.LazyInitializationException: could not initialize proxy - no Session

at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:165)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:286)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185)
at com.myeclipse.pojo.Book_$$_jvstdc3_0.getName(Book_$$_jvstdc3_0.java)
at com.ghibernate.test.HibernateTest.testLoad(HibernateTest.java:106)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

        如果出现上面这个异常,大部分是因为session被关闭了,还要从session中取数据造成的。

但是懒加载也有优势:那就是效率高,因为

3)class的lazy

      class默认情况下是支持懒加载的(在*.hbm.xml中的class中有一个属性lazy=“true”),所以在load方法时,是懒加载,但是当我们把lazy=“false”时,就不支持懒加载了,这是即使是使用load方法,也会是即时加载。

项目结构如下:

jar包和hibernate官网配置参见《》

Book实体类代码:

package com.myeclipse.pojo;import java.util.Date;public class Book {		private int id;	private String author;	private String name;	private double price;	private Date pubDate;		public int getId() {		return id;	}	public void setId(int id) {		this.id = id;	}	public String getAuthor() {		return author;	}	public void setAuthor(String author) {		this.author = author;	}	public String getName() {		return name;	}	public void setName(String name) {		this.name = name;	}	public double getPrice() {		return price;	}	public void setPrice(double price) {		this.price = price;	}	public Date getPubDate() {		return pubDate;	}	public void setPubDate(Date pubDate) {		this.pubDate = pubDate;	}	@Override	public String toString() {		return "Book [id=" + id + ", author=" + author + ", name=" + name				+ ", price=" + price + ", pubDate=" + pubDate + "]";	}		}
Book.hbm.xml代码:

HibernateUtil代码:

package com.robert.util;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.boot.registry.StandardServiceRegistryBuilder;import org.hibernate.cfg.Configuration;/** * hibernate工具类 */public class HibernateUtil {	private static Configuration cfg = null;	private static SessionFactory factory = null;	private static Session session = null ;		static {		init();	}	/**	 * 初始化获得Configuration和SessionFacroty对象	 */	public static void init() {		cfg = new Configuration().configure();		factory = cfg.buildSessionFactory(new StandardServiceRegistryBuilder()				.applySettings(cfg.getProperties()).build());	}	/**	 * 获得Session对象	 * @return	 */	public static Session getSession() {		if (factory != null){			return session = factory.openSession();		}				init();		return session = factory.openSession();	}		/**	 * 关闭Session	 */	public static void closeSession() {		if(session!=null && session.isOpen())			session.close();	}}
hibernate.cfg.xml代码:

com.mysql.jdbc.Driver
jdbc:mysql:///hibernate4
root
root
org.hibernate.dialect.MySQL5Dialect
true
true
update

HibernateTest代码:

package com.ghibernate.test;import java.util.Date;import java.util.List;import org.hibernate.Query;import org.hibernate.Session;import org.hibernate.Transaction;import org.hibernate.cfg.Configuration;import org.hibernate.tool.hbm2ddl.SchemaExport;import org.junit.Test;import com.myeclipse.pojo.Book;import com.robert.util.HibernateUtil;public class HibernateTest {	@Test	public void testCreateDB() {		Configuration cfg = new Configuration().configure();		SchemaExport se = new SchemaExport(cfg);		// 第一个参数:是否生成ddl脚本		// 第二个参数:是否执行到数据库中		se.create(true, true);	}	@Test	public void testSave() {		Session session = HibernateUtil.getSession();		Transaction tx = session.beginTransaction();		Book book = new Book();		book.setName("读者");		book.setPrice(5.6);		book.setAuthor("众人");		book.setPubDate(new Date());		Book book1 = new Book();		book1.setName("傲慢与偏见");		book1.setPrice(80.0);		book1.setAuthor("简.奥斯汀");		book1.setPubDate(new Date());		Book book2 = new Book();		book2.setName("中国历史");		book2.setPrice(30.0);		book2.setAuthor("人民出版社");		book2.setPubDate(new Date());		Book book3 = new Book();		book3.setName("翩眇之旅");		book3.setPrice(70.0);		book3.setAuthor("萧鼎");		book3.setPubDate(new Date());		Book book4 = new Book();		book4.setName("蓝血人");		book4.setPrice(60.0);		book4.setAuthor("卫斯理");		book4.setPubDate(new Date());		Book book5 = new Book();		book5.setName("我的大学");		book5.setPrice(60.5);		book5.setAuthor("高尔基");		book5.setPubDate(new Date());		session.save(book);		session.save(book1);		session.save(book2);		session.save(book3);		session.save(book4);		session.save(book5);		tx.commit();		HibernateUtil.closeSession();	}	@Test	public void testGet() {		Session session = HibernateUtil.getSession();		Transaction tx = session.beginTransaction();		Book book = (Book) session.get(Book.class, 1);		System.out.println("book_name=" + book.getName());		tx.commit();		HibernateUtil.closeSession();		System.out.println("book_name=" + book.getName());	}	@Test	public void testLoad() {		Session session = HibernateUtil.getSession();		Transaction tx = session.beginTransaction();		Book book = (Book) session.load(Book.class, 1);		System.out.println("book_id=" + book.getId());		tx.commit();		HibernateUtil.closeSession();		//当Book.hbm.xml中的class中的lazy参数是ture时,这里会报错,错误见博客开头		System.out.println("book_name=" + book.getName());	}}

=========================================================================

还有一种情况是get的懒加载,如下:

新建一个项目,结构如下:

hibernate项目搭建,参见

实体类Book如下:

package com.myeclipse.pojo;import java.util.Date;public class Book {		private int id;	private String author;	private String name;	private double price;	private Date pubDate;	private Category category;		public int getId() {		return id;	}	public void setId(int id) {		this.id = id;	}	public String getAuthor() {		return author;	}	public void setAuthor(String author) {		this.author = author;	}	public String getName() {		return name;	}	public void setName(String name) {		this.name = name;	}	public double getPrice() {		return price;	}	public void setPrice(double price) {		this.price = price;	}	public Date getPubDate() {		return pubDate;	}	public void setPubDate(Date pubDate) {		this.pubDate = pubDate;	}	public Category getCategory() {		return category;	}	public void setCategory(Category category) {		this.category = category;	}	@Override	public String toString() {		return "Book [id=" + id + ", author=" + author + ", name=" + name				+ ", price=" + price + ", pubDate=" + pubDate + "]";	}		}

Book.hbm.xml代码:

Category实体类代码:

package com.myeclipse.pojo;import java.util.HashSet;import java.util.Set;public class Category{		private int id;	private String name;	private Set
books = new HashSet
(); 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 Set
getBooks() { return books; } public void setBooks(Set
books) { this.books = books; }}

Category.hbm.xml代码:

HIbernateUtil和hibernate.cfg.xml和上面一样。

HibernateTest代码:

package com.ghibernate.test;import java.util.Date;import java.util.Iterator;import java.util.List;import org.hibernate.Query;import org.hibernate.Session;import org.hibernate.Transaction;import org.hibernate.cfg.Configuration;import org.hibernate.tool.hbm2ddl.SchemaExport;import org.junit.Test;import com.myeclipse.pojo.Book;import com.myeclipse.pojo.Category;import com.robert.util.HibernateUtil;public class HibernateTest {	@Test	public void testCreateDB() {		Configuration cfg = new Configuration().configure();		SchemaExport se = new SchemaExport(cfg);		// 第一个参数:是否生成ddl脚本		// 第二个参数:是否执行到数据库中		se.create(true, true);	}	@Test	public void testSave() {		Session session = HibernateUtil.getSession();		Transaction tx = session.beginTransaction();		Category category = new Category();		category.setName("文学");		Category category1 = new Category();		category1.setName("历史");		Category category2 = new Category();		category2.setName("仙侠");		Category category3 = new Category();		category3.setName("科幻");		Category category4 = new Category();		category4.setName("恐怖");		Book book = new Book();		book.setName("读者");		book.setPrice(5.6);		book.setAuthor("众人");		book.setPubDate(new Date());		book.setCategory(category);		Book book1 = new Book();		book1.setName("傲慢与偏见");		book1.setPrice(80.0);		book1.setAuthor("简.奥斯汀");		book1.setPubDate(new Date());		book1.setCategory(category1);		Book book2 = new Book();		book2.setName("中国历史");		book2.setPrice(30.0);		book2.setAuthor("人民出版社");		book2.setPubDate(new Date());		book2.setCategory(category1);		Book book3 = new Book();		book3.setName("翩眇之旅");		book3.setPrice(70.0);		book3.setAuthor("萧鼎");		book3.setPubDate(new Date());		book3.setCategory(category2);		Book book4 = new Book();		book4.setName("蓝血人");		book4.setPrice(60.0);		book4.setAuthor("卫斯理");		book4.setPubDate(new Date());		book4.setCategory(category3);		Book book5 = new Book();		book5.setName("我的大学");		book5.setPrice(60.5);		book5.setAuthor("高尔基");		book5.setPubDate(new Date());		book5.setCategory(category);		session.save(book);		session.save(book1);		session.save(book2);		session.save(book3);		session.save(book4);		session.save(book5);		session.save(category4);		tx.commit();		HibernateUtil.closeSession();	}	@Test	public void testGet() {		Session session = HibernateUtil.getSession();		Transaction tx = session.beginTransaction();		//当Category.hbm.xml中的set中的lazy属性是true(默认是true)时,先查询一端的Category,只会先查询Category数据,		//当执行下面for中的category.getBooks时才会去查询Book数据,这时就是懒加载		//但是当我们把Category.hbm.xml中的set中的lazy属性改为false时,会在查询Category的时候,把Book也查询出来,这时就是即时加载		Category category = (Category) session.get(Category.class, 1) ;		System.out.println("category_name="+category.getName());		for (Iterator
iter = category.getBooks().iterator();iter.hasNext();) { System.out.println(iter.next().getName()); } tx.commit(); HibernateUtil.closeSession(); } }

在HibernateTest类中增加一个方法

@Test	public void testLoad() {		Session session = HibernateUtil.getSession();		Transaction tx = session.beginTransaction();		Category category = (Category) session.load(Category.class, 1) ;		System.out.println("category_name="+category.getName());		System.out.println("书籍数量:"+category.getBooks().size());				tx.commit();		HibernateUtil.closeSession();	}
断点运行,可以看到,执行完

Category category = (Category) session.load(Category.class, 1) ;

这句,并没有查询数据的sql语句

当执行

System.out.println("category_name="+category.getName());
这句后,打印sql语句如下:

Hibernate:     select        category0_.id as id1_0_0_,        category0_.name as name2_0_0_     from        Category category0_     where        category0_.id=?category_name=文学

继续运行

System.out.println("书籍数量:"+category.getBooks().size());

这句后,打印sql语句

Hibernate:     select        books0_.category_id as category2_0_0_,        books0_.id as id1_1_0_,        books0_.id as id1_1_1_,        books0_.category_id as category2_1_1_,        books0_.author as author3_1_1_,        books0_.book_name as book_nam4_1_1_,        books0_.price as price5_1_1_,        books0_.pubDate as pubDate6_1_1_     from        t_book books0_     where        books0_.category_id=?书籍数量:2
当把Category.hbm.xml中set的lazy更改为extra时,代码如下:

HibernateTest中的testLoad代码:

@Test	public void testLoad() {		Session session = HibernateUtil.getSession();		Transaction tx = session.beginTransaction();		Category category = (Category) session.load(Category.class, 1) ;		System.out.println("category_name="+category.getName());		System.out.println("书籍数量:"+category.getBooks().size());				tx.commit();		HibernateUtil.closeSession();	}
打印的sql语句如:

Hibernate:     select        category0_.id as id1_0_0_,        category0_.name as name2_0_0_     from        Category category0_     where        category0_.id=?category_name=文学Hibernate:     select        count(id)     from        t_book     where        category_id =?书籍数量:2
4)总结:

set和list默认下都是lazy=true,默认支持懒加载。但是当使用size()的时候,依然会查询整个set集合的内容。

lazy=false时,立即查询所有集合的内容。

lazy=extra时,比较智能,支持懒加载,当使用size()的时候,不会查询整个集合,仅仅查询集合中元素的个数,当需要使用集合元素的内容时,再去查询。

5)单端关联上的lazy:(many-to-one,one-to-one),默认是支持懒加载的lazy=proxy

6)property上的懒加载lazy,需要用到第三方增加,且大部分情况下用不到property懒加载,只有当是大对象时Blob,Clob才会用到

你可能感兴趣的文章
Java易混小知识——equals方法和==的区别
查看>>
内置对象(Session、Application、ViewState)
查看>>
为什么Java有GC还需要自己来关闭某些资源?
查看>>
Android 热修复,插件式开发---基本知识
查看>>
JSP九大内置对象、四种作用域、跳转方式
查看>>
JSP 自定义标签
查看>>
JSP JavaBean
查看>>
从两个字符串中找出最大公共子字符串
查看>>
Java代码添加背景音乐
查看>>
Java面试题全集(上)
查看>>
JAVA泛型中的有界类型(extends super)
查看>>
炫酷进度条:Android 仿应用宝下载进度条
查看>>
Java程序内存的简单分析
查看>>
Javascript单例模式概念与实例
查看>>
SQL NULL 函数
查看>>
多例设计模式
查看>>
WebView的JavaScript与本地代码三种交互方式
查看>>
WebView的JavaScript与本地代码三种交互方式
查看>>
Android Studio里面配置Tesseract
查看>>
深入浅出JavaScript之this
查看>>