Hibernate从入门到精通

1. Hibernate框架简述

Hibernate框架简化了java应用程序与数据库交互的开发。Hibernate是一个开源,轻量级的ORM(对象关系映射) 工具。了解更多Hibernate,访问Hibernate官网。
ORM 工具简化了数据创建,数据处理和数据访问。它是将对象映射到数据库中存储的数据(表)的编程技术。

Hibernate框架的优点:

  • 开源和轻量级: Hibernate框架是根据LGPL许可证和轻量级的开源工具。
  • 快速性能: Hibernate框架的性能很快,因为缓存在Hibernate框架内部使用。hibernate框架中有两种类型的缓存:一级缓存和二级缓存。一级缓存默认是启用的。
  • 数据库独立查询: HQL(Hibernate查询语言)是面向对象的SQL版本。 它生成数据库独立查询。 所以你不需要编写数据库特定的查询语句。 在Hibernate之前,如果项目更改了数据库,我们需要更改SQL查询,从而导致维护变得非常复杂。
  • 自动创建表: Hibernate框架提供了自动创建数据库表的功能。 因此,无需手动在数据库中创建表。
  • 简化复杂连接: 在hibernate框架中可轻松获取多个表中的数据。
  •  提供查询统计和数据库状态: Hibernate支持查询缓存,并提供有关查询和数据库状态的统计信息。

2. Hibernate体系结构

Hibernate架构包括许多对象持久对象,会话工厂,事务工厂,连接工厂,会话,事务等。

Hibernate从入门到精通_第1张图片

Hibernate框架使用许多对象会话工厂,会话,事务等以及现有的Java API,如JDBC(Java数据库连接),JTA(Java事务API)和JNDI(Java命名目录接口)。

Hibernate体系结构的要素如下:
会话工厂(SessionFactory)
SessionFactory是ConnectionProvider的会话和客户端工厂。它拥有数据的二级缓存(可选)。org.hibernate.SessionFactory接口提供了工厂方法来获取Session的对象。
会话(Session)
Session对象提供应用程序和存储在数据库中的数据之间的接口。它是一个短生命周期的对象并包装JDBC连接。它是事务,查询和标准的工厂。 它拥有一级缓存(强制性)数据。org.hibernate.Session接口提供插入,更新和删除对象的方法。它还提供了事务,查询和标准的工厂方法。
事务(Transaction)
事务对象指定工作的原子单位,它是一个可选项。org.hibernate.Transaction接口提供事务管理的方法。
连接提供者(ConnectionProvider)
它是一个JDBC连接工厂。它从DriverManager或DataSource抽象出来的应用程序。它是一个可选项。
事务工厂(TransactionFactory)
它是一个事务工厂,是一个可选项。

3. Hibernate简单示例

3.1 创建一个Maven项目,目录结构如下:

Hibernate从入门到精通_第2张图片

3.2 在pom.xml里添加要依赖的jar配置


	UTF-8
	5.2.1.Final



	
		org.hibernate
		hibernate-core
		${hibernate.version}
	
	
		mysql
		mysql-connector-java
		8.0.12
	
	
		junit
		junit
		4.11
		test
	

3.3 创建表结构(如果这里不创建,hibernate可以自动生成表结构)

Hibernate从入门到精通_第3张图片

3.4 创建实体类HUser

public class HUser implements java.io.Serializable {
	private static final long serialVersionUID = 1L;
	
	private Integer id;
	private String name;
	
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}

3.5 创建实体类的映射文件Huser.hbm.xml





	
		
			
			
		
		
			
		
	

3.6 创建配置文件hibernate.cfg.xml




	
		
		com.mysql.cj.jdbc.Driver
		
		jdbc:mysql://localhost:3306/hibernatetest?useSSL=false&serverTimezone=UTC
		root
		root
		
		org.hibernate.dialect.MySQL5Dialect
		
		true
		
		true
		
		update
		
	

3.7 创建管理Session的辅助类

public class HibernateUtil {
	private static SessionFactory sessionFactory;
	static {
		sessionFactory =  new Configuration().configure("hibernate.cfg.xml").buildSessionFactory();
	}

