Hibernate中OneToOne延时加载的问题-解决方案

    xiaoxiao2026-04-25  12

    在上一篇文章中我们已经解释了延迟加载的问题。那我们该如何解决? 我觉得该分两个方面来讨论。 如果这是一个新的项目,在发布之前我们有足够的时间来修改数据的映射和关联关系、以及已经存在的sql语句,或者我们可以更改客户的数据库,并且不存在复杂的数据关系,可以做数据更新。那么我们可以通过修改两端的关联关系来解决这个问题。 但如果这是一个老的项目,已经发布,并且客户那里有大量的数据,那么建议是通过增加一个新的entity,针对用户场景,只提取想要的相关数据。 再或者,使用hibernate提供的byteCode instructment用类增强器对二进制Class文件进行强化处理。 有位兄弟在博文里面已经做了比较详细的总结,虽然我没有全部试过,但还是推荐各位先看看http://blog.csdn.net/wangpeng047/article/details/19624795。这样我也懒得写步骤。 其中我试了上文提到的第一种方法,双外键关联。这可以实现延迟加载,但是其缺点也比较明显。

    两张表里都增加了一个外键字段,增加了存储空间。在存储的时候消耗了额外的Join语句。 非双外键的insert: 13:51:21.037 [main] DEBUG org.hibernate.SQL - insert into steeling_wheel (car_id, type, id) values (?, ?, ?) 13:51:21.037 [main] TRACE o.h.type.descriptor.sql.BasicBinder - binding parameter [1] as [BIGINT] - [1999] 13:51:21.037 [main] TRACE o.h.type.descriptor.sql.BasicBinder - binding parameter [2] as [VARCHAR] - [wood] 13:51:21.037 [main] TRACE o.h.type.descriptor.sql.BasicBinder - binding parameter [3] as [BIGINT] - [2000] 13:51:21.039 [main] DEBUG org.hibernate.SQL - select steelingwh0_.id as id1_1_1_, steelingwh0_.car_id as car_id3_1_1_, steelingwh0_.type as type2_1_1_, car1_.id as id1_0_0_, car1_.brand as brand2_0_0_ from steeling_wheel steelingwh0_ left outer join car car1_ on steelingwh0_.car_id=car1_.id where steelingwh0_.id=? 13:51:21.039 [main] TRACE o.h.type.descriptor.sql.BasicBinder - binding parameter [1] as [BIGINT] - [2000]

    双外键:

    13:48:38.737 [main] DEBUG org.hibernate.SQL - insert into car (brand, steeling_wheel_id, id) values (?, ?, ?) 13:48:38.737 [main] TRACE o.h.type.descriptor.sql.BasicBinder - binding parameter [1] as [VARCHAR] - [BENZ] 13:48:38.737 [main] TRACE o.h.type.descriptor.sql.BasicBinder - binding parameter [2] as [BIGINT] - [2000] 13:48:38.737 [main] TRACE o.h.type.descriptor.sql.BasicBinder - binding parameter [3] as [BIGINT] - [1999] 13:48:38.738 [main] DEBUG org.hibernate.SQL - update steeling_wheel set car_id=?, type=? where id=? 13:48:38.738 [main] TRACE o.h.type.descriptor.sql.BasicBinder - binding parameter [1] as [BIGINT] - [1999] 13:48:38.738 [main] TRACE o.h.type.descriptor.sql.BasicBinder - binding parameter [2] as [VARCHAR] - [wood] 13:48:38.738 [main] TRACE o.h.type.descriptor.sql.BasicBinder - binding parameter [3] as [BIGINT] - [2000] 13:48:38.740 [main] DEBUG org.hibernate.SQL - select steelingwh0_.id as id1_1_2_, steelingwh0_.car_id as car_id3_1_2_, steelingwh0_.type as type2_1_2_, car1_.id as id1_0_0_, car1_.brand as brand2_0_0_, car1_.steeling_wheel_id as steeling3_0_0_, steelingwh2_.id as id1_1_1_, steelingwh2_.car_id as car_id3_1_1_, steelingwh2_.type as type2_1_1_ from steeling_wheel steelingwh0_ left outer join car car1_ on steelingwh0_.car_id=car1_.id left outer join steeling_wheel steelingwh2_ on car1_.steeling_wheel_id=steelingwh2_.id where steelingwh0_.id=? 13:48:38.740 [main] TRACE o.h.type.descriptor.sql.BasicBinder - binding parameter [1] as [BIGINT] - [2000]

    另外,提到的OneToOne改成OneToMany,这种做法除了对象集合的额外开销之外。如果你是一个老项目,会对项目中已经存在的其他sql语句造成影响。 比如有这样的Sql:

    <named-query name="Operations.findxxx"> <query> SELECT car FROM Car car WHERE car.steelingWheel.Id = :swId ORDER BY ca.id DESC </query> </named-query>

    这时,你的改动就会造成legacy的代码出错。

    在这里,除了上面提到的方法,额外的我介绍一个。就是新增一个entity去获取你想要的参数,然后再做转换。

    接着上文的例子。我们新增一个CarLite的Entity,这里我们没有关联SteelingWheel:

    @Entity //指向同一张表 @Table( name = "car" ) public class CarLite { @Id @Column( name = "id" ) @GeneratedValue( strategy = GenerationType.AUTO ) Long id; @Column( name = "brand" ) String brand; }

    在确定没有用到SteelingWheel的用户场景,我们就调用这个Entity来获取Car Table的值。这里要特别注意,Car和CarLite都指向同一张表!

    运行一下:

    List<CarLite> carLites = carLiteRepository.findAll();

    看看结果:

    *************start***************** 14:38:27.739 [main] INFO o.h.h.i.QueryTranslatorFactoryInitiator - HHH000397: Using ASTQueryTranslatorFactory 14:38:27.926 [main] DEBUG org.hibernate.SQL - select carlite0_.id as id1_0_, carlite0_.brand as brand2_0_ from car carlite0_ *************end*****************

    只有一条select语句。 然后将获取的carLites转换问cars:

    List<Car> cars = new ArrayList<>(); for( CarLite carLite : carLites ) { Car car = new Car(); car.setId( carLite.getId() ); car.setBrand( carLite.getBrand() ); cars.add( car ); }

    虽然这里增加了额外的转换,但是效率却越胜于额外的N条select语句。

    转载请注明原文地址: https://ju.6miu.com/read-1309214.html
    最新回复(0)