zoukankan      html  css  js  c++  java
  • Hibernate一对多操作

    --------------------siwuxie095

       

       

       

       

       

       

       

       

    Hibernate 一对多操作

       

       

    以客户和联系人为例,客户是一,联系人是多

       

    一个客户里面有多个联系人,一个联系人只能属于一个客户

       

    注意:这里的客户是公司级的,即 公司,联系人 公司里的员工

       

       

       

       

    (一)一对多映射配置

       

       

    第一步:创建两个实体类,客户和联系人

       

       

       

       

    第二步:让两个实体类之间互相表示

       

    1)在客户实体类中表示多个联系人

       

       

       

    2)在联系人实体类中表示所属客户

       

       

       

       

       

    第三步:配置映射关系

       

    「一般一个实体类对应一个映射配置文件」

       

    1)配置基本的映射

       

       

    2)配置关联关系的映射(一对多关系

       

    1)在客户的映射配置文件中,表示所有联系人

       

       

       

    2)在联系人的映射配置文件中,表示所属客户

       

       

       

       

       

    第四步:在核心配置文件中引入映射配置文件

       

       

       

       

       

       

       

       

    (二)一对多级联保存

       

    如:添加客户,为这个客户添加一个联系人

       

    1)复杂写法

       

    /**

    * 一对多级联保存的复杂写法

    *

    *

    * 手动加上 @Test 以进行单元测试(将自动导入 JUnit 4 jar 包)

    *

    * 选中方法名,右键->Run As->JUint Test

    */

    @Test

    public void testSave(){

    SessionFactory sessionFactory=null;

    Session session=null;

    Transaction tx=null;

    try {

    //得到 SessionFactory 对象

    sessionFactory=HibernateUtils.getSessionFactory();

    //创建 Session 对象

    session=sessionFactory.openSession();

    //开启事务

    tx=session.beginTransaction();

    //添加一个客户,为这个客户添加一个联系人

    //(1)

    //创建客户和联系人对象

    Customer customer=new Customer();

    customer.setCustName("百度");

    customer.setCustLevel("VIP");

    customer.setCustSource("网络");

    customer.setCustPhone("110");

    customer.setCustMobile("114");

    LinkMan linkMan=new LinkMan();

    linkMan.setLkmName("小明");

    linkMan.setLkmGender("");

    linkMan.setLkmPhone("111");

    //(2)

    //建立客户对象和联系人对象的关系

    //

    //在客户实体类中表示联系人,在联系人实体类中表示客户

    //

    //具体:

    //把联系人对象放到客户对象的 Set 集合中

    //把客户对象放到联系人对象中

    customer.getLinkManSet().add(linkMan);

    linkMan.setCustomer(customer);

    //(3)

    //保存到数据库(级联保存)

    session.save(customer);

    session.save(linkMan);

    //提交事务

    tx.commit();

    } catch (Exception e) {

    //回滚事务

    tx.rollback();

    } finally {

    //关闭资源

    session.close();

    sessionFactory.close();

    }

    }

       

       

       

    2)简化写法

       

    先在客户的映射配置文件中的 set 标签添加 cascade 属性,并

    将其值设置为 save-update,再进行具体实现

       

       

    /**

    * 一对多级联保存的简化写法

    *

    * 在客户的映射配置文件中的set 标签

    * 添加 cascade 属性,并将其值设置为

    * save-update

    */

    @Test

    public void testSaveX(){

    SessionFactory sessionFactory=null;

    Session session=null;

    Transaction tx=null;

    try {

    //得到 SessionFactory 对象

    sessionFactory=HibernateUtils.getSessionFactory();

    //创建 Session 对象

    session=sessionFactory.openSession();

    //开启事务

    tx=session.beginTransaction();

    //添加一个客户,为这个客户添加一个联系人

    //(1)

    //创建客户和联系人对象

    Customer customer=new Customer();

    customer.setCustName("谷歌");

    customer.setCustLevel("普通");

    customer.setCustSource("网络");

    customer.setCustPhone("911");

    customer.setCustMobile("995");

    LinkMan linkMan=new LinkMan();

    linkMan.setLkmName("小强");

    linkMan.setLkmGender("");

    linkMan.setLkmPhone("999");

    //(2)

    //建立客户对象和联系人对象的关系

    //

    //在客户实体类中表示联系人

    //

    //具体:

    //把联系人对象放到客户对象的 Set 集合中

    customer.getLinkManSet().add(linkMan);

    //(3)

    //保存到数据库(级联保存)

    session.save(customer);

    //简化所在:不用把客户对象放到联系人对象

    //中,且最后不用保存联系人对象

    //提交事务

    tx.commit();

    } catch (Exception e) {

    //回滚事务

    tx.rollback();

    } finally {

    //关闭资源

    session.close();

    sessionFactory.close();

    }

    }

       

       

       

       

       

       

       

    (三)一对多级联删除

       

    如:删除某个客户,把客户里面的所有联系人都删除

       

    1)具体写法

       

    先在客户的映射配置文件中的 set 标签添加 cascade 属性,并

    将其值设置为 delete,再进行具体实现

       

       

    /**

    * 一对多级联删除

    *

    * 在客户的映射配置文件中的 set 标签

    * 添加 cascade 属性,并将其值设置为

    * delete

    */

    @Test

    public void testDelete(){

    SessionFactory sessionFactory=null;

    Session session=null;

    Transaction tx=null;

    try {

    //得到 SessionFactory 对象

    sessionFactory=HibernateUtils.getSessionFactory();

    //创建 Session 对象

    session=sessionFactory.openSession();

    //开启事务

    tx=session.beginTransaction();

    //除一个客户,并将这个客户中的所有联系人删除

    //(1)

    //根据 id 查询客户对象

    Customer customer=session.get(Customer.class, 1);

    //(2)

    //调用 Session delete() 方法实现级联删除

    session.delete(customer);

    //提交事务

    tx.commit();

    } catch (Exception e) {

    //回滚事务

    tx.rollback();

    } finally {

    //关闭资源

    session.close();

    sessionFactory.close();

    }

    }

       

       

       

    2)执行过程

       

    1)根据 id 查询客户

       

    2)根据外键 id 值查询联系人

       

    3)把联系人外键设置为 null

       

    4)删除联系人和客户

       

       

       

       

       

       

    (四)一对多修改

       

    如:让某联系人不再属于原客户,而属于新客户

       

    (1)主要问题

       

    因为 Hibernate 双向维护外键,即 在客户和联系人中都要配置外键

       

    所以在修改客户时会修改一次外键,修改联系人时也会修改一次外键,

    也就是说产生了多余的 sql 语句,使得效率低下

       

       

       

    (2)解决方式

       

    修改中,让其中一方放弃外键维护,一般是让的一方放弃

       

       

       

    (3)具体写法

       

    先在客户的映射配置文件中的 set 标签添加 inverse 属性,并

    将其值设置为 true,再进行具体实现

       

       

    /**

    * 一对多修改

    *

    * 在客户的映射配置文件中的 set 标签

    * 添加 inverse 属性,并将其值设置为

    * true

    */

    @Test

    public void testUpdate(){

    SessionFactory sessionFactory=null;

    Session session=null;

    Transaction tx=null;

    try {

    //得到 SessionFactory 对象

    sessionFactory=HibernateUtils.getSessionFactory();

    //创建 Session 对象

    session=sessionFactory.openSession();

    //开启事务

    tx=session.beginTransaction();

    //在百度工作的小明跳槽到谷歌,修改联系人表中对应的外键

    //(1)

    //根据 id 分别查询客户(谷歌)和联系人(小明)

    Customer customer=session.get(Customer.class, 2);

    LinkMan linkMan=session.get(LinkMan.class, 1);

    //(2)

    //设置持久态对象的值:

    //1)把联系人对象放到客户对象的 Set 集合中

    //2)把客户对象放到联系人对象中

    customer.getLinkManSet().add(linkMan);

    linkMan.setCustomer(customer);

    //持久态对象可以自动更新数据库,所以下面的代码不用写

    //session.update(customer);

    //session.update(linkMan);

    //提交事务

    tx.commit();

    } catch (Exception e) {

    //回滚事务

    tx.rollback();

    } finally {

    //关闭资源

    session.close();

    sessionFactory.close();

    }

    }

       

       

       

       

       

       

       

    工程结构目录如下:

       

       

       

       

    HibernateUtils.java:

       

    package com.siwuxie095.utils;

       

    import org.hibernate.Session;

    import org.hibernate.SessionFactory;

    import org.hibernate.cfg.Configuration;

       

    public class HibernateUtils {

    static Configuration cfg=null;

    static SessionFactory sessionFactory=null;

    //或:加上 private final 亦可,不过此时不能等于 null

    // private static final Configuration cfg;

    // private static final SessionFactory sessionFactory;

    //静态代码块

    static {

    //加载核心配置文件

    cfg=new Configuration();

    cfg.configure();

    sessionFactory=cfg.buildSessionFactory();

    }

    //提供方法返回 sessionFactory

    public static SessionFactory getSessionFactory() {

    return sessionFactory;

    }

    //提供方法返回与本地线程绑定的 Session

    public static Session getCurrentSession() {

    return sessionFactory.getCurrentSession();

    }

    }

       

       

       

    Customer.java:

       

    package com.siwuxie095.entity;

       

    import java.util.HashSet;

    import java.util.Set;

       

    //客户实体类(客户是公司级的)

    public class Customer {

    private Integer cid; //客户 id

    private String custName; //客户名称

    private String custLevel; //客户级别

    private String custSource; //客户来源

    private String custPhone; //客户电话

    private String custMobile; //客户手机

    //在客户实体类中表示多个联系人,即一个客户里面有多个联系人

    //

    //Hibernate 中要求使用 Set 集合表示"多"的数据

    private Set<LinkMan> linkManSet=new HashSet<LinkMan>();

    public Set<LinkMan> getLinkManSet() {

    return linkManSet;

    }

    public void setLinkManSet(Set<LinkMan> linkManSet) {

    this.linkManSet = linkManSet;

    }

    public Integer getCid() {

    return cid;

    }

    public void setCid(Integer cid) {

    this.cid = cid;

    }

    public String getCustName() {

    return custName;

    }

    public void setCustName(String custName) {

    this.custName = custName;

    }

    public String getCustLevel() {

    return custLevel;

    }

    public void setCustLevel(String custLevel) {

    this.custLevel = custLevel;

    }

    public String getCustSource() {

    return custSource;

    }

    public void setCustSource(String custSource) {

    this.custSource = custSource;

    }

    public String getCustPhone() {

    return custPhone;

    }

    public void setCustPhone(String custPhone) {

    this.custPhone = custPhone;

    }

    public String getCustMobile() {

    return custMobile;

    }

    public void setCustMobile(String custMobile) {

    this.custMobile = custMobile;

    }

    }

       

       

       

    LinkMan.java:

       

    package com.siwuxie095.entity;

       

       

    //联系人实体类

    public class LinkMan {

       

    private Integer lid; // 联系人 id

    private String lkmName; // 联系人姓名

    private String lkmGender; // 联系人性别

    private String lkmPhone; // 联系人电话

    //在联系人实体类中表示所属客户,即一个联系人只能属于一个客户

    private Customer customer;

    public Customer getCustomer() {

    return customer;

    }

    public void setCustomer(Customer customer) {

    this.customer = customer;

    }

    public Integer getLid() {

    return lid;

    }

    public void setLid(Integer lid) {

    this.lid = lid;

    }

    public String getLkmName() {

    return lkmName;

    }

    public void setLkmName(String lkmName) {

    this.lkmName = lkmName;

    }

    public String getLkmGender() {

    return lkmGender;

    }

    public void setLkmGender(String lkmGender) {

    this.lkmGender = lkmGender;

    }

    public String getLkmPhone() {

    return lkmPhone;

    }

    public void setLkmPhone(String lkmPhone) {

    this.lkmPhone = lkmPhone;

    }

    }

       

       

       

    HibernateOneToMany.java:

       

    package com.siwuxie095.hibernatetest;

       

    import org.hibernate.Session;

    import org.hibernate.SessionFactory;

    import org.hibernate.Transaction;

    import org.junit.Test;

       

    import com.siwuxie095.entity.Customer;

    import com.siwuxie095.entity.LinkMan;

    import com.siwuxie095.utils.HibernateUtils;

       

       

    //一对多操作

    public class HibernateOneToMany {

    /**

    * 一对多级联保存的复杂写法

    *

    *

    * 手动加上 @Test 以进行单元测试(将自动导入 JUnit 4 jar 包)

    *

    * 选中方法名,右键->Run As->JUint Test

    */

    @Test

    public void testSave(){

    SessionFactory sessionFactory=null;

    Session session=null;

    Transaction tx=null;

    try {

    //得到 SessionFactory 对象

    sessionFactory=HibernateUtils.getSessionFactory();

    //创建 Session 对象

    session=sessionFactory.openSession();

    //开启事务

    tx=session.beginTransaction();

    //添加一个客户,为这个客户添加一个联系人

    //(1)

    //创建客户和联系人对象

    Customer customer=new Customer();

    customer.setCustName("百度");

    customer.setCustLevel("VIP");

    customer.setCustSource("网络");

    customer.setCustPhone("110");

    customer.setCustMobile("114");

    LinkMan linkMan=new LinkMan();

    linkMan.setLkmName("小明");

    linkMan.setLkmGender("");

    linkMan.setLkmPhone("111");

    //(2)

    //建立客户对象和联系人对象的关系

    //

    //在客户实体类中表示联系人,在联系人实体类中表示客户

    //

    //具体:

    //把联系人对象放到客户对象的 Set 集合中

    //把客户对象放到联系人对象中

    customer.getLinkManSet().add(linkMan);

    linkMan.setCustomer(customer);

    //(3)

    //保存到数据库(级联保存)

    session.save(customer);

    session.save(linkMan);

    //提交事务

    tx.commit();

    } catch (Exception e) {

    //回滚事务

    tx.rollback();

    } finally {

    //关闭资源

    session.close();

    sessionFactory.close();

    }

    }

    /**

    * 一对多级联保存的简化写法

    *

    * 在客户的映射配置文件中的 set 标签

    * 添加 cascade 属性,并将其值设置为

    * save-update

    */

    @Test

    public void testSaveX(){

    SessionFactory sessionFactory=null;

    Session session=null;

    Transaction tx=null;

    try {

    //得到 SessionFactory 对象

    sessionFactory=HibernateUtils.getSessionFactory();

    //创建 Session 对象

    session=sessionFactory.openSession();

    //开启事务

    tx=session.beginTransaction();

    //添加一个客户,为这个客户添加一个联系人

    //(1)

    //创建客户和联系人对象

    Customer customer=new Customer();

    customer.setCustName("谷歌");

    customer.setCustLevel("普通");

    customer.setCustSource("网络");

    customer.setCustPhone("911");

    customer.setCustMobile("995");

    LinkMan linkMan=new LinkMan();

    linkMan.setLkmName("小强");

    linkMan.setLkmGender("");

    linkMan.setLkmPhone("999");

    //(2)

    //建立客户对象和联系人对象的关系

    //

    //在客户实体类中表示联系人

    //

    //具体:

    //把联系人对象放到客户对象的 Set 集合中

    customer.getLinkManSet().add(linkMan);

    //(3)

    //保存到数据库(级联保存)

    session.save(customer);

    //简化所在:不用把客户对象放到联系人对象

    //中,且最后不用保存联系人对象

    //提交事务

    tx.commit();

    } catch (Exception e) {

    //回滚事务

    tx.rollback();

    } finally {

    //关闭资源

    session.close();

    sessionFactory.close();

    }

    }

    /**

    * 一对多级联删除

    *

    * 在客户的映射配置文件中的 set 标签

    * 添加 cascade 属性,并将其值设置为

    * delete

    */

    @Test

    public void testDelete(){

    SessionFactory sessionFactory=null;

    Session session=null;

    Transaction tx=null;

    try {

    //得到 SessionFactory 对象

    sessionFactory=HibernateUtils.getSessionFactory();

    //创建 Session 对象

    session=sessionFactory.openSession();

    //开启事务

    tx=session.beginTransaction();

    //删除一个客户,并将这个客户中的所有联系人删除

    //(1)

    //根据 id 查询客户对象

    Customer customer=session.get(Customer.class, 1);

    //(2)

    //调用 Session delete() 方法实现级联删除

    session.delete(customer);

    //提交事务

    tx.commit();

    } catch (Exception e) {

    //回滚事务

    tx.rollback();

    } finally {

    //关闭资源

    session.close();

    sessionFactory.close();

    }

    }

    /**

    * 一对多修改

    *

    * 在客户的映射配置文件中的 set 标签

    * 添加 inverse 属性,并将其值设置为

    * true

    */

    @Test

    public void testUpdate(){

    SessionFactory sessionFactory=null;

    Session session=null;

    Transaction tx=null;

    try {

    //得到 SessionFactory 对象

    sessionFactory=HibernateUtils.getSessionFactory();

    //创建 Session 对象

    session=sessionFactory.openSession();

    //开启事务

    tx=session.beginTransaction();

    //在百度工作的小明跳槽到谷歌,修改联系人表中对应的外键

    //(1)

    //根据 id 分别查询客户(谷歌)和联系人(小明)

    Customer customer=session.get(Customer.class, 2);

    LinkMan linkMan=session.get(LinkMan.class, 1);

    //(2)

    //设置持久态对象的值:

    //1)把联系人对象放到客户对象的 Set 集合中

    //2)把客户对象放到联系人对象中

    customer.getLinkManSet().add(linkMan);

    linkMan.setCustomer(customer);

    //持久态对象可以自动更新数据库,所以下面的代码不用写

    //session.update(customer);

    //session.update(linkMan);

    //提交事务

    tx.commit();

    } catch (Exception e) {

    //回滚事务

    tx.rollback();

    } finally {

    //关闭资源

    session.close();

    sessionFactory.close();

    }

    }

    }

       

       

       

    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>

       

    <!--

    (1)

    class 标签:配置实体类和数据库表的对应;

    name 属性:实体类的全路径,即全限定名;

    table 属性:数据库表的名称(数据库表由 Hibernate 自动生成)

    -->

    <class name="com.siwuxie095.entity.Customer" table="t_customer">

    <!--

    (2)

    id 标签:配置实体类 id 和表 id 对应(主键);

    name 属性:实体类里 id 属性名称;

    column 属性:生成表中 id 字段名称

    -->

    <id name="cid" column="cid">

    <!-- native:设置主键 id 自动增长 -->

    <generator class="native"></generator>

    </id>

    <!--

    (3)

    property 标签:配置其它属性和表中字段对应;

    name 属性:实体类属性名称;

    column 属性:生成表中字段名称

    -->

    <property name="custName" column="cust_name"></property>

    <property name="custLevel" column="cust_level"></property>

    <property name="custSource" column="cust_source"></property>

    <property name="custPhone" column="cust_phone"></property>

    <property name="custMobile" column="cust_mobile"></property>

    <!--

    (4)

    set 标签:配置关联关系的映射(配置关联对象),代表一个 Set 集合;

    name 属性:"多"的一方的对象的 Set 集合的名称(在客户实体类中声明);

    cascade 属性:save-update 表示级联保存,delete 表示级联删除(逗号隔开);

    inverse 属性:true 表示放弃关系维护(放弃外键的维护权)(默认为 false

    注意:inverse="true" 主要用于修改操作,防止产生多余的 sql 语句,但如果

    同时配置了 cascade="save-update" inverse="true",将会导致在级联保存

    操作后,没有外键(为 null

    -->

    <set name="linkManSet" cascade="save-update,delete" inverse="true">

    <!--

    一对多建表,有外键。Hibernate 的机制

    是双向维护外键(即都配置外键)

    key 标签:配置"多"的一方的外键

    column 属性:"多"的一方的外键名称

    -->

    <key column="clid"></key>

    <!--

    one-to-many 标签:配置实体类的一对多关联

    class 属性:"多"的一方的类的全路径,即联系人实体类的全限定名

    -->

    <one-to-many class="com.siwuxie095.entity.LinkMan"/>

    </set>

    </class>

    </hibernate-mapping>

       

       

       

    LinkMan.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>

    <class name="com.siwuxie095.entity.LinkMan" table="t_linkman">

    <id name="lid" column="lid">

    <generator class="native"></generator>

    </id>

    <property name="lkmName" column="lkm_name"></property>

    <property name="lkmGender" column="lkm_gender"></property>

    <property name="lkmPhone" column="lkm_phone"></property>

    <!-- 配置关联关系的映射(配置关联对象) -->

    <!--

    many-to-one 标签:配置实体类的多对一关联;

    name 属性:"一"的一方的对象的名称(在联系人实体类中声明);

    class 属性:"一"的一方的类的全路径,即客户实体类的全限定名;

    column 属性:表中的外键名称

    -->

    <many-to-one name="customer" class="com.siwuxie095.entity.Customer" column="clid"></many-to-one>

    </class>

    </hibernate-mapping>

       

       

       

    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">

    <hibernate-configuration>

    <session-factory>

    <!-- 第一部分:配置数据库信息(必须) -->

    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>

    <!-- 或使用 jdbc:mysql:///hibernate_db 代替,省略 localhost:3306 -->

    <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate_db</property>

    <property name="hibernate.connection.username">root</property>

    <property name="hibernate.connection.password">8888</property>

    <!-- 第二部分:配置 Hibernate 信息(可选) -->

    <!-- 输出底层 sql 语句 -->

    <property name="hibernate.show_sql">true</property>

    <!-- 输出底层 sql 语句格式 -->

    <property name="hibernate.format_sql">true</property>

    <!--

    Hibernate 帮助创建表,不是自动创建,而需要配置之后。

    update:如果已经有表,就更新,如果没有,就自动创建

    -->

    <property name="hibernate.hbm2ddl.auto">update</property>

    <!--

    配置数据库方言,让 Hibernate 框架识别不同数据库自己特有的语句

    如:在 MySQL 中实现分页的关键字 limit,只能在 MySQL 中使用,而

    Oracle 中实现分页的关键字则是 rownum

    -->

    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

    <!-- 配置 Session 绑定本地线程 -->

    <property name="hibernate.current_session_context_class">thread</property>

    <!-- 第三部分:引入映射配置文件,把映射配置文件放到核心配置文件(必须) -->

    <mapping resource="com/siwuxie095/entity/Customer.hbm.xml"/>

    <mapping resource="com/siwuxie095/entity/LinkMan.hbm.xml"/>

    </session-factory>

    </hibernate-configuration>

       

       

       

       

       

       

       

       

       

    【made by siwuxie095】

  • 相关阅读:
    rabbitmq在ios中实战采坑
    网络七层架构一句话简述
    HystrixCommand实战
    前端SEO技巧
    前端面试-难点问题2-java和javascript的区别
    前端面试题--难点问题
    [微信营销企划之路]003.Access forbidden!
    [Python进阶]001.不定参数
    [安卓基础]011存储数据(中)——sqlite语法介绍
    [JavaWeb基础] 015.Struts2 表单验证框架
  • 原文地址:https://www.cnblogs.com/siwuxie095/p/7296533.html
Copyright © 2011-2022 走看看