hibernate的CRUD操作

本文简单总结一下hibernate的具有映射关系CRUD操作,主要使用到了cascade和fetch,其中cascade针对的是CUD操作,表示级联关系,fetch针对的是R操作,表示级联加载方式。

1.先看下javaEE的API中关于cascade的描述

javax.persistence
Enum CascadeType

java.lang.Object
  java.lang.Enum
      javax.persistence.CascadeType
All Implemented Interfaces:
Serializable, Comparable< CascadeType>

public enum CascadeType
extends Enum< CascadeType>
 
  

Defines the set of cascadable operations that are propagated to the associated entity. The value cascade=ALL is equivalent to cascade={PERSIST, MERGE, REMOVE, REFRESH}.

Since: Java Persistence 1.0
Enum Constant Summary
ALL           Cascade all operations
MERGE           Cascade merge operation
PERSIST           Cascade persist operation
REFRESH           Cascade refresh operation
REMOVE           Cascade remove operation

 

Method Summary
static CascadeType valueOf(String name)           Returns the enum constant of this type with the specified name.
static CascadeType[] values()           Returns an array containing the constants of this enum type, in the order they're declared.

 

Methods inherited from class java.lang.Enum
clone, compareTo, equals, getDeclaringClass, hashCode, name, ordinal, toString, valueOf

 

Methods inherited from class java.lang.Object
finalize, getClass, notify, notifyAll, wait, wait, wait

具体的使用方式,以annotation为例,例如@ManyToOne(cascade=CascadeType.ALL),其中cascade的值可以是一个数组。

2.再看下javaEE的API中关于fetch的描述

javax.persistence Enum FetchType

java.lang.Object
  java.lang.Enum
      javax.persistence.FetchType
All Implemented Interfaces:
Serializable, Comparable< FetchType>

public enum FetchType
extends Enum< FetchType>
 
  

Defines strategies for fetching data from the database. The EAGER strategy is a requirement on the persistence provider runtime that data must be eagerly fetched. The LAZY strategy is a hint to the persistence provider runtime that data should be fetched lazily when it is first accessed. The implementation is permitted to eagerly fetch data for which the LAZY strategy hint has been specified. In particular, lazy fetching might only be available for Basic mappings for which property-based access is used.

   Example:
   @Basic(fetch=LAZY)
   protected String getName() { return name; }
 

Since:
Java Persistence 1.0

Enum Constant Summary
EAGER
          Defines that data must be eagerly fetched
LAZY
          Defines that data can be lazily fetched

 

Method Summary
static FetchType valueOf(String name)
          Returns the enum constant of this type with the specified name.
static FetchType[] values()
          Returns an array containing the constants of this enum type, in the order they're declared.

 

Methods inherited from class java.lang.Enum
clone, compareTo, equals, getDeclaringClass, hashCode, name, ordinal, toString, valueOf

 

Methods inherited from class java.lang.Object
finalize, getClass, notify, notifyAll, wait, wait, wait

具体的使用方式,以annotation为例,例如@ManyToOne(fetch=FetchType.EAGER)。

3.进行CRCD的C,即插入(insert)操作

仍然使用之前的Group和User,二者为一对多关系

Group

package com.baosight.model;

import java.util.*;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name="t_group")
public class Group {
	private String id;
	private String name;
	private Set users = new HashSet();
	@Id
	@GeneratedValue//auto
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@OneToMany(mappedBy="group",cascade=CascadeType.ALL)
	public Set getUsers() {
		return users;
	}
	public void setUsers(Set users) {
		this.users = users;
	}
}
User

package com.baosight.model;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;

@Entity
@Table(name="t_user")
public class User {
	private String id;
	private String name;
	private Group group;
	@Id
	@GeneratedValue//auto
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@ManyToOne(cascade=CascadeType.ALL)
	public Group getGroup() {
		return group;
	}
	public void setGroup(Group group) {
		this.group = group;
	}
}
使用JUnit进行测试
package com.baosight.model;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Configuration;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

public class OrMappingTest {
	private static SessionFactory sf = null;
	@BeforeClass
	public static void beforeClass(){
		new SchemaExport(new AnnotationConfiguration().configure()).create(false, true);
		// 读取配置文件
		Configuration cfg = new AnnotationConfiguration();
		// 得到session工厂
		sf = cfg.configure().buildSessionFactory();
	}
	
