Spring Boot:HIbernate不断调用复杂的外部联接查询

时间:2019-02-16 06:47:50

标签: mysql hibernate spring-boot

在Spring Boot应用程序中,我有两个实体Requirement和Product。需求与产品具有一对多关系。

在产品回购接口中,我有一个简单的查询方法,该方法可获取具有给定require_id的产品列表。这是代码:

interface ProductRepo: JpaRepository<Product, Int>{

 fun findProductsByRequirement_Id(id:Int) : List<Product>
}

但是,当从Rest Controller调用此方法时,我可以看到,与每个产品一起,hibernate返回的是对应的需求对象,而不仅仅是request_id。它不止于此,它还返回与JSON结果中的需求对象关联的所有异物(交易和销售)。

我已经在application.properties文件中将此选项设置为“ spring.jpa.properties.hibernate.show_sql = true”,每次调用该查询方法时,我在控制台中都会看到Hibernate不断调用许多复杂的外部联接查询甚至我都没有要求。我认为,当我不需要所有这些异物时,这会消耗不必要的资源。

以下是休眠在后台运行的sql查询:

  

休眠:将requiremen0_.id选择为id1_8_0_,将requiremen0_.deal_id选择为   deal_id4_8_0_,requiremen0_.requirement_total与requirem2_8_0_,   requiremen0_.sale_id为sale_id5_8_0_,requiremen0_.title为   title3_8_0_,deal1_.id为id1_4_1_,deal1_.account_id为   account_7_4_1_,以crm_cust8_4_1_的身分交易1..crm_customer_id,   deal1_.exp_closing_date为exp_clos2_4_1_,deal1_.requirement_title为   requirem3_4_1_,deal1_.sales_value为sales_va4_4_1_,deal1_.stage为   stage5_4_1_,deal1_.type为type6_4_1_,deal1_.user_id为   user_id9_4_1_,account2_.id为id1_0_2_,account2_.address为   地址2_0_2_,帐户2_.crm_customer_id作为crm_cust9_0_2_,   account2_.email为电子邮件3_0_2_,account2_.key_person为   key_pers4_0_2_,account2_.name为name5_0_2_,account2_.phone为   电话6_0_2_,帐户2_.status为状态7_0_2_,帐户2_。类型为   type8_0_2_,account2_.user_id为user_id10_0_2_,crmcustome3_.id为   id1_2_3_,crmcustome3_.address作为地址2_2_3_,crmcustome3_.email作为   email3_2_3_,crmcustome3_.key_person作为key_pers4_2_3_,   crmcustome3_.name为name5_2_3_,crmcustome3_.number_of_users为   number_o6_2_3_,crmcustome3_.phone作为phone7_2_3_,   crmcustome3_.subscription_type作为subscrip8_2_3_,   crmcustome3_.validity_exp_date为validity9_2_3_,user4_.id为   id1_11_4_,user4_.crm_customer_id作为crm_cust8_11_4_,   user4_.designation为designat2_11_4_,user4_.hierarchy_level为   hierarch3_11_4_,user4_.logged_in作为logging_i4_11_4_,user4_.login_id   作为login_id5_11_4_,user4_.login_pw作为login_pw6_11_4_,user4_.name作为   名称7_11_4_,sale5_.id为id1_9_5_,sale5_.crm_customer_id为   crm_cust4_9_5_,sale5_.deal_id作为deal_id5_9_5_,sale5_.sales_date作为   sales_da2_9_5_,sale5_.sales_value作为sales_va3_9_5_,sale5_.user_id   作为user_id6_9_5_,crmcustome6_.id作为id1_2_6_,crmcustome6_.address作为   地址2_2_6_,crmcustome6_.email作为电子邮件3_2_6_,   crmcustome6_.key_person为key_pers4_2_6_,crmcustome6_.name为   name5_2_6_,crmcustome6_.number_of_users作为number_o6_2_6_,   crmcustome6_.phone为phone7_2_6_,crmcustome6_.subscription_type为   subscrip8_2_6_,crmcustome6_.validity_exp_date作为有效期9_2_6_,   deal7_.id为id1_4_7_,Deal7_.account_id为account_7_4_7_,   deal7_.crm_customer_id为crm_cust8_4_7_,Deal7_.exp_closing_date为   exp_clos2_4_7_,deal7_.requirement_title为requirem3_4_7_,   deal7_.sales_value作为sales_va4_4_7_,deal7_.stage作为stage5_4_7_,   deal7_.type为type6_4_7_,Deal7_.user_id为user_id9_4_7_,user8_.id   作为id1_11_8_,user8_.crm_customer_id作为crm_cust8_11_8_,   user8_.designation为designat2_11_8_,user8_.hierarchy_level为   hierarch3_11_8_,user8_.logged_in作为logging_i4_11_8_,user8_.login_id   作为login_id5_11_8_,user8_.login_pw作为login_pw6_11_8_,user8_.name作为   来自需求requirename0_的name7_11_8_左外部加入交易   对requiremen0_.deal_id = deal1_.id的Deal1_左外部加入帐户   deal1_.account_id = account2_.id上的account2_左外部联接   在deal1_.crm_customer_id = crmcustome3_.id上的crm_customers crmcustome3_   左外部加入用户user4_ on deal1_.user_id = user4_.id左外部   在requiremen0_.sale_id = sale5_.id上左加入外部销售   crm_customers crmcustome6_特价5_.crm_customer_id = crmcustome6_.id   左外加入交易Deal7_待售中5_.deal_id = deal7_.id左外   加入用户user8_ on sale5_.user_id = user8_.id,其中requiremen0_.id =?

