Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/http/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Hibernate多对多集合插入优化_Java_Hibernate_Spring Data Jpa - Fatal编程技术网

Java Hibernate多对多集合插入优化

Java Hibernate多对多集合插入优化,java,hibernate,spring-data-jpa,Java,Hibernate,Spring Data Jpa,我刚接触数据库,我有一个与HSQLDB合作的SpringDataJPA培训项目,该项目有两个实体,其中包含子集合和多对多关系。 一个实体称为菜单,它包含一个菜品列表,反之亦然,一个菜品包含它所属的一组菜单。 当我尝试将一组盘子插入表中时,Hibernate会为每个实体发送一个单独的调用。有没有办法优化Hibernate发送一个复杂查询来保存整个子集合? UPD。 抱歉弄错了,实际上我正在保存包含菜品收藏的菜单,而不仅仅是保存菜品收藏 Hibernate: call next value

我刚接触数据库,我有一个与HSQLDB合作的SpringDataJPA培训项目,该项目有两个实体,其中包含子集合和多对多关系。 一个实体称为菜单,它包含一个菜品列表,反之亦然,一个菜品包含它所属的一组菜单。 当我尝试将一组盘子插入表中时,Hibernate会为每个实体发送一个单独的调用。有没有办法优化Hibernate发送一个复杂查询来保存整个子集合? UPD。 抱歉弄错了,实际上我正在保存包含菜品收藏的菜单,而不仅仅是保存菜品收藏

Hibernate: 
    call next value for global_seq
Hibernate: 
    /* insert com.atanava.restaurants.model.Menu
        */ insert 
        into
            menus
            (date, restaurant_id, id) 
        values
            (?, ?, ?)
Hibernate: 
    /* insert collection
        row com.atanava.restaurants.model.Menu.dishes */ insert 
        into
            dishes_menus
            (menu_id, dish_id) 
        values
            (?, ?)
Hibernate: 
    /* insert collection
        row com.atanava.restaurants.model.Menu.dishes */ insert 
        into
            dishes_menus
            (menu_id, dish_id) 
        values
            (?, ?)
Hibernate: 
    /* insert collection
        row com.atanava.restaurants.model.Menu.dishes */ insert 
        into
            dishes_menus
            (menu_id, dish_id) 
        values
            (?, ?)
Hibernate: 
    /* insert collection
        row com.atanava.restaurants.model.Menu.dishes */ insert 
        into
            dishes_menus
            (menu_id, dish_id) 
        values
            (?, ?)
Hibernate: 
    /* insert collection
        row com.atanava.restaurants.model.Menu.dishes */ insert 
        into
            dishes_menus
            (menu_id, dish_id) 
        values
            (?, ?)
菜单类:

@NamedQueries({
        @NamedQuery(name = Menu.GET, query = "SELECT m FROM Menu m WHERE m.id=:id AND m.restaurant.id=:restaurantId"),
        @NamedQuery(name = Menu.BY_RESTAURANT, query = "SELECT m FROM Menu m WHERE m.restaurant.id=:restaurantId ORDER BY m.date DESC"),
        @NamedQuery(name = Menu.BY_DATE, query = "SELECT m FROM Menu m WHERE m.date=:date"),
        @NamedQuery(name = Menu.BY_REST_AND_DATE, query = "SELECT m FROM Menu m WHERE m.restaurant.id=:restaurantId AND m.date=:date"),
        @NamedQuery(name = Menu.DELETE, query = "DELETE FROM Menu m WHERE m.id=:id AND m.restaurant.id=:restaurantId"),
})

@Entity
@Table(name = "menus", uniqueConstraints = {@UniqueConstraint(columnNames = {"restaurant_id", "date"},
        name = "restaurant_id_date_idx")})
public class Menu extends AbstractBaseEntity {