	public static SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	/**
	 * Session是由SessionFactory负责创建的,而SessionFactory的实现是线程安全的,多个并发的线程可以同时访问一 个SessionFactory并从中获取Session实例,
	 * 而Session不是线程安全的。Session中包含了数 据库操作相关的状态信息,如果多个线程同时使用一个Session实例进行CRUD,就可能导致数据存取的混乱。
	 * java.lang.ThreadLocal,在编写多线程程序时提供了一种解决方案。
	 * 线程局部变量(ThreadLocal)就是为每一个使用该变量的线程都提供一个变量值的副本,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。
	 * 从线程的角度看,就好像每 一个线程都完全拥有一个该变量。 ThreadLocal这个类本身不是代表线程要访问的变量,这个类的成员变量才是。
	 * JDK1.5给ThreadLocal加了泛型功能,即是 ThreadLocal,这个泛型T即是要线程的本地变量。线程通过ThreadLocal的get和set方法去访问这个变量T。
	 * ThreadLocal类中有一个Map,用于存储每一个线程的变量的副本。
	 */
	private static final ThreadLocal threadLocal = new ThreadLocal();
	
	public static Session getSession() throws HibernateException {
		Session session = (Session) threadLocal.get();
		if (session == null) {
			session = sessionFactory.openSession();
			threadLocal.set(session);
		}
		return session;
	}

	public static void closeSession() throws HibernateException {
		Session session = (Session) threadLocal.get();
		if (session != null)
			session.close();
		threadLocal.set(null);
	}

	public static void shutdown() {
		getSessionFactory().close();
	}
}

3.8 创建测试类

public class HibernateTest {

	private Session session;
	private Transaction tx;

	@Before
	public void before() {
		session = HibernateUtil.getSession();
		tx = session.beginTransaction();
	}

	@Test
	public void test() {
		try {
			HUser hUser = new HUser();
			hUser.setName("hibernate demo");
			session.save(hUser);// 这里操作的是java对象
			tx.commit();
			System.out.println("保存成功!");
		} catch (Exception e) {
			e.printStackTrace();
			tx.rollback();
			System.out.println("保存失败!");
		} finally {
			HibernateUtil.closeSession();
		}
	}

	@After
	public void after() {
		HibernateUtil.shutdown();
	}
}

4. Hibernate注解

由上一个章节可以看出每一个实体类,都需要有一个以*.hbm.xml(*即类名)命名的映射文件,如果实体类很多,那么会有很多映射文件,这样很不友好。而Hibernate注解可以解决这个问题。如@Entity,@Id,@Table,@Column等。

下面四个常用注解及解释:

@Entity注释将此类标记为实体。
@Table注释指定要保留此实体的数据的表名。 如果不使用@Table注释,hibernate将使用类名作为表名称bydefault。
@Id注释标记此实体的标识符。
@Column注释指定此属性或字段的列的详细信息。如果未指定@Column注释,则属性名称将用作列名称bydefault。

Hibernate注解基于JPA 2规范,并支持所有功能。所有JPA注释都在javax.persistence.*包中定义。Hibernate EntityManager实现由JPA规范定义的接口和生命周期。

4.1 修改实体类HUser

@Entity
@Table(name = "huser")
public class HUser implements java.io.Serializable {
	private static final long serialVersionUID = 1L;

	private Integer id;
	private String name;

	/**
	 * @Id 定义为数据库的主键ID 
	 * 建议不要在属性上引入注解,因为属性是private的,如果引入注解会破坏其封装特性,所以建议在getter方法上加入注解。
	 * @GeneratedValue ID的生成策略为自动生成
	 */
	@Id
	@Column(name = "hid")
	@GeneratedValue
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	@Column(name = "hname", length = 20)
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}

4.2 修改配置文件hibernate.cfg.xml




5. Hibernate生命周期

Hibernate中的一个对象存在于以下四个状态之中的一种:

  • 短暂(Transient)
  • 持久(Persistent)
  • Removed
  • Detached

