1

我对我的大量域实体使用休眠批处理保存处理。首先,当我在数据库中只有一个实体可以插入时,我没有遇到性能问题。但是比我添加了与另一个实体的一对一关系之后,我遇到了性能和内存泄漏问题。Hibernate 现在一次做了两个插入。

这是我的域模型:

@Entity
@Table(name = "PRODUCT", uniqueConstraints = { @UniqueConstraint(columnNames = { "UPC" }) })
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Product {

    @Id
    @Column(name = "PRODUCT_ID", columnDefinition = "bigint")
    @Index(name = "PRODUCT_ID_IDX")
    private Long id;

    @Column(name = "UPC")
    private String upc;

    @Column(name = "CURRENCY")
    private String currency;

    @Column(name = "RETAIL_PRICE")
    private Double retailPrice;

    @Column(name = "SALE_PRICE")
    @Index(name = "PRODUCT_PRICE_IDX")
    private Double salePrice;

    @Type(type = "true_false")
    @Column(name = "INSTOCK")
    private boolean instock;

    @Column(name = "SHIPPING")
    private Double shipping;

    @Column(name = "RATING")
    private Integer rating;

    @Column(name = "VIEWS")
    @Index(name = "PRODUCT_VIEWS_IDX")
    private Long views;

    @OneToMany(fetch = FetchType.LAZY, cascade = { CascadeType.ALL })
    @JoinColumn(name = "PRODUCT_ID", nullable = false)
    @Index(name = "PRODUCT_ID_REVIEW_IDX")
    private List<ProductReview> reviews = new ArrayList<ProductReview>();

    //Here is new relation
    @OneToOne(fetch = FetchType.LAZY, mappedBy = "product", cascade = CascadeType.ALL)
    private ProductInformation information;

    @ManyToOne(fetch = FetchType.LAZY)
    @JsonIgnore
    @JoinColumn(name = "CATEGORY_ID", nullable = true)
    @Index(name = "PRODUCT_CAT_IDX")
    private ProductCategory category;

    @ManyToOne(fetch = FetchType.LAZY)
    @JsonIgnore
    @JoinColumn(name = "BRAND_ID", nullable = true)
    @Index(name = "PRODUCT_BRAND_IDX")
    private ProductBrand brand;

产品信息实体:

@Indexed
@Entity
@Table(name = "PRODUCT_INFO")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class ProductInformation {

    @Id
    @DocumentId
    @Column(name = "PRODUCT_ID", columnDefinition = "integer", unique = true, nullable = false)
    private Long id;

    @Column(name = "BUY_URL")
    private String buyUrl;

    @Column(name = "IMAGE_URL")
    private String imageUrl;

    @Column(name = "NAME", length = 10000)
    @Fields({
        @Field(index = org.hibernate.search.annotations.Index.TOKENIZED, analyzer = @Analyzer(impl = LowercaseKeywordAnalyzer.class)),
        @Field(name = "name", index = org.hibernate.search.annotations.Index.TOKENIZED, analyzer = @Analyzer(impl = LowercaseKeywordAnalyzer.class)) })
    @Index(name = "product_info_name_idx")
    private String name;

    @Column(name = "LONG_DESCRIPTION", length = 10000)
    private String longDescription;

    @Column(name = "SHORT_DESCRIPTION", length = 10000)
    private String shortDescription;

    @Column(name = "KEYWORDS", length = 10000)
    private String keywords;

    @OneToOne(fetch = FetchType.LAZY)
    @PrimaryKeyJoinColumn
    private Product product;

我如何设置我的产品:

result.setInformation(info);
    info.setProduct(result);

我的 DAO 方法:

@Override
    @Transactional(propagation = Propagation.REQUIRED)
    public int batchSave(List<Product> products, int batchSize) {

        int insertedCount = 0;
        Session batchSession = null;
        Transaction batchTransaction = null;
        try {
            batchSession = getSessionFactory().openSession();
            batchTransaction = batchStateLessSession.beginTransaction();
            for (Product product : products) {
                //First I used save() but this method calls select before insert and this                    //not a good idea.
                //batchSession.save(product);
                batchSession.persist(product);
                if (++insertedCount % batchSize == 0) {
                    batchSession.flush();
                    batchSession.clear();
                }
            }
            batchSession.flush();
            batchSession.clear();
            batchTransaction.commit();
            batchSession.close();
        } catch (ConstraintViolationException ex) {
            if (batchSession != null && batchTransaction != null) {
                batchSession.clear();
                batchTransaction.commit();
                batchSession.close();
            }
        }

        return insertedCount;
    }

我的批量大小是 50 行。所有休眠属性均已正确设置。我不使用 StatelessSession 因为我需要在我的实体上创建全文搜索索引。保存 30K 实体后出现内存泄漏。但我的 XML 文件有 10M 条目。当我没有 ProductInformation 实体并且所有字段都存储在 Product 实体中时,所有字段都可以正常工作,没有任何泄漏。

你对我的问题有任何想法吗?也许我应该使用 StatelessSession 并在插入所有行后在 10M 行表上创建全文索引?

4

0 回答 0