    public static final String GET = "Menu.get";
    public static final String BY_RESTAURANT = "Menu.getAllByRestaurant";
    public static final String BY_DATE = "Menu.getAllByDate";
    public static final String BY_REST_AND_DATE = "Menu.getByRestAndDate";
    public static final String DELETE = "Menu.delete";

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "restaurant_id", nullable = false)
    @OnDelete(action = OnDeleteAction.CASCADE)
    @NotNull
    private Restaurant restaurant;

    @ManyToMany(fetch = FetchType.EAGER)
    @Fetch(FetchMode.SUBSELECT)
    @JoinTable(name = "dishes_menus",
            joinColumns = @JoinColumn(name = "menu_id"),
            inverseJoinColumns = @JoinColumn(name = "dish_id"))
    private List<Dish> dishes;

    @Column(name = "date", columnDefinition = "date default current_date", nullable = false)
    @NotNull
    private LocalDate date;

    //constructors, getters, setters
}
UPD2 以下是我的spring-db.xml配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:jdbc="http://www.springframework.org/schema/jdbc"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

    <jdbc:initialize-database data-source="dataSource" enabled="${database.init}">
        <jdbc:script location="${jdbc.initLocation}"/>
        <jdbc:script encoding="utf-8" location="classpath:db/populateDB.sql"/>
    </jdbc:initialize-database>

    <context:property-placeholder location="classpath:db/hsqldb.properties" system-properties-mode="OVERRIDE"/>

    <!--no pooling-->
    <bean id="dataSource"
          class="org.springframework.jdbc.datasource.DriverManagerDataSource"
          p:driverClassName="org.hsqldb.jdbcDriver"
          p:url="${database.url}"
          p:username="${database.username}"
          p:password="${database.password}"/>

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
          p:dataSource-ref="dataSource"
          p:packagesToScan="com.atanava.**.model">
        <!--p:persistenceUnitName="persistenceUnit">-->

        <property name="jpaPropertyMap">
            <map>
                <entry key="#{T(org.hibernate.cfg.AvailableSettings).FORMAT_SQL}" value="${hibernate.format_sql}"/>
                <entry key="#{T(org.hibernate.cfg.AvailableSettings).USE_SQL_COMMENTS}" value="${hibernate.use_sql_comments}"/>
                <entry key="#{T(org.hibernate.cfg.AvailableSettings).JPA_PROXY_COMPLIANCE}" value="false"/>
                <!--<entry key="#{T(org.hibernate.cfg.AvailableSettings).HBM2DDL_AUTO}" value="${hibernate.hbm2ddl.auto}"/>-->
            </map>
        </property>

        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" p:showSql="${jpa.showSql}">
            </bean>
        </property>
    </bean>

    <tx:annotation-driven/>

    <!-- Transaction manager for a single JPA EntityManagerFactory (alternative to JTA) -->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
          p:entityManagerFactory-ref="entityManagerFactory"/>

    <context:component-scan base-package="com.atanava.**.repository**"/>
    <jpa:repositories base-package="com.atanava.**.repository**"/>

</beans>

下面是我创建的persistence.xml文件:

<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.2"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
    <persistence-unit name="menu-persistence-unit">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <class>com.atanava.restaurants.model.Menu</class>
        <class>com.atanava.restaurants.model.Dish</class>
        <properties>
            <property name="hibernate.jdbc.batch_size" value="20"/>
        </properties>
    </persistence-unit>
</persistence>

org.hibernate.jpa.HibernatePersistenceProvider
com.atanava.restaurants.model.Menu
com.atanava.restaurants.model.Dish

您可以在文档中找到有关批处理的信息:


本质上,您只需将persistence.xml中的
hibernate.jdbc.batch_size
属性设置为例如20。

为了有效地使用hibernate,您应该查看一下Vlad Mihalcea的页面。他用
描述了这个问题。为了优化许多实体的插入,您可以看看关于.Felix的文章,谢谢您的建议。我对它进行了如下重构:@ManyToMany(fetch=FetchType.EAGER,cascade={CascadeType.REMOVE,CascadeType.MERGE})@JoinTable(name=“dish\u menus”、joinColumns=@JoinColumn(name=“menu\u id”)、inverseJoinColumns=@JoinColumn(name=“dish\u id”))私有盘;但是Hibernate仍然会发送大量的插入请求。首先,我不确定是否需要立即获取。只要始终使用延迟加载,并在需要时初始化集合。由于我没有尝试您的整个代码库,我只能指出我的观察结果。我意识到你在
Dish
类中使用了
Set
。但是,在类
菜单
中,可以使用
列表
。我的想法是首先删除Hibernate可以自动创建的一些东西,例如手动初始化数据库。然后,可能更容易找到原因。不幸的是,这对我不起作用。可能是因为我试图一次保存整个菜单,而不是一批对象。我这样保存:
crudmenusrepository.save(menu)
,其中菜单包含一个列表或一组菜肴。这应该可以。您可以调试到
org.hibernate.persister.collection.AbstractCollectionPersister#insertRows
以查看发生了什么。感谢Christian,我将尝试以这种方式进行调试。我尝试以这种方式进行调试,但由于某些原因,没有调用此方法。我更新了我的问题,并添加了我创建的spring-db.xml配置和persistence.xml文件。也许你应该启用调试日志来查看到底发生了什么。每次获取语句执行时,查询都会注销,但这并不意味着每次都会重新创建查询。很可能,它已经被重新用于批处理了。
CREATE TABLE dishes
(
    id            INTEGER GENERATED BY DEFAULT AS SEQUENCE GLOBAL_SEQ PRIMARY KEY,
    restaurant_id INTEGER              NOT NULL,
    name          VARCHAR(255)         NOT NULL,
    price         INTEGER              NOT NULL,
    active        BOOLEAN DEFAULT TRUE NOT NULL,
    FOREIGN KEY (restaurant_id) REFERENCES restaurants (id) ON DELETE CASCADE
);
CREATE UNIQUE INDEX unique_restaurant_id_dish_name_idx on dishes (restaurant_id, name);

