我对我的大量域实体使用休眠批处理保存处理。首先,当我在数据库中只有一个实体可以插入时,我没有遇到性能问题。但是比我添加了与另一个实体的一对一关系之后,我遇到了性能和内存泄漏问题。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 行表上创建全文索引?