如何避免这种情况?

以下是产品和需求的实体类:

package com.ksk.crmserver.Model

import com.fasterxml.jackson.annotation.JsonIgnore
import javax.persistence.*

@Entity
@Table(name = "requirements")
data class Requirement(
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        val id: Int = 0,
        @Column(name = "title")
        val title: String = "",

        @OneToMany(mappedBy = "requirement")
        @JsonIgnore
        val products: List<Product>? = null,
        @Column(name = "requirement_total")

        val requirementTotal: Int = 0,

        @ManyToOne
        var deal: Deal? = null,

        @ManyToOne
        val sale: Sale?=null
)


package com.ksk.crmserver.Model

import javax.persistence.*


@Entity
@Table(name = "products", indexes = [Index(name = "idx_product", columnList = "name")])

data class Product(
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        val id: Int = 0,
        val name: String = "",
        val description: String? = "",

        @Column(name = "unit_cost")
        val unitCost: Double = 0.0,

        @Column(name = "qty")
        val qty: Double? = 0.0,

        val unit: String? = "",

        @Column(name = "total_Cost")
        val totalCost: Double? = 0.0,

        @Column(name = "profit_margin")
        val profitMargin: Double? = 0.0,

        val profit: Double? = 0.0,

        @Column(name = "vat_percentage")
        val vatPercentage: Double? = 0.0,

        val vat: Double? = 0.0,

        @Column(name = "total_price")
        val totalPrice: Double? = 0.0,

        @ManyToOne
        @JoinColumn(name = "requirement_id")
        val requirement: Requirement? = null


)

编辑: 我尝试使用EntityManager.getReference来获取Requirement Object的实例。但它仍在运行很长的SQL查询,以便从数据库中按ID提取需求。这是我来自Product的RestController类的代码:

恐怕它仍在运行sql join查询。这是我的Rest Controller代码:

@RestController
@CrossOrigin
class ProductRoute(val productRepo: ProductRepo, val requirementRepo: RequirementRepo) {

    @Autowired
    val entityManager: EntityManager?=null

