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

JPA学习(六) 单向多对一

程序员文章站 2022-04-24 10:30:22
...

记录 单向多对一

目录

1.单向多对一

1.多方的代码

2.一方代码

3.测试类

4.运行结果

2.注意点

 


1.单向多对一

单向多对一 (many to one) (一方拿不了多方 但是多方可以拿一方)

比如:产品对应产品类型(其实就是可以理解为创建外键 处理外键的值)
@ManyToOne //多对一  多个产品对应一个产品类型 所以这个是配置在多方的对象上的  默认配置@ManyToOne  h会自动建立外键, 外键id名称=属性名_id
不能使用@clumn (name=...) 来配置外键名称 得使用 @JoinColumn(name = "dir_id") //用这个注解来配置

1.多方的代码

@Entity //产品 多方

@Table(name = "t_goods")
public class Goods {


    @Id
    @GeneratedValue
    private Long id;
    private String goodsName;

    //一方的对象
//    @ManyToOne   //d多对一  多个产品对应一个产品类型  默认配置@ManyToOne  h会自动建立外键, 外键id名称=属性名_id
    @ManyToOne(fetch = FetchType.LAZY)  //延迟加载
    //默认立即加载
    //不能使用@clumn (name=...) 来配置外键名称
    @JoinColumn(name = "type_id") //用这个注解来配置外键 让他生成可以查询到一方主键的外键
    private GoodsType goodsType;  //这里不能默认new一个  否则会报错


    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getGoodsName() {
        return goodsName;
    }

    public void setGoodsName(String goodsName) {
        this.goodsName = goodsName;
    }

    public GoodsType getGoodsType() {
        return goodsType;
    }

    public void setGoodsType(GoodsType goodsType) {
        this.goodsType = goodsType;
    }

    @Override
    public String toString() {
        return "Goods{" +
                "id=" + id +
                ", goodsName='" + goodsName + '\'' +
                '}';
    }
}

注意 使用了一个延迟加载 提升效率 (后面稍微稍微说一下)

2.一方代码

@Entity //产品订单 一方
public class GoodsType {

    @Id
    @GeneratedValue
    private Long tid;

    private String tname;


    @Override
    public String toString() {
        return "GoodsType{" +
                "tid=" + tid +
                ", tname='" + tname + '\'' +
                '}';
    }

    public Long getTid() {
        return tid;
    }

    public void setTid(Long tid) {
        this.tid = tid;
    }

    public String getTname() {
        return tname;
    }

    public void setTname(String tname) {
        this.tname = tname;
    }
}

 

3.测试类

public class MtoOTest {


    @Before
    //实例化多方 和 一方的正确示范
    public void mtoTest() {
        EntityManager entityManager = JPAUtil.getEntityManager();
        entityManager.getTransaction().begin();
        //多方
        Goods goods1 = new Goods();
        goods1.setGoodsName("apple");

        Goods goods2 = new Goods();
        goods2.setGoodsName("banana FAQ");


        //一方
        GoodsType goodsType = new GoodsType();
        goodsType.setTname("fruit");

        //建立多方到一方的关系 本质就是处理外键的值
        // goods1.getGoodsType.setTypeId(goodsType.getId);
        goods1.setGoodsType(goodsType);
        goods2.setGoodsType(goodsType);

        //正确顺序: 先保存一方 再 保存多方
        entityManager.persist(goodsType); //当goodstype 持久化后 存入到表里面 然后将goods的外键进行了更新
        //提交
        entityManager.persist(goods1);
        entityManager.persist(goods2);

        entityManager.getTransaction().commit();
        entityManager.close();
    }