	@Test
	public void testSaveUser() {
		Group g = new Group();
		User u = new User();
		u.setName("u1");
		g.setName("g1");
		u.setGroup(g);
		Session s = sf.getCurrentSession();
		s.beginTransaction();
//		s.save(g);
		s.save(u);
		s.getTransaction().commit();
	}
	@Test
	public void testSaveGroup() {
		User u1 = new User();
		u1.setName("u1");
		User u2 = new User();
		u2.setName("u2");
		Group g = new Group();
		g.setName("g1");
		g.getUsers().add(u1);
		g.getUsers().add(u2);
		u1.setGroup(g);
		u2.setGroup(g);
		Session s = sf.getCurrentSession();
		s.beginTransaction();
		s.save(g);
		s.getTransaction().commit();
	}
	@Test
	public void testGetUser() {
		testSaveGroup();
		Session s = sf.getCurrentSession();
		s.beginTransaction();
		User u = (User) s.get(User.class, "2");
		s.getTransaction().commit();
		System.out.println(u.getGroup().getName());
	}
	@Test
	public void testUpdateUser() {
		testSaveGroup();
		
		Session s = sf.getCurrentSession();
		s.beginTransaction();
		User u = (User) s.get(User.class, "2");
		s.getTransaction().commit();
		
		u.setName("user");
		u.getGroup().setName("group");
		
		Session s2 = sf.getCurrentSession();
		s2.beginTransaction();
		s2.update(u);
		s2.getTransaction().commit();
		
	}
	@Test
	public void testLoadUser() {
		testSaveGroup();
		Session s = sf.getCurrentSession();
		s.beginTransaction();
		User u = (User) s.load(User.class, "2");
		System.out.println(u.getGroup().getName());
		s.getTransaction().commit();
	}
	@Test
	public void testDeleteUser() {
		testSaveGroup();
		Session s = sf.getCurrentSession();
		s.beginTransaction();
//		User u = (User) s.load(User.class, "2");
//		u.setGroup(null);
//		s.delete(u);
		s.createQuery("delete from User u where u.id=2").executeUpdate();
		s.getTransaction().commit();
	}
	@Test
	public void testGetGroup() {
		testSaveGroup();
		Session s = sf.getCurrentSession();
		s.beginTransaction();
		Group g = (Group) s.get(Group.class, "1");
		s.getTransaction().commit();
		for(User u:g.getUsers()){
			System.out.println(u.getName());
		}
	}
	@Test
	public void testLoadGroup() {
		testSaveGroup();
		Session s = sf.getCurrentSession();
		s.beginTransaction();
		Group g = (Group) s.load(Group.class, "1");
		for(User u:g.getUsers()){
			System.out.println(u.getName());
		}
		s.getTransaction().commit();
	}
	@Test
	public void testDeleteGroup() {
		testSaveGroup();
		Session s = sf.getCurrentSession();
		s.beginTransaction();
		Group g = (Group) s.load(Group.class, "1");
		for(User u:g.getUsers()){
			u.setGroup(null);
		}
		g.setUsers(null);
		s.delete(g);
		s.getTransaction().commit();
	}
	/*@Test
	public void testSchemaExport() {
	}*/
	@AfterClass
	public static void afterClass(){
		// 关闭session工厂
		sf.close();
	}
}
其中测试C使用的方法为testSaveUser和testSaveGroup

3.1先看testSaveUser,当不设置Group和User二者之间的关联时,方法为:

	@Test
	public void testSaveUser() {
		Group g = new Group();
		User u = new User();
		u.setName("u1");
		g.setName("g1");
//		u.setGroup(g);
		Session s = sf.getCurrentSession();
		s.beginTransaction();
		s.save(g);
		s.save(u);
		s.getTransaction().commit();
	}
运行结果为

hibernate的CRUD操作_第1张图片

可以看到2张表插入的数据没有关联,group_id是null

3.2当testSaveUser设置Group和User二者之间的关联时,方法为:

