解密DDD:高内聚对象组的维护之道( 五 )

每种策略保存一条数据后,各个表数据如下:
user_per_class_matcher 如下:

解密DDD:高内聚对象组的维护之道

文章插图
sex_per_class_matcher 如下:
解密DDD:高内聚对象组的维护之道

文章插图
vip_per_class_matcher 如下:
解密DDD:高内聚对象组的维护之道

文章插图
具有以下特点:
  1. 每个具体的子类对应一张表,表中存储父类和子类的数据;
  2. 为每个子类生成id,所生成的 id 不重复;
从表数据上可以看出,子类中有相同的属性,则每个子类都需要创建一遍,会导致表结构冗余,影响查询效率 。
3.2.4. 小节三种策略各具特色,都有最佳应用场景,简单如下:
  1. 单表策略 。
子类的数据量不大,且与父类的属性差别不大;
ß可以使用单表继承策略来减少表的数量;
  1. Joined 策略 。
  2. 子类的属性较多,且与父类的属性差别较大;
  3. 需要一个主表,用于对所有的子类进行管理;
  4. 每个实体一个表策略 。
  5. 子类的属性较多,且与父类的属性差别较大;
  6. 子类过于离散,无需统一管理;
当子类过多或数据量过大时,Joined 和 table per class 在查询场景存在明显的性能问题,这个需要格外注意 。
3.3. 立即加载&延迟加载JPA提供了两种加载策略:立即加载和延迟加载 。
  1. 一对一关联,默认获取策略是立即加载(EAGER),查询一个对象,会把它关联的对象都查出来初始化到属性中;
  2. 一对多关联,默认获取策略是懒加载(LAZY),即只有在使用到相关联数据时才会查询数据库;
如果默认策略不符合要求,可以通过手工设置注解上 fetch 配置,对默认策略进行重写 。
3.3.1. 立即加载
立即加载会在查询主实体类的同时查询它所有关联实体类,并绑定到实体属性上 。
立即加载的好处是能够提高查询效率,因为不需要额外的查询操作 。但是,使用立即加载会增加数据库的查询负担,查询出所有关联实体类,会导致查询结果的数据量比较大 。
实体配置如下:
@Entity@Table(name = "order_info")public class Order{@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)@JoinColumn(name = "order_id")private List<OrderItem> orderItems = new ArrayList<>();@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)private Pay pay;@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)private Address address;// 忽略其他属性和方法}测试脚本如下:
Order order = this.orderRepository.findById(this.order.getId()).get();Assertions.assertNotNull(order);System.out.println("访问 item");Assertions.assertEquals(3, order.getOrderItems().size());System.out.println("访问 address");Assertions.assertNotNull(order.getAddress().getDetail());System.out.println("访问 pay");Assertions.assertNotNull(order.getPay().getPrice());日志输出如下:
Hibernate: select order0_.id as id1_3_0_, order0_.address_id as address_6_3_0_, order0_.pay_id as pay_id7_3_0_, order0_.status as status2_3_0_, order0_.total_price as total_pr3_3_0_, order0_.total_selling_price as total_se4_3_0_, order0_.user_id as user_id5_3_0_, address1_.id as id1_2_1_, address1_.detail as detail2_2_1_, orderitems2_.order_id as order_id6_4_2_, orderitems2_.id as id1_4_2_, orderitems2_.id as id1_4_3_, orderitems2_.price as price2_4_3_, orderitems2_.product_id as product_3_4_3_, orderitems2_.quantity as quantity4_4_3_, orderitems2_.selling_price as selling_5_4_3_, pay3_.id as id1_5_4_, pay3_.price as price2_5_4_ from order_info order0_ left outer join address address1_ on order0_.address_id=address1_.id left outer join order_item orderitems2_ on order0_.id=orderitems2_.order_id left outer join pay_info pay3_ on order0_.pay_id=pay3_.id where order0_.id=?访问 item访问 address访问 pay从日志输出可见:
  1. JPA 使用多张表的join,通过一个复杂的 sql 一次性获取了所有数据;
  2. 在访问关联实体时,未触发任何加载操作;


    推荐阅读