需求分析
eg 1-
部门与员工的例子
一个部门有多个员工[一对多]
多个员工,属于一个部门[多对一]
eg 2-
一个项目多个开发人员
一个开发人员参与多个项目 [多对多]
一对多与多对一映射
一.需求分析
二.数据库
t_dept
字段:deptId deptName
t_employee
字段:empId empName salary dept_id
三.javabean
设计关键:通过一方维护到另一方
class Dept{ private int deptId; private String deptName; //部门对应多个员工 private Set<Employee> emps; } class Employee{ private int empId; private String empName; private double salary; //多个员工对应一个部门 private Dept dept; }
四.映射
Dept映射关键点
1.映射的集合属性:"emps"
2.指定集合属性对应的集合表:"t_employee"
3.指定集合表的外键字段
4.指定集合元素的类型
Employee映射的关键点
1.映射的部门属性: dept
2.映射的部门对象,对应的外键字段:dept_id
3.部门的类型
实例-保存数据-查询数据
总配置文件
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!--1.数据库连接配置--> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql:///learnHibernate</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">33269456.cx</property> <!-- 数据库方言配置,hibernate会根据不同的方言生成符合当前数据库语法的sql --> <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property> <!--2.其他相关配置--> <!--2.1显示运行时的sql语句--> <property name="hibernate.show_sql">true</property> <!--2.2格式化sql--> <property name="hibernate.format_sql">true</property> <!--2.3自动建表,写好映射就可以--> <property name="hibernate.hbm2ddl.auto">update</property> <!--3.加载所有映射--> </session-factory> </hibernate-configuration>
Dept.java
package com.cx.entity; import java.util.HashSet; import java.util.Set; /** * Created by cxspace on 16-8-2. */ public class Dept { private int deptId; private String deptName; //一对多(一个部门对应多个员工) private Set<Employee> employees = new HashSet<>(); public int getDeptId() { return deptId; } public void setDeptId(int deptId) { this.deptId = deptId; } public String getDeptName() { return deptName; } public void setDeptName(String deptName) { this.deptName = deptName; } public Set<Employee> getEmployees() { return employees; } public void setEmployees(Set<Employee> employees) { this.employees = employees; } }
相关映射配置
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.cx.entity"> <class name="Dept" table="t_dept"> <id name="deptId"> <generator class="native"></generator> </id> <property name="deptName" length="20"></property> <!-- 1.映射的集合属性:"emps" 2.指定集合属性对应的集合表:"t_employee" 3.指定集合表的外键字段 4.指定集合元素的类型 --> <!--table="t_employee",可以省略--> <set name="employees" table="t_employee"> <key column="dept_id"></key> <one-to-many class="Employee"></one-to-many> </set> </class> </hibernate-mapping>
Employee.java
package com.cx.entity; /** * Created by cxspace on 16-8-2. */ public class Employee { private int empId; private String empName; private double salary; private Dept dept; public Dept getDept() { return dept; } public void setDept(Dept dept) { this.dept = dept; } public int getEmpId() { return empId; } public void setEmpId(int empId) { this.empId = empId; } public String getEmpName() { return empName; } public void setEmpName(String empName) { this.empName = empName; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } }
相关映射配置
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.cx.entity"> <class name="Employee" table="t_employee"> <id name="empId"> <generator class="native"></generator> </id> <property name="empName" length="20"></property> <property name="salary" type="double"></property> <!-- 多对一映射配置 Employee 映射关键点: 1. 映射的部门属性 : dept 2. 映射的部门属性,对应的外键字段: dept_id 3. 部门的类型 --> <many-to-one name="dept" column="dept_id" class="Dept"></many-to-one> </class> </hibernate-mapping>
测试类
package com.cx.test; import com.cx.entity.Dept; import com.cx.entity.Employee; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import org.junit.Test; /** * Created by cxspace on 16-8-2. */ public class Save { private static SessionFactory sf; static { sf = new Configuration() .configure() .addClass(Dept.class) .addClass(Employee.class) // 测试时候使用 .buildSessionFactory(); } //保存,部门方 一对一方法操作 public void save(){ Session session = sf.openSession(); session.beginTransaction(); //部门对象 Dept dept = new Dept(); dept.setDeptName("应用开发部"); //员工对象 Employee emp_zs = new Employee(); emp_zs.setEmpName("张三"); Employee emp_ls = new Employee(); emp_ls.setEmpName("李四"); //关系 dept.getEmployees().add(emp_zs); dept.getEmployees().add(emp_ls); //保存 session.save(emp_zs); session.save(emp_ls); session.save(dept); session.getTransaction().commit(); session.close(); /* * Hibernate: insert into t_employee (empName, salary, dept_id) values (?, ?, ?) Hibernate: insert into t_employee (empName, salary, dept_id) values (?, ?, ?) Hibernate: insert into t_dept (deptName) values (?) Hibernate: update t_employee set dept_id=? where empId=? Hibernate: update t_employee set dept_id=? where empId=? * */ } //保存,员工方[多对一保存],效率更高 @Test public void save2(){ Session session = sf.openSession(); session.beginTransaction(); Dept dept = new Dept(); dept.setDeptName("综合部"); Employee emp_zs = new Employee(); emp_zs.setEmpName("张三"); Employee emp_ls = new Employee(); emp_ls.setEmpName("李四"); emp_zs.setDept(dept); emp_ls.setDept(dept); session.save(dept); session.save(emp_ls); session.save(emp_zs); session.getTransaction().commit(); session.close(); /* * * 结果 * * Hibernate: insert into t_dept (deptName) values (?) Hibernate: insert into t_employee (empName, salary, dept_id) values (?, ?, ?) Hibernate: insert into t_employee (empName, salary, dept_id) values (?, ?, ?) * * * */ } }
结果
package com.cx.test; import com.cx.entity.Dept; import com.cx.entity.Employee; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import org.junit.Test; /** * Created by cxspace on 16-8-2. */ public class Get { private static SessionFactory sf; static { sf = new Configuration() .configure() .addClass(Dept.class) .addClass(Employee.class) // 测试时候使用 .buildSessionFactory(); } @Test public void get(){ Session session = sf.openSession(); session.beginTransaction(); //通过部门方获取另一方 // Dept dept = (Dept) session.get(Dept.class , 1); // System.out.println(dept.getDeptName()); // System.out.println(dept.getEmployees());
结果
Hibernate:
select
dept0_.deptId as deptId0_0_,
dept0_.deptName as deptName0_0_
from
t_dept dept0_
where
dept0_.deptId=?
应用开发部
Hibernate:
select
employees0_.dept_id as dept4_0_1_,
employees0_.empId as empId1_,
employees0_.empId as empId1_0_,
employees0_.empName as empName1_0_,
employees0_.salary as salary1_0_,
employees0_.dept_id as dept4_1_0_
from
t_employee employees0_
where
employees0_.dept_id=?
[com.cx.entity.Employee@d35dea7, com.cx.entity.Employee@24313fcc]
//通过员工获取部门 Employee emp = (Employee)session.get(Employee.class,1); System.out.println(emp.getEmpName()); System.out.println(emp.getDept().getDeptName()); session.getTransaction().commit(); session.close();
结果
Hibernate:
select
employee0_.empId as empId1_0_,
employee0_.empName as empName1_0_,
employee0_.salary as salary1_0_,
employee0_.dept_id as dept4_1_0_
from
t_employee employee0_
where
employee0_.empId=?
张三
Hibernate:
select
dept0_.deptId as deptId0_0_,
dept0_.deptName as deptName0_0_
from
t_dept dept0_
where
dept0_.deptId=?
应用开发部
}
}
Inverse属性
在维护关联关系的时候起作用。表示控制权是否转移。(在一的一方起作用)
inverse 控制反转
inverse = false不反转 有控制权
= true 控制反转 没有控制权 (不能主动维护另一方)
维护关联关系
1.保存数据
设计关联
如果设置控制反转,然后通过部门方维护关联关系。在保存部门的时候,同时保存员工,数据会保存,但关联关系不会维护,外键字段为NULL。
2.获取数据
无影响
3.解除关联关系
有影响
没有控制权无法接触关联关系,无法生成update语句,也不会报错
4.删除数据对关联关系的影响
有控制权,可以删除,先清空外键引用,再删除。
没控制权报错,无法删除。
测试代码
package com.cx.test; import com.cx.entity.Dept; import com.cx.entity.Employee; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import org.junit.Test; /** * Created by cxspace on 16-8-2. */ public class Inverse { private static SessionFactory sf; static { sf = new Configuration() .configure() .addClass(Dept.class) .addClass(Employee.class) // 测试时候使用 .buildSessionFactory(); } //inverse对保存数据的影响 public void save(){ Session session = sf.openSession(); session.beginTransaction(); //部门对象 Dept dept = new Dept(); dept.setDeptName("运维部"); //员工对象 Employee emp_zs = new Employee(); emp_zs.setEmpName("张三"); Employee emp_ls = new Employee(); emp_ls.setEmpName("李四"); //关系 dept.getEmployees().add(emp_zs); dept.getEmployees().add(emp_ls); //inverse = true ,不会设置关联,此时的关联应该通过员工方来维护 //保存 session.save(emp_zs); session.save(emp_ls); session.save(dept); session.getTransaction().commit(); session.close(); /* * * * Hibernate: insert into t_employee (empName, salary, dept_id) values (?, ?, ?) Hibernate: insert into t_employee (empName, salary, dept_id) values (?, ?, ?) Hibernate: insert into t_dept (deptName) values (?) * * * */ } //inverse属性,对获取数据的影响---无影响 public void get(){ Session session = sf.openSession(); session.beginTransaction(); Dept dept = (Dept) session.get(Dept.class,2); System.out.println(dept.getDeptName()); System.out.println(dept.getEmployees()); session.getTransaction().commit(); session.close(); /* * * * * Hibernate: select dept0_.deptId as deptId0_0_, dept0_.deptName as deptName0_0_ from t_dept dept0_ where dept0_.deptId=? 综合部 Hibernate: select employees0_.dept_id as dept4_0_1_, employees0_.empId as empId1_, employees0_.empId as empId1_0_, employees0_.empName as empName1_0_, employees0_.salary as salary1_0_, employees0_.dept_id as dept4_1_0_ from t_employee employees0_ where employees0_.dept_id=? [com.cx.entity.Employee@d35dea7, com.cx.entity.Employee@24313fcc] * * * * * * * * */ } public void removeRelation(){ Session session = sf.openSession(); session.beginTransaction(); Dept dept = (Dept)session.get(Dept.class,2); dept.getEmployees().clear(); session.getTransaction().commit(); session.close(); /* * inverse=true 没有控制权 * * Hibernate: select dept0_.deptId as deptId0_0_, dept0_.deptName as deptName0_0_ from t_dept dept0_ where dept0_.deptId=? * * * inverse = false Hibernate: select dept0_.deptId as deptId0_0_, dept0_.deptName as deptName0_0_ from t_dept dept0_ where dept0_.deptId=? Hibernate: select employees0_.dept_id as dept4_0_1_, employees0_.empId as empId1_, employees0_.empId as empId1_0_, employees0_.empName as empName1_0_, employees0_.salary as salary1_0_, employees0_.dept_id as dept4_1_0_ from t_employee employees0_ where employees0_.dept_id=? Hibernate: update t_employee set dept_id=null where dept_id=? * * */ } @Test public void deleteData(){ Session session = sf.openSession(); session.beginTransaction(); Dept dept = (Dept) session.get(Dept.class,1); session.delete(dept); session.getTransaction().commit(); session.close(); /* inverse = true Hibernate: select dept0_.deptId as deptId0_0_, dept0_.deptName as deptName0_0_ from t_dept dept0_ where dept0_.deptId=? Hibernate: delete from t_dept where deptId=? 报错 org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96) at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66) at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275) at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:268) at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:189) at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321) at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51) at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216) at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383) at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133) at com.cx.test.Inverse.deleteData(Inverse.java:217) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.internal.runners.TestMethodRunner.executeMethodBody(TestMethodRunner.java:99) at org.junit.internal.runners.TestMethodRunner.runUnprotected(TestMethodRunner.java:81) at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34) at org.junit.internal.runners.TestMethodRunner.runMethod(TestMethodRunner.java:75) at org.junit.internal.runners.TestMethodRunner.run(TestMethodRunner.java:45) at org.junit.internal.runners.TestClassMethodsRunner.invokeTestMethod(TestClassMethodsRunner.java:66) at org.junit.internal.runners.TestClassMethodsRunner.run(TestClassMethodsRunner.java:35) at org.junit.internal.runners.TestClassRunner$1.runUnprotected(TestClassRunner.java:42) at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34) at org.junit.internal.runners.TestClassRunner.run(TestClassRunner.java:52) at org.junit.runner.JUnitCore.run(JUnitCore.java:130) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:119) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144) Caused by: java.sql.BatchUpdateException: Cannot delete or update a parent row: a foreign key constraint fails (`learnHibernate`.`t_employee`, CONSTRAINT `FKFDCF5A195CFBCEF9` FOREIGN KEY (`dept_id`) REFERENCES `t_dept` (`deptId`)) at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:2054) at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1467) at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70) at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268) ... 32 more inverse = false 正常删除 Hibernate: select dept0_.deptId as deptId0_0_, dept0_.deptName as deptName0_0_ from t_dept dept0_ where dept0_.deptId=? Hibernate: update t_employee set dept_id=null where dept_id=? Hibernate: delete from t_dept where deptId=? */ } }
cascade属性
表示级联操作
none不级联操作 ,默认值
save-update级联保存或者更新
delete级联删除
save-update,delete 级联保存、更新、删除
all 同上
实例
package com.cx.test; import com.cx.entity.Dept; import com.cx.entity.Employee; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import org.junit.Test; /** * Created by cxspace on 16-8-2. */ public class Cascade { private static SessionFactory sf; static { sf = new Configuration() .configure() .addClass(Dept.class) .addClass(Employee.class) // 测试时候使用 .buildSessionFactory(); } //级联保存 @Test public void save(){ Session session = sf.openSession(); session.beginTransaction(); Dept dept = new Dept(); dept.setDeptName("人事部"); Employee emp_zs = new Employee(); emp_zs.setEmpName("张三"); Employee emp_ls = new Employee(); emp_ls.setEmpName("李四"); // 关系 dept.getEmployees().add(emp_zs); dept.getEmployees().add(emp_ls); //设置了级联只要保存部门 session.save(dept); session.getTransaction().commit(); session.close(); /* * * Hibernate: insert into t_dept (deptName) values (?) Hibernate: insert into t_employee (empName, salary, dept_id) values (?, ?, ?) Hibernate: insert into t_employee (empName, salary, dept_id) values (?, ?, ?) Hibernate: update t_employee set dept_id=? where empId=? Hibernate: update t_employee set dept_id=? where empId=? * */ } public void delete(){ Session session = sf.openSession(); session.beginTransaction(); Dept dept = (Dept) session.get(Dept.class,5); session.delete(dept); session.getTransaction().commit(); session.close(); /* * * Hibernate: select dept0_.deptId as deptId0_0_, dept0_.deptName as deptName0_0_ from t_dept dept0_ where dept0_.deptId=? Hibernate: select employees0_.dept_id as dept4_0_1_, employees0_.empId as empId1_, employees0_.empId as empId1_0_, employees0_.empName as empName1_0_, employees0_.salary as salary1_0_, employees0_.dept_id as dept4_1_0_ from t_employee employees0_ where employees0_.dept_id=? Hibernate: update t_employee set dept_id=null where dept_id=? Hibernate: delete from t_employee where empId=? Hibernate: delete from t_employee where empId=? Hibernate: delete from t_dept where deptId=? * * */ } }