以上几个状态在下面图中解释:

Hibernate从入门到精通_第4张图片

下面来看这几个状态的流转说明 -

当从一个实体创建一个新的Java对象时,该对象处于“短暂”状态。 Hibernate不知道它的存在,因为它独立于Hibernate的管理。

如果使用方法:get,load或find获取实体对象,则将获得一个等同于数据库中的1条记录的对象。 此对象处于Persistent状态。 它由Hibernate管理。

会话调用方法:save,saveOrUpdate和persist。 合并将短暂(Transient)对象置于Hibernate的管理之下,此对象转为持久化(Persistent)状态。 在使用的具体情况下,它向数据库插入或更新数据。

Session调用evict(..)或clear(),以便从处于Hibernate管理状态的对象处于关闭状态,并且这些对象处于分离(Detached)的状态。

使用update(..),saveOrUpdate(..),merge(..)将有助于重新连接分离对象。 在具体情况下,它会向数据库中创建更新或插入数据。 对象转回持久化(Persistent)状态。

Session调用方法:remove(..),delete(..)删除除记录并持久化对象。

6. Hibernate集合映射

可以在Hibernate中映射持久类的集合元素。 您需要从以下类型之一声明持久类中的集合类型:

    java.util.List
    java.util.Set
    java.util.SortedSet
    java.util.Map
    java.util.SortedMap
    java.util.Collection
    org.hibernate.usertype.UserCollectionType

有很多元素的子元素用来映射集合。 它们是
key元素
元素用于根据原始身份在连接的表中定义外键。 外键元素默认为空。 所以对于不可空的外键,需要指定not-null属性。key元素的属性是column,on-delete,property-ref,not-null,update和unique。
索引集合
集合元素可以分为两种形式:索引和非索引。List 和 Map集合都可被索引,而集合和行集合是非索引的。这里,索引收集 List 和 Map需要一个额外的元素元素用于标识类型。
集合元素
集合元素可以具有值或实体引用(另一个类对象)。可以使用4个元素之一。element,component-element,one-to-many,many-to-many。
element 和 component-element 用于正常值,例如string,int等,而一对多和多对多用于映射实体引用。但是如果集合存储实体引用(另一个类对象),我们需要定义元素。

6.1 集合映射中的映射列表(List)示例

List中存储字符串值而不是实体引用的示例,这就是为什么要在列表元素中使用element标签而不是one-to-many标签的元素。

持久化类

public class Article {
	private int id;
	private String title;
	private String content;
	private List comments;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	public List getComments() {
		return comments;
	}

	public void setComments(List comments) {
		this.comments = comments;
	}
}

持久化类的映射文件


	
		
			
		
		
		

		
			
			
			
		

	

更新hibernate.hnm.xml配置文件

存储数据类

@Test
public void test() {
	try {
		ArrayList comments = new ArrayList();
		comments.add("文章写的真好~");
		comments.add("文章写的棒棒哒~");
	        
	        Article article = new Article();
	        article.setTitle("Hibernate入门到精通");
	        article.setContent("Hibernate入门到精通的内容是。。。");
	        article.setComments(comments);

	        session.persist(article);

		tx.commit();
			
		Query
query = session.createQuery("from Article"); List
articles = query.list(); Iterator
itr = articles.iterator(); while (itr.hasNext()) { Article art = itr.next(); System.out.println("Article Title: " + art.getTitle()); List cmts = art.getComments(); Iterator itr2 = cmts.iterator(); while (itr2.hasNext()) { System.out.println(itr2.next()); } } session.close(); System.out.println("success"); } catch (Exception e) { e.printStackTrace(); tx.rollback(); } }

如果持久化类具有包含实体引用的列表(List)对象,则需要使用一对多关联来映射列表元素。
在这里,我们使用博客发表文章应用场景,在博客上一篇文章有多个评论。
在这种情况下,一篇文章可以有多个评论,每个评论可能有自己的信息,这就是为什么在持久化类中使用列表(包含Comment类的引用)来表示一系列评论。

持久化类