@Test
	public void testSaveUser() {
		Group g = new Group();
		User u = new User();
		u.setName("u1");
		g.setName("g1");
		u.setGroup(g);
		Session s = sf.getCurrentSession();
		s.beginTransaction();
//		s.save(g);
		s.save(u);
		s.getTransaction().commit();
	}
需要在User中的getGroup上使用@ManyToOne(cascade=CascadeType.ALL),表示级联保存

@ManyToOne(cascade=CascadeType.ALL)
	public Group getGroup() {
		return group;
	}
运行结果

hibernate的CRUD操作_第2张图片


可以看到,这时group_id就有值了。

3.3再看看testSaveGroup,当仅在Group设置二者之间的关联时,方法为:

@Test
	public void testSaveGroup() {
		User u1 = new User();
		u1.setName("u1");
		User u2 = new User();
		u2.setName("u2");
		Group g = new Group();
		g.setName("g1");
		g.getUsers().add(u1);
		g.getUsers().add(u2);
//		u1.setGroup(g);
//		u2.setGroup(g);
		Session s = sf.getCurrentSession();
		s.beginTransaction();
		s.save(g);
		s.getTransaction().commit();
	}
需要在Group中的getUsers上使用@OneToMany(mappedBy="group",cascade=CascadeType.ALL),表示级联保存

@OneToMany(mappedBy="group",cascade=CascadeType.ALL)
	public Set getUsers() {
		return users;
	}
测试结果为

hibernate的CRUD操作_第3张图片

可以看到,是有问题的,此时group_id的值为null

3.4还需要在上面的User设置关联,testSaveGroup为

@Test
	public void testSaveGroup() {
		User u1 = new User();
		u1.setName("u1");
		User u2 = new User();
		u2.setName("u2");
		Group g = new Group();
		g.setName("g1");
		g.getUsers().add(u1);
		g.getUsers().add(u2);
		u1.setGroup(g);
		u2.setGroup(g);
		Session s = sf.getCurrentSession();
		s.beginTransaction();
		s.save(g);
		s.getTransaction().commit();
	}
这时,group_id就有值了


4.关于CRUD的R,即读取操作,主要使用的是get和load方法,使用到的是fetch

值得一提的是,对于本例中的Many2One/One2Many双向关联,在不设置fetch的时候,hibernate对于fetch是有默认值的。

具体来说,@ManyToOne的默认值为fetch=FetchType.EAGER。例如本例中User不设置fetch相当于设置了fetch=FetchType.EAGER,当R的时候会自动级联查询1的一方

@OneToMany的默认值为fetch=FetchType.LAZY。例如本例中Group不设置fetch相当于设置了fetch=FetchType.LAZY,当R的时候不会自动级联查询多的一方

首先看下get方法

4.1看下testGetUser方法

@Test
	public void testGetUser() {
		testSaveGroup();
		Session s = sf.getCurrentSession();
		s.beginTransaction();
		User u = (User) s.get(User.class, "2");
		s.getTransaction().commit();
		System.out.println(u.getGroup().getName());
	}
结果为

hibernate的CRUD操作_第4张图片

从结果可以看到,会自动进行级联查询
4.2看下testGetGroup方法

@Test
	public void testGetGroup() {
		testSaveGroup();
		Session s = sf.getCurrentSession();
		s.beginTransaction();
		Group g = (Group) s.get(Group.class, "1");
		s.getTransaction().commit();
		for(User u:g.getUsers()){
			System.out.println(u.getName());
		}
	}
运行结果为

hibernate的CRUD操作_第5张图片

上面讲过@OneToMany的默认值为fetch=FetchType.LAZY,所以未执行对User的查询

4.3修改Group的getUsers方法

@OneToMany(mappedBy="group",cascade=CascadeType.ALL,fetch=FetchType.EAGER)
	public Set getUsers() {
		return users;
	}
测试结果为

hibernate的CRUD操作_第6张图片

再来看看load方法

4.4看下testLoadUser

@Test
	public void testLoadUser() {
		testSaveGroup();
		Session s = sf.getCurrentSession();
		s.beginTransaction();
		User u = (User) s.load(User.class, "2");
		System.out.println(u.getGroup().getName());
		s.getTransaction().commit();
	}
