1.一对一(会用即可)
主表:没有外键 有主键
从表:拥有外键的是从表
先操作从表,再去操作主表
one-to-one ,many-to-one 只是表达多个表之间的关系。
外键:目的是多表连接
主键:目的是唯一标识数据
1.1 方式一: 按照主键映射 (主键都是一样的)
用已有的主键充当外键去连接表来表示关系
方式二:按照外键映射
给表额外插入一个列作为外键去连接另一个表
2、一对多|多对一(最常见的,重点掌握)
示例
2.1 持久化类
package com.qf.domain; //从表(拥有外键。) public class Contact { private Integer contact_id; //主键 private String contact_name; private Integer contact_cust_id;//外键(表达关系的时候声明外键即可) private String contact_gender; private String contact_phone; private String contact_mobile; private String contact_email; private String contact_qq; private String contact_position; private String contact_memo;//备注 //表达多(Contact)对一(Customer)关系 private Customer customer; set/get..... }
package com.qf.domain; //主表 public class Customer { private Integer cust_id;//主键 private String cust_name; private Integer cust_user_id; private Integer cust_create_id; private String cust_source; private String cust_industry; private String cust_level; private String cust_linkman; private String cust_phone; private String cust_mobile; //表达一(Customer)对多(Contact)的关系 private Set<Contact> contacts =new HashSet<>(); set/get..... }
映射文件 Contact.hbm.xml <?xml version="1.0" encoding="UTF-8"?> <!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.qf.domain"> <class name="Contact" table="contact"> <id name="contact_id"> <generator class="native"></generator> </id> <property name="contact_name" ></property> <property name="contact_gender" ></property> <property name="contact_phone" ></property> <property name="contact_mobile" ></property> <property name="contact_email" ></property> <property name="contact_qq" ></property> <property name="contact_position" ></property> <property name="contact_memo" ></property> <!-- 表达多对一关系 column:声明外键--> <many-to-one name="customer" column="contact_cust_id"></many-to-one> </class> </hibernate-mapping> Customer.hbm.xml <?xml version="1.0" encoding="UTF-8"?> <!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.qf.domain"> <class name="Customer" table="customer"> <id name="cust_id" column="cust_id"> <generator class="native"></generator> </id> <property name="cust_name" column="cust_name"></property> <property name="cust_user_id" column="cust_user_id"></property> <property name="cust_create_id" column="cust_create_id"></property> <property name="cust_source" column="cust_source"></property> <property name="cust_industry" column="cust_industry"></property> <property name="cust_level" column="cust_level"></property> <property name="cust_linkman" column="cust_linkman"></property> <property name="cust_phone" column="cust_phone"></property> <property name="cust_mobile" column="cust_mobile"></property> <!-- 表达一对多的关系 --> <set name="contacts"> <!-- column外键:说明哪一个外键要连接当前的表 --> <key column="contact_cust_id"></key> <!-- 表达关系 --> <one-to-many class="Contact"/> </set> </class> </hibernate-mapping>
2.3 主配置文件 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <!-- 4(数据库信息)+1(数据库方言)+2(生成sql格式化并打印)+1(数据库表生成策略)+1(加载映射文件)+ 1(事务隔离级别)+1(配置current_session_context) --> <hibernate-configuration> <session-factory> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/1715_hibernate05</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">123456</property> <!-- JBoss Tools 提示工具 --> <property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property> <property name="hibernate.show_sql">true</property> <property name="hibernate.format_sql">true</property> <property name="hibernate.hbm2ddl.auto">update</property> <!-- 隔离级别 --> <property name="hibernate.connection.isolation">4</property> <!-- 目的:要使用getCurrentSession()获取当前线程绑定的Session,必须要做如下配置:--> <property name="hibernate.current_session_context_class">thread</property> <mapping resource="com/qf/domain/Customer.hbm.xml"/> <mapping resource="com/qf/domain/Contact.hbm.xml"/> </session-factory> </hibernate-configuration>
多对多: 示例1:多个学生可以被多个老师教,多个老师可以教多个 学生; 示例2:多个用户可以有多个角色,多个角色可以有多个用户。 例如:马云既是老板又是演员。李彦宏既是企业家又是老板。 1.User.java public class User { private Integer user_id; private String user_name; private String user_pwd; private String user_state;//用户状态 //表达User和Role的多对多的关系 private Set<Role> roles =new HashSet<>(); set/get....... } 2.Role.java public class Role { private Integer role_id;//角色编号 private String role_name;//角色名 private String role_memo;//角色备注 //表达Role和User的多对多的关系 private Set<User> users =new HashSet<>(); set/get....... } 3.User.hbm.xml <?xml version="1.0" encoding="UTF-8"?> <!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.qf.domain"> <class name="User" table="user"> <id name="user_id"> <generator class="native"></generator> </id> <property name="user_name"></property> <property name="user_pwd"></property> <property name="user_state"></property> <!-- 表达多对多的关系 table:表示中间表的名称 inverse:true 不维护关系(放弃维护关系) false:默认false,维护关系 --> <set name="roles" table="user_role" inverse="true" > <!-- 引用已经存在的键连接当前表User--> <key column="user_id1"></key> <!-- class:与当前表要建立关系的实体类名称 column:声明外键.表示在中间表中生成一个新的列。 作为外键去连接与当前表要建立关系的表 --> <many-to-many class="Role" column="role_id1"></many-to-many> </set> </class> </hibernate-mapping> 4.Role.hbm.xml <?xml version="1.0" encoding="UTF-8"?> <!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.qf.domain"> <class name="Role" table="role"> <id name="role_id"> <generator class="native"></generator> </id> <property name="role_name"></property> <property name="role_memo"></property> <!-- 表达多对多的关系 table:表示中间表的名称 --> <set name="users" table="user_role" > <!-- 引用已经存在的键连接当前表Role--> <key column="role_id1"></key> <!-- class:与当前表要建立关系的实体类名称 column:声明外键.表示在中间表中生成一个新的列。 作为外键去连接与当前表要建立关系的表 --> <many-to-many class="User" column="user_id1"></many-to-many> </set> </class> </hibernate-mapping> 5.hibernate.cfg.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <!-- 4(数据库信息)+1(数据库方言)+2(生成sql格式化并打印)+1(数据库表生成策略)+1(加载映射文件)+ 1(事务隔离级别)+1(配置current_session_context) --> <hibernate-configuration> <session-factory> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/1715_hibernate06</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">123456</property> <!-- JBoss Tools 提示工具 --> <property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property> <property name="hibernate.show_sql">true</property> <property name="hibernate.format_sql">true</property> <property name="hibernate.hbm2ddl.auto">update</property> <!-- 隔离级别 --> <property name="hibernate.connection.isolation">4</property> <!-- 目的:要使用getCurrentSession()获取当前线程绑定的Session,必须要做如下配置:--> <property name="hibernate.current_session_context_class">thread</property> <mapping resource="com/qf/domain/User.hbm.xml"/> <mapping resource="com/qf/domain/Role.hbm.xml"/> </session-factory> </hibernate-configuration> 6.测试 //插入 @Test public void test01() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); try { User user1 =new User(); user1.setUser_name("马云11111"); User user2 =new User(); user2.setUser_name("李彦宏1111"); Role role1 =new Role(); role1.setRole_name("企业家11111"); Role role2 =new Role(); role2.setRole_name("演员11111"); //表达多对多的关系 //从user角度出发表达关系 user1.getRoles().add(role1); user1.getRoles().add(role2); user2.getRoles().add(role1); user2.getRoles().add(role2); //从role角度出发表达关系 role1.getUsers().add(user1); role1.getUsers().add(user2); role2.getUsers().add(user1); role2.getUsers().add(user2); session.save(user1); session.save(user2); session.save(role1); session.save(role2); transaction.commit(); } catch (Exception e) { // TODO: handle exception if (transaction!=null) { transaction.rollback(); } } } 执行以上代码报错:约束异常。 解决方式一:去除掉一方关系表达维护,例如:删除掉30-34行代码 解决方式二:代码不用改变,在不需要维护关系的地方添加inverse="true"(谁放弃给谁加) 示例:User维护User和Role的关系。 Role放弃关系维护。 <set name="roles" table="user_role" inverse="true" > <!-- 引用已经存在的键连接当前表User--> <key column="user_id1"></key> <!-- class:与当前表要建立关系的实体类名称 column:声明外键.表示在中间表中生成一个新的列。 作为外键去连接与当前表要建立关系的表 --> <many-to-many class="Role" column="role_id1"></many-to-many> </set> 备注:inverse true:放弃维护关系 false:维护关系 ,默认 7.cascade级联操作(多表关系) /* cascade:级联操作 * save-update(重点): 级联更新 .持久化当前对象的同时要持久化与之相关联的对象。 * 示例:session.save(User) 含义:持久化User的同时在持久化与User关联的类Role 在以上案例中可以去除40行和41行 * delete: 级联删除 删除一个对象的同时会删除掉与之相关连的对象 (不建议使用,慎重使用) * all: save-update和delete结合一起 */ //删除用户(使用cascade="delete"会删除调用当前数据和与之关联的所有数据) @Test public void test02() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); try { //删除一个用户 User user = session.get(User.class, 3); session.delete(user);//删除user的同时删除了该user关联的role角色 transaction.commit(); } catch (Exception e) { // TODO: handle exception if (transaction!=null) { transaction.rollback(); } } } //给用户删除指定角色(不使用cascade="delete"删除) @Test public void test03() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); try { //一个用户 User user = session.get(User.class, 5); //给该用户删除一个角色 Role role= session.get(Role.class, 6); //从用户移除角色 user.getRoles().remove(role);//内连接查询 session.delete(role); transaction.commit(); } catch (Exception e) { // TODO: handle exception if (transaction!=null) { transaction.rollback(); } } }