public class Article {
	private int id;
	private String title;
	private String content;
	private List comments;

	//getters and setters
}

public class Comment {
	private int id;
	private String commentcontent;
	private String postedBy;

	//getters and setters
}

持久化类的映射文件Article.hbm.xml和Comment.hbm.xml


	
		
			
		
		
		

		
		
			
			
			
			
		
	





	
		
			
		
		
		
	

配置文件hibernate.cfg.xml


存储数据的类

@Test
public void test() {
	try {
		ArrayList comments = new ArrayList();
		
		Comment comment1 = new Comment();
		comment1.setCommentcontent("文章写的真好~");
		comment1.setPostedBy("Angelia头号粉!!!");
		
		Comment comment2 = new Comment();
		comment2.setCommentcontent("文章写的棒棒哒~");
		comment2.setPostedBy("Angelia二号粉!!!");
		
		comments.add(comment1);
		comments.add(comment2);
        
                Article article = new Article();
                article.setTitle("Hibernate入门到精通");
                article.setContent("Hibernate入门到精通的内容是。。。");
                article.setComments(comments);

                session.persist(article);

	        tx.commit();
		
	        Query
query = session.createQuery("from Article"); List
articles = query.list(); Iterator
itr = articles.iterator(); while (itr.hasNext()) { Article art = itr.next(); System.out.println("Article Title: " + art.getTitle()); List cmts = art.getComments(); Iterator itr2 = cmts.iterator(); while (itr2.hasNext()) { System.out.println(itr2.next()); } } session.close(); System.out.println("success"); } catch (Exception e) { e.printStackTrace(); tx.rollback(); } }

6.2 若持久类有List对象,我们可以通过列表或者bag元素在映射文件中映射。这个包(bag)就像List一样,但它不需要索引元素。

  
          
          



        
        

请注意,bag不是基于索引的,而list是基于索引的。

6.3 若持久类具有Set对象,可以在映射文件中使用set元素映射Set集合。set元素不需要索引元素。List和Set之间的区别是: Set只存储唯一的值。

  
          
          




        
        
        
        

6.4 Hibernate允许我们将Map元素与RDBMS进行映射。我们知道,List和Map是基于索引的集合。 在map的情况下,索引列作为键,元素列用作值。

持久化类

public class Article {
	private int id;
	private String title;
	private String content;
	private Map comments;

	//getters and setters

}

持久化类的映射文件Article.hbm.xml


	
		
			
		
		
		

		
                    
                    
                    
                
	

存储数据的类

@Test
public void test() {
	try {
		HashMap comments = new HashMap();
		comments.put("文章写的真好~", "Angelia的头号粉丝");
		comments.put("文章写的棒棒哒~", "Angelia的二号粉丝");

		Article article = new Article();
		article.setTitle("Hibernate入门到精通");
		article.setContent("Hibernate入门到精通的内容是。。。");
		article.setComments(comments);

		session.persist(article);

		Query query = session.createQuery("from Article ");
		List
list = query.list(); Iterator
iterator = list.iterator(); while (iterator.hasNext()) { Article art = iterator.next(); System.out.println("Article title:" + art.getTitle()); Map map = art.getComments(); Set> set = map.entrySet(); Iterator> itercomment = set.iterator(); while (itercomment.hasNext()) { Map.Entry entry = (Map.Entry) itercomment.next(); System.out.println("Comment name:" + entry.getKey()); System.out.println("Comment posted by:" + entry.getValue()); } } session.close(); System.out.println("success"); } catch (Exception e) { e.printStackTrace(); tx.rollback(); } }

6.5 双向映射

持久化类

public class Article {
	private int id;
	private String title;
	private String content;
	private Set comments;

	//getters and setters
}

public class Comment {
	private int id;
	private String commentcontent;
	private String postedBy;
	
	private Article article;

	//getters and setters
}

持久化类的映射文件Article.hbm.xml和Comment.hbm.xml


	
		
			
		
		
				

		
			
			
		
	





	
		
			
		
		
		
		
		
			
		
	


你可能感兴趣的:(Hibernate)