执行结果为

hibernate的CRUD操作_第7张图片

4.5看下testLoadGroup

@Test
	public void testLoadGroup() {
		testSaveGroup();
		Session s = sf.getCurrentSession();
		s.beginTransaction();
		Group g = (Group) s.load(Group.class, "1");
		for(User u:g.getUsers()){
			System.out.println(u.getName());
		}
		s.getTransaction().commit();
	}
执行结果为

hibernate的CRUD操作_第8张图片

注意,此时,并为设置Group和Use的fetch属性

5.CRUD的U,即修改操作,主要使用的是update方法

前面提到了,可以设置cascade指明级联方式,再执行与之相对应的操作

看下testUpdateUser

@Test
	public void testUpdateUser() {
		testSaveGroup();
		
		Session s = sf.getCurrentSession();
		s.beginTransaction();
		User u = (User) s.get(User.class, "2");
		s.getTransaction().commit();
		
		u.setName("user");
		u.getGroup().setName("group");
		
		Session s2 = sf.getCurrentSession();
		s2.beginTransaction();
		s2.update(u);
		s2.getTransaction().commit();
		
	}
执行结果为

hibernate的CRUD操作_第9张图片

6.CRUD的D,即删除操作,主要使用delete方法

6.1先看下testDeleteUser

@Test
	public void testDeleteUser() {
		testSaveGroup();
		Session s = sf.getCurrentSession();
		s.beginTransaction();
		User u = (User) s.load(User.class, "2");
//		u.setGroup(null);
		s.delete(u);
//		s.createQuery("delete from User u where u.id=2").executeUpdate();
		s.getTransaction().commit();
	}

测试结果

hibernate的CRUD操作_第10张图片

由于Group和User中都设置了cascade,所以删除User数据会级联删除Group的数据

6.2要想只删除User的数据,需要在删除之前先切断映射关系

@Test
	public void testDeleteUser() {
		testSaveGroup();
		Session s = sf.getCurrentSession();
		s.beginTransaction();
		User u = (User) s.load(User.class, "2");
		u.setGroup(null);
		s.delete(u);
//		s.createQuery("delete from User u where u.id=2").executeUpdate();
		s.getTransaction().commit();
	}
执行结果

hibernate的CRUD操作_第11张图片

6.3当然,在明确知道要删除的多的一方的id的话,还可以直接执行HQL进行删除操作

@Test
	public void testDeleteUser() {
		testSaveGroup();
		Session s = sf.getCurrentSession();
		s.beginTransaction();
//		User u = (User) s.load(User.class, "2");
//		u.setGroup(null);
//		s.delete(u);
		s.createQuery("delete from User u where u.id=2").executeUpdate();
		s.getTransaction().commit();
	}

执行结果

hibernate的CRUD操作_第12张图片
6.4看下testDeleteGroup

@Test
	public void testDeleteGroup() {
		testSaveGroup();
		Session s = sf.getCurrentSession();
		s.beginTransaction();
		Group g = (Group) s.load(Group.class, "1");
//		for(User u:g.getUsers()){
//			u.setGroup(null);
//		}
//		g.setUsers(null);
		s.delete(g);
		s.getTransaction().commit();
	}
运行结果

hibernate的CRUD操作_第13张图片
由于Group和User都设置了cascade,所以在删除Group的同时会级联删除相关的User数据

为了解决这一问题,需要在删除之前,先将二者之间的级联设置为null

注意,只删除一方无效果,需要将双方的关联都去除

6.5只删除1,不删除多

@Test
	public void testDeleteGroup() {
		testSaveGroup();
		Session s = sf.getCurrentSession();
		s.beginTransaction();
		Group g = (Group) s.load(Group.class, "1");
		for(User u:g.getUsers()){
			u.setGroup(null);
		}
		g.setUsers(null);
		s.delete(g);
		s.getTransaction().commit();
	}
运行结果为

hibernate的CRUD操作_第14张图片
可以看到在删除1之前首先解除了多对其的引用

以上即为hibernate的CRUD常见的操作,需要注意cascade和fetch的配置,需要在具体的使用中仔细体会。





你可能感兴趣的:(hibernate,java)