    @GetMapping("/get/productsByReqId")
    fun getProductsByRequirementId(@RequestParam id: Int): List<Product> {
        val requirement = this.entityManager?.getReference(Requirement::class.java, id) as Requirement
        print("Done fetching the requirement")
        return this.productRepo.findProductsByRequirement(requirement)
    }

这是Hibernate正在运行的sql:

  

休眠:将requiremen0_.id选择为id1_8_0_,将requiremen0_.deal_id选择为   deal_id4_8_0_,requiremen0_.requirement_total与requirem2_8_0_,   requiremen0_.sale_id为sale_id5_8_0_,requiremen0_.title为   title3_8_0_,deal1_.id为id1_4_1_,deal1_.account_id为   account_7_4_1_,以crm_cust8_4_1_的身分交易1..crm_customer_id,   deal1_.exp_closing_date为exp_clos2_4_1_,deal1_.requirement_title为   requirem3_4_1_,deal1_.sales_value为sales_va4_4_1_,deal1_.stage为   stage5_4_1_,deal1_.type为type6_4_1_,deal1_.user_id为   user_id9_4_1_,account2_.id为id1_0_2_,account2_.address为   地址2_0_2_,帐户2_.crm_customer_id作为crm_cust9_0_2_,   account2_.email为电子邮件3_0_2_,account2_.key_person为   key_pers4_0_2_,account2_.name为name5_0_2_,account2_.phone为   电话6_0_2_,帐户2_.status为状态7_0_2_,帐户2_。类型为   type8_0_2_,account2_.user_id为user_id10_0_2_,crmcustome3_.id为   id1_2_3_,crmcustome3_.address作为地址2_2_3_,crmcustome3_.email作为   email3_2_3_,crmcustome3_.key_person作为key_pers4_2_3_,   crmcustome3_.name为name5_2_3_,crmcustome3_.number_of_users为   number_o6_2_3_,crmcustome3_.phone作为phone7_2_3_,   crmcustome3_.subscription_type作为subscrip8_2_3_,   crmcustome3_.validity_exp_date为validity9_2_3_,user4_.id为   id1_11_4_,user4_.crm_customer_id作为crm_cust8_11_4_,   user4_.designation为designat2_11_4_,user4_.hierarchy_level为   hierarch3_11_4_,user4_.logged_in作为logging_i4_11_4_,user4_.login_id   作为login_id5_11_4_,user4_.login_pw作为login_pw6_11_4_,user4_.name作为   名称7_11_4_,产品5_.requirement_id为require13_5_5_,   products5_.id为id1_5_5_,product5_.id为id1_5_6_,   product5_.description为descript2_5_6_,products5_.name为   名称3_5_6_,产品5_。利润为利润4_5_6_,   products5_.profit_margin为profit_m5_5_6_,product5_.qty为   qty6_5_6_,products5_.requirement_id为require13_5_6_,   product5_.total_price为total_co7_5_6_,product5_.total_price为   total_pr8_5_6_,products5_.unit为unit9_5_6_,products5_.unit_cost为   unit_co10_5_6_,products5_.vat如vat11_5_6_,   products5_.vat_percentage为vat_per12_5_6_,sale6_.id为id1_9_7_,   sale6_.crm_customer_id为crm_cust4_9_7_,sale6_.deal_id为   deal_id5_9_7_,sale6_.sales_date作为sales_da2_9_7_,sale6_.sales_value   作为sales_va3_9_7_,sale6_.user_id作为user_id6_9_7_,crmcustome7_.id作为   id1_2_8_,crmcustome7_.address作为地址2_2_8_,crmcustome7_.email作为   email3_2_8_,crmcustome7_.key_person作为key_pers4_2_8_,   crmcustome7_.name为name5_2_8_,crmcustome7_.number_of_users为   number_o6_2_8_,crmcustome7_.phone如phone7_2_8_,   crmcustome7_.subscription_type作为subscrip8_2_8_,   crmcustome7_.validity_exp_date为validity9_2_8_,deal8_.id为   id1_4_9_,deal8_.account_id作为account_7_4_9_,deal8_.crm_customer_id   作为crm_cust8_4_9_,deal8_.exp_closing_date作为exp_clos2_4_9_,   deal8_.requirement_title为requirem3_4_9_,Deal8_.sales_value为   sales_va4_4_9_,deal8_.stage为stage5_4_9_,deal8_.type为   type6_4_9_,deal8_.user_id作为user_id9_4_9_,user9_.id作为id1_11_10_,   user9_.crm_customer_id为crm_cust8_11_10_,user9_.designation为   designat2_11_10_,user9_.hierarchy_level作为hierarch3_11_10_,   user9_.logged_in为logging_i4_11_10_,user9_.login_id为   login_id5_11_10_,user9_.login_pw为login_pw6_11_10_,user9_.name为   需求需求中的name7_11_10_来自左外部加入交易   对requiremen0_.deal_id = deal1_.id的Deal1_左外部加入帐户   deal1_.account_id = account2_.id上的account2_左外部联接   在deal1_.crm_customer_id = crmcustome3_.id上的crm_customers crmcustome3_   左外部加入用户user4_ on deal1_.user_id = user4_.id左外部   在requiremen0_.id = products5_.requirement_id上加入产品products5_   左外部加入sales sale6_ on requiremen0_.sale_id = sale6_.id   外连接crm_customers crmcustome7_上   sale6_.crm_customer_id = crmcustome7_.id左外加入交易Deal8_   sale6_.deal_id = deal8_.id向左外部加入用户user9_   sale6_.user_id = user9_.id其中requiremen0_.id =?

     

完成获取要求2019-02-16 21:01:00.341 INFO 80558-   [nio-8080-exec-1] o.h.h.i.QueryTranslatorFactoryInitiator:   HHH000397:使用ASTQueryTranslatorFactory

     

休眠:选择product0_.id作为id1_5_,选择product0_.description作为   descript2_5_,product0_.name为name3_5_,product0_.profit为   Profit4_5_,product0_.profit_margin为profit_m5_5_,product0_.qty为   qty6_5_,product0_.requirement_id为require13_5_,   product0_.total_cost为total_co7_5_,product0_.total_price为   total_pr8_5_,product0_.unit为unit9_5_,product0_.unit_cost为   unit_co10_5_,product0_.vat为vat11_5_,product0_.vat_percentage为   来自产品product0_的vat_per12_5_,其中product0_.requirement_id =?

1 个答案:

答案 0 :(得分:0)

您可以将ManyToOne关系的fetchType设置为Lazy(ManyToOne关系的默认值为Eager)。这样,Hibernate仅在调用被调用对象时才加载它们。 如果要让Hibernate返回Id而不是整个引用的对象,则可以在此处查找:Hibernate - Foreign keys instead of Entities