CREATE TABLE menus
(
    id            INTEGER GENERATED BY DEFAULT AS SEQUENCE GLOBAL_SEQ PRIMARY KEY,
    restaurant_id INTEGER                   NOT NULL,
    date          DATE DEFAULT CURRENT_DATE NOT NULL,
    CONSTRAINT restaurant_id_date_idx UNIQUE (restaurant_id, date),
    FOREIGN KEY (restaurant_id) REFERENCES restaurants (id) ON DELETE CASCADE
);

CREATE TABLE dishes_menus
(
    dish_id INTEGER NOT NULL,
    menu_id INTEGER NOT NULL,
    CONSTRAINT dish_id_menu_id_idx UNIQUE (dish_id, menu_id),
    FOREIGN KEY (dish_id) REFERENCES dishes (id) ON DELETE CASCADE,
    FOREIGN KEY (menu_id) REFERENCES menus (id) ON DELETE CASCADE
);
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:jdbc="http://www.springframework.org/schema/jdbc"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

    <jdbc:initialize-database data-source="dataSource" enabled="${database.init}">
        <jdbc:script location="${jdbc.initLocation}"/>
        <jdbc:script encoding="utf-8" location="classpath:db/populateDB.sql"/>
    </jdbc:initialize-database>

    <context:property-placeholder location="classpath:db/hsqldb.properties" system-properties-mode="OVERRIDE"/>

    <!--no pooling-->
    <bean id="dataSource"
          class="org.springframework.jdbc.datasource.DriverManagerDataSource"
          p:driverClassName="org.hsqldb.jdbcDriver"
          p:url="${database.url}"
          p:username="${database.username}"
          p:password="${database.password}"/>

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
          p:dataSource-ref="dataSource"
          p:packagesToScan="com.atanava.**.model">
        <!--p:persistenceUnitName="persistenceUnit">-->

        <property name="jpaPropertyMap">
            <map>
                <entry key="#{T(org.hibernate.cfg.AvailableSettings).FORMAT_SQL}" value="${hibernate.format_sql}"/>
                <entry key="#{T(org.hibernate.cfg.AvailableSettings).USE_SQL_COMMENTS}" value="${hibernate.use_sql_comments}"/>
                <entry key="#{T(org.hibernate.cfg.AvailableSettings).JPA_PROXY_COMPLIANCE}" value="false"/>
                <!--<entry key="#{T(org.hibernate.cfg.AvailableSettings).HBM2DDL_AUTO}" value="${hibernate.hbm2ddl.auto}"/>-->
            </map>
        </property>

        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" p:showSql="${jpa.showSql}">
            </bean>
        </property>
    </bean>

    <tx:annotation-driven/>

    <!-- Transaction manager for a single JPA EntityManagerFactory (alternative to JTA) -->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
          p:entityManagerFactory-ref="entityManagerFactory"/>

    <context:component-scan base-package="com.atanava.**.repository**"/>
    <jpa:repositories base-package="com.atanava.**.repository**"/>

</beans>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.2"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
    <persistence-unit name="menu-persistence-unit">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <class>com.atanava.restaurants.model.Menu</class>
        <class>com.atanava.restaurants.model.Dish</class>
        <properties>
            <property name="hibernate.jdbc.batch_size" value="20"/>
        </properties>
    </persistence-unit>
</persistence>