欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JPA中(单向)多对一关联关系

程序员文章站 2022-04-15 22:11:58
...

JPA多对一关系映射

1.实体类

1).Employee实体类

/**
 * 如何将java实体类,与mysql中的表映射呢?
 * 	通过注解进行配置即可。
 * 编写实体类,关于基本类型属性,一定不要使用基本类型,而是
 * 使用对应的包装类型,为什么呢?
 * 	基本类型属性,如果没有赋值,有一个默认值。
 * 	例如: int age;默认值age=0,0是代表没有填写年龄?0岁?
 * 	推荐使用改包装类:Integer,是一个引用类型数据,如果没有值,默认是null。
 * @author boge
 */
/**
 * Entity注解表示当前类是一个可以与mysql表映射的实体类,表明默认是:Employee的小写
 * 如果,你不喜欢这样,可以通过@Table注解来标识
 * 
 * @Baisic:标识在每一个get方法之上,表示与mysql表中的字段映射,默认就有。
 *  
 * mysql表中的字段,生成,默认按照实体类的get方法进行判断的。
 * 	下面我们做了一个案例,getUserName1方法,但是没有userName1属性。
 * 	结果,在mysql表中,就出现了userName1属性。
 * 	这就证明了,hibernate生成的mysql表中的列,默认是按照get方法进行判断的,而不是
 * 成员属性判断的。
 * @author boge
 */

@Table(name="emp")
@Entity
public class Employee {
	private Integer empId;
	private String userName;
	private Integer age;
	private String address;
	private String gender;
	
	//在多方,使用成员属性,来关联1方实体类
	//在表中,如何体现,关联关系?外键!在多方表中,使用一个外键列,关联一方的主键
	private Department dept;
	
	/**
	 * @ManyToOne默认是立即加载,EAGER,表示查询多方实体对象时,立即将他
	 * 关联的一方实体对象查询出来,并放到多方的成员属性
	 * 如果,修改fetch=FetchType.LAZY,则表示懒加载,意思就是:
	 * 	如果只查询多方数据,只发送查询多方的sql语句,并不会立即查询关联的一方数据。
	 * 	什么时候,通过多方实体对象,调用了关联的一方实体对象,则再发起查询语句去查询一方数据。
	 * 他们适用什么场景?
	 * 	1、如果你的业务场景,仅仅针对多方进行查询,并不需要他的一方数据,以后会单独某个多方
	 * 关联的一方数据,那这种场景,就设置为懒加载。
	 * 	2、如果,你的业务场景,查询多方数据时,必须要立刻查询出来关联的一方数据,那就使用默认的
	 * EAGER立即查询即可。
	 * @return
	 */
	@ManyToOne(fetch=FetchType.LAZY)//关联的对象,采用懒加载查询
	@JoinColumn(name="dept")//指定在多方表中的外键列名称
	public Department getDept() {
		return dept;
	}
	public void setDept(Department dept) {
		this.dept = dept;
	}

	/**
	 * @Id表示:映射mysql表中的主键,你希望哪个java类的属性,映射mysql中的中间,
	 * 你就在它对应的get方法上,添加ID注解即可
	 * 
	 * 如果,你使用的数字,你希望,主键自增,对应mysql表的:auto_increment
	 * 通过@GeneratedValue来指定主键自增策略,strategy指定具体采取哪个策略。
	 * IDENTITY:主键自增
	 * @return
	 */
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	public Integer getEmpId() {
		return empId;
	}
	public void setEmpId(Integer empId) {
		this.empId = empId;
	}
	/*
	 * 默认列名,就是java类的属性名,通过@Column进行修改
	 * ,unique=true,nullable=false
	 */
	@Column(name="user_name")
	@Basic()//  optional=false   userName字段,不能为null
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	/**
	 * 添加@Transient表示,忽略该属性对应的字段,将来就不会针对该属性进行映射
	 * 表中也不会有该字段
	 * 但是要注意:千万不要导错包,是:javax.persistences
	 * @return
	 */
//	@Transient
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
	@Override
	public String toString() {
		return "Employee [empId=" + empId + ", userName=" + userName + ", age=" + age + ", address=" + address
				+ ", gender=" + gender + "]";
	}
	public Employee(Integer empId, String userName, Integer age, String address, String gender) {
		super();
		this.empId = empId;
		this.userName = userName;
		this.age = age;
		this.address = address;
		this.gender = gender;
	}
	/**
	 * 如果你生成了有参构造方法,一定要为该实体类,提供一个无参构造方法
	 */
	public Employee() {
		super();
	}
}

2).Department实体类

@Entity
public class Department {

	private Integer deptId;
	private String deptName;
	private String deptManager;
	
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	public Integer getDeptId() {
	return deptId;
	}
	public void setDeptId(Integer deptId) {
	this.deptId = deptId;
	}
	public String getDeptName() {
		return deptName;
	}
	public void setDeptName(String deptName) {
		this.deptName = deptName;
	}
	public String getDeptManager() {
		return deptManager;
	}
	public void setDeptManager(String deptManager) {
		this.deptManager = deptManager;
	}
	@Override
	public String toString() {
		return "Department [deptId=" + deptId + ", deptName=" + deptName + ", deptManager=" + deptManager + "]";
	}
}

2.测试类(RMTest)

注:测试方法由下往上依次看更容易理解

/**
 * 关系映射测试类,在本类中,测试实体类之间的关联关系
 * @author boge
 */