    @Test  //获取多方的数据
    public void getOneTest() {
        EntityManager entityManager = JPAUtil.getEntityManager();
        Goods goods = entityManager.find(Goods.class, 1L);
        System.out.println(goods.toString());
        System.out.println(goods.getGoodsType()); //获取关联对象 懒加载这里才会发数据
        /*  fetch 抓取策略  立即加载策略
        *     select
        goods0_.id as id1_5_0_,
        goods0_.goodsName as goodsNam2_5_0_,
        goods0_.goodsType_tid as goodsTyp3_5_0_,
        goodstype1_.tid as tid1_0_1_,
        goodstype1_.tname as tname2_0_1_
    from
        t_goods goods0_
    left outer join
        GoodsType goodstype1_
            on goods0_.goodsType_tid=goodstype1_.tid
    where
        goods0_.id=?
Goods{id=1, goodsName='apple'goodsType=fruit\'}
        *   多方 左外连接 一方 获得数据
        * */


        /*  fetch 抓取策略  延迟加载      @ManyToOne(fetch = FetchType.LAZY)  //延迟加载
      Hibernate:
    select
        goods0_.id as id1_5_0_,
        goods0_.goodsName as goodsNam2_5_0_,
        goods0_.goodsType_tid as goodsTyp3_5_0_
    from
        t_goods goods0_
    where
        goods0_.id=?
Goods{id=1, goodsName='apple'}
Hibernate:
    select
        goodstype0_.tid as tid1_0_0_,
        goodstype0_.tname as tname2_0_0_
    from
        GoodsType goodstype0_
    where
        goodstype0_.tid=?
GoodsType{tid=1, tname='fruit'}
*/
    }

4.运行结果

执行的是 getOneTest() Test方法

可以看到 第一步在创建entityManager的时候会初始化表:

JPA学习(六) 单向多对一

JPA学习(六) 单向多对一

表对应的建表语句:

goodtype(一方):

CREATE TABLE `goodstype` (
  `tid` bigint(20) NOT NULL AUTO_INCREMENT,
  `tname` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`tid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

good(多方): 可以看到有添加外键 并将typeid和 外键的tid进行绑定

CREATE TABLE `t_goods` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `goodsName` varchar(255) DEFAULT NULL,
  `type_id` bigint(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `FK_iq8i1e6oxrmldi7ac5jx0v2sx` (`type_id`),
  CONSTRAINT `FK_iq8i1e6oxrmldi7ac5jx0v2sx` FOREIGN KEY (`type_id`) REFERENCES `goodstype` (`tid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

代码往下走 看得到添加数据:(先添加一方,再添加多方)

JPA学习(六) 单向多对一

到提交事务之前,做了如下数据库操作:可以看到 将一方的数据保存了 ,再保存了 多方的数据

Hibernate: insert into GoodsType (tname) values (?)

Hibernate: insert into t_goods (goodsName, type_id) values (?, ?)

Hibernate: insert into t_goods (goodsName, type_id) values (?, ?)

但是数据库还没有

JPA学习(六) 单向多对一JPA学习(六) 单向多对一

事务提交后:

JPA学习(六) 单向多对一JPA学习(六) 单向多对一

这里只执行了三行sql,(在单向一对多的时候实现相同效果需要五条sql  每次插入多方数据会update一次)

 

然后到查询数据

JPA学习(六) 单向多对一

当查询完打印goods时,

执行的语句是:

Hibernate: 
    select
        goods0_.id as id1_5_0_,
        goods0_.goodsName as goodsNam2_5_0_,
        goods0_.type_id as type_id3_5_0_ 
    from
        t_goods goods0_ 
    where
        goods0_.id=?

没有去专门去取对应的产品类型。

再往下走 获取 getType,这个时候才出现了新的查询语句,查询对应的goodsType,

Hibernate: 
    select
        goodstype0_.tid as tid1_0_0_,
        goodstype0_.tname as tname2_0_0_ 
    from
        GoodsType goodstype0_ 
    where
        goodstype0_.tid=?

原因是在配置了懒加载,就是在多方属性配置@ManyToOne(fetch = FetchType.LAZY)。

如果我把懒加载去掉,可以看到执行的语句是一次性执行完毕的

 select
        goods0_.id as id1_5_0_,
        goods0_.goodsName as goodsNam2_5_0_,
        goods0_.goodsType_tid as goodsTyp3_5_0_,
        goodstype1_.tid as tid1_0_1_,
        goodstype1_.tname as tname2_0_1_
    from
        t_goods goods0_
    left outer join
        GoodsType goodstype1_  on goods0_.goodsType_tid=goodstype1_.tid 
    where  
        goods0_.id=?

这样耗内存,所以一般都不这么使用。

 

2.注意点

 

错误保存
多方对象的关联一方的对象 不要默认实例化

JPA学习(六) 单向多对一

因为实例化后没有id和外键 否则报错 TransientPropertyValueException

正确保存

一次性保存一方 同时保存2个多方 比如:保存一个产品类型 ,两个产品
先保存一方 也就是外键的对应的表的数据先存入 后存入 多方的数据 也就是拥有外键的数据存入
(和数据库的数据存入顺序一致)

JPA学习(六) 单向多对一

fetch 抓取 (ManyToOneTest)
1.默认立即加载
@ManyToOne
2.延迟加载
@ManyToOne(fetch = FetchType.LAZY)  //延迟加载


获取持久状态对象后 还需要获取关联对象(比如getGoodsType()),此时才会发出真正的sql 获取值
好处:

提高性能,但是如果把entityManager提前关闭 会出现延迟加载 初始化异常 LazyInitzationException :  no session
看测试代码中的 他的立即加载 是会用左外连接将数据全部查询出来
而懒加载是你要查询什么就查询什么 不需要的就不会一次性查出来 这样提高效率

可以通过多方.get一方是否为null 来判断是否有外键的关联

[email protected](name = "type_id")

用这个注解来配置外键 让他生成可以查询到一方主键的外键

 

 

 

上一篇: java nio

下一篇: java nio 示例代码