public class RMTest {
	/**
	 * 1、单向多对一,员工和部门,两个实体
	 * 		Employee实体类为多方,Department实体类为一方
	 * 	单向多对一:在多方来关联一方的关联关系,只在多方编写关联代码
	 * 如何在多方中,关联一方呢?
	 * 	在多方实体类Employee当中,使用Department成员属性,来表示关联的一方实体类
	 * 在多方实体类中Employee,使用@ManyToOne注解,标注在一方的get方法上面即可。
	 * 	会自动生成多对一关联关系,生成的表当中,会自动添加一个外键列,来关联一方的主键列。
	 */
	EntityManagerFactory emf;
	EntityManager em;
	EntityTransaction transaction;

//	演示通过@ManyToOne注解的fetch属性,修改为懒加载模式。
//	演示查询多方时,默认采用左外连接关联查询一方数据。
	@Test
	public void test4(){
		/*
		 * 因为有ManyToOne关联关系,默认查询多方时,就会通过左外连接查询
		 * 立刻将多方关联的一方数据,查询出来,并且,封装到多方的成员属性当中。
		 * 这也是ORM的一个好处,通过关联对象,将关联的其他对象,直接查询出来。
		 * 同时,这也是一个弊端,如:当前你只想查询员工信息,并不想查询他的部门信息
		 * 但是,它会立即将部门信息查询出来。会影响性能。
		 */
		Employee xiaobai = em.find(Employee.class, 1);
		System.out.println(xiaobai);
		System.out.println(xiaobai.getDept());
	}

//	演示能不能删除一方持久态对象。
	@Test
	public void test3(){
			//持久态
		Department lizong = em.find(Department.class, 1);
		em.remove(lizong);
		//为什么提交了事务,删除持久态对象,报错?
		//原因是:可能是一方持久态对象,有关联的多方数据,所以不能删除,外键级联操作。
		transaction.commit();
	}
	
	@Test
	public void test2(){
		/*		演示一方、多方先、后保存的区别。
		 *  先保存多方,比后保存多方,多了一条Update语句,为什么呢?
		 *  	如果,先保存多方EMployee,在此时,并不知道一方的主键,因为一方还没插入呢!!
		 *  	于是,先保存Employee的除了外键列的其他列数据。
		 *  	然后再保存一方数据,得到了1方Department的主键
		 *  	最后再那种Department的主键去修改多方Employee的外键。
		 *  
		 *  如果先保存1方,就不会多一条UPDATA语句,为什么呢?
		 *  	因为,先保存了1方,1方的主键已经有了,再保存多方的时候,自然可以直接添加外键列。  
		 */
		Employee emp1 = new Employee(null, "小白", 18, "云南昆明", "男");
		Department department1 = new Department();
		department1.setDeptManager("李总");
		department1.setDeptName("研发部");
		//实现关联关系的映射,仅仅通过set方法即可。
		emp1.setDept(department1);
		
		em.persist(emp1);//多方员工
		em.persist(department1);//保存一方部门
		//em.persist(emp1);//多方员工
		
		transaction.commit();	
	}
	
	@Test
	public void test1(){
		Employee emp1 = new Employee(null, "小白", 18, "云南昆明", "男");
		Employee emp2 = new Employee(null, "小黑", 18, "云南昆明", "男");
		
		Department department1 = new Department();
		department1.setDeptManager("李总");
		department1.setDeptName("研发部");
		Department department2 = new Department();
		department2.setDeptManager("张总");
		department2.setDeptName("设计部");
		//通过对象关联的方式,将表中数据进行关联。
		emp1.setDept(department1);
		emp2.setDept(department2);
		
		em.persist(department1);
		em.persist(department2);
		
		em.persist(emp1);
		em.persist(emp2);
		transaction.commit();
		
		/*
		 * 经过测试,我们发现,jpa可以自动帮助我们维护关联关系,
		 * 如:它会自动在多方表中的记录中,通过外键列维护多对一的关系
		 * 而在java代码中,我们仅仅需要,通过java代码,实现对象之间的关联即可。
		 */
	}

	@Before
	public void before() {
		// 1、获取EntityMangerFactory
		emf = Persistence.createEntityManagerFactory("jpa-01");
		// 2、获取EntityManger
		// 重点对象,所有增删改查操作,都是通过它的方法进行的
		em = emf.createEntityManager();
		transaction = em.getTransaction();
		transaction.begin();
	}
}

3.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<!-- RESOURCE_LOCAL:开启本地事务的支持 -->
	<persistence-unit name="jpa-01" transaction-type="RESOURCE_LOCAL" >
	<!--  添加底层实现的支持 ,如,配置HIbernate对于JPA的支持-->
	<provider>org.hibernate.ejb.HibernatePersistence</provider>
	<!-- 映射的实体类 -->
	<class>
		com.kmu.entity.Employee
	</class>
	<class>
		com.kmu.entity.Department
	</class>

	<properties>
		<!-- 配置数据库连接信息 -->
		<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
		<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/jpa" />
		<property name="javax.persistence.jdbc.user" value="root" />
		<property name="javax.persistence.jdbc.password" value="123123" />
		<!-- 配置Hibernate框架需要的部分数据 -->
		<!-- 
			hibernate.format_sql:格式化sql,将来,程序运行时,会将运行的一些
			信息,打印在控制台,如执行的sql语句打印在控制台。
			hibernate.show_sql:在日志中,显示执行的mysql语句
			hibernate.hbm2ddl.auto:自动见表、更新表结构的操作。
				update:通过该配置选项,可以自动根据实体类,生成mysql中的数据表。
				none:则不会自动生成表,而是需要你手动亲自在mysql中创建一个与java类映射的表。
		 -->
		<property name="hibernate.format_sql" value="true" />
		<property name="hibernate.show_sql" value="true" />
		<property name="hibernate.hbm2ddl.auto" value="update" />
	</properties>
	</persistence-unit>
</persistence>

4.所用到得jpa-jar

百度网盘:
链接:https://pan.baidu.com/s/1IS_EMbgNUQXigoNbj3Sp8Q
提取码:r5jw