Spring JpaRepository保存导致生成100项选择

时间:2019-04-11 09:32:08

标签: jpa spring-data-jpa

我在JpaRepository上调用save时遇到非常奇怪的错误。 该代码似乎微不足道,所以我只能认为它与配置有关。

基本上,我在存储库上调用findBy方法,这将完全按预期返回dao对象的列表,我遍历此列表设置时间戳,然后在每个dao上调用save(),将第一个保存称为日志中充满了数百条相同的select语句,在我试图保存的dao上进行选择,直到最终出现堆栈溢出。 是什么原因造成的? (请注意,最初我在dao对象列表上调用了saveAll()-毫无疑问,它具有相同的错误)

  public void triggerDeletion() {
        ZonedDateTime expiryDate = ZonedDateTime.now().minus(daysAfterExpiry);
        // Get list of conversations to delete
        List<ConversationDao> conversationDaoList = conversationDatabaseService.retrieveExpiredConversations(expiryDate);
        // Mark each conversation as deleted by setting its deletion timestamp to now.
        conversationDaoList.stream().forEach(conversation->delete(conversation));

    }
    public  void delete(ConversationDao conversationDao){
        conversationDao.setDeletionTimestamp(new Timestamp(System.currentTimeMillis()));

        conversationDatabaseService.save( conversationDao );   <------ This generates 100s of select statements.
    }
    ...
// ConversationDatabaseService Interface
////////////////////////////////////////

public interface ConversationDatabaseService {   
    void save(ConversationDao conversationDao); 

}
...
// Conversation DatabaseService Class
/////////////////////////////////////

@Service
public class ConversationDatabaseServiceImpl implements ConversationDatabaseService {

    private final ConversationRepository conversationRepository;

    public void save(ConversationDao conversationDao) {

    conversationRepository.saveAndFlush(conversationDao);  // Just save has also been tried.
}

}
... 
// ConversationRepository interface
///////////////////////////////////

public interface ConversationRepository extends JpaRepository<ConversationDao, String> {

    List<ConversationDao> findByExpiryDateLessThanAndDeletionTimestampIsNull(Timestamp expiryDate);
}
...
// ConversationDao
//////////////////////////////////

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import java.sql.Date;
import java.sql.Timestamp;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;

import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.UpdateTimestamp;

@Entity
@Table(name = "DOCX_CONVERSATION")
public class ConversationDao {
    @Id
    @GeneratedValue(generator = "uuid2")
    @GenericGenerator(name = "uuid2",
        strategy = "uuid2")
    @Column(name = "CONVERSATION_ID",
        columnDefinition = "char")
    private String conversationId;

    @Column(name = "PROCESS_CODE")
    private String processCode;

    @Column(name = "PROFILE_ID",
        columnDefinition = "char")
    private String profileId;

    @Column(name = "REMINDER_EMAIL_SENT",
        columnDefinition = "char")
    private String reminderEmailSent;

    @Column(name = "EXPIRY_DATE")
    private Date expiryDate;

    @Column(name = "DELETION_TIMESTAMP")
    private Timestamp deletionTimestamp;

    @Column(name = "LAST_LOGIN_TIMESTAMP")
    private Timestamp lastLoginTimestamp;

    @Column(name = "CREATED_USER_ID",
        columnDefinition = "char")
    private String colleagueId;

    @Column(name = "CREATED_TIMESTAMP",
        updatable = false)
    @CreationTimestamp
    private Timestamp createdTimestamp;

    @Column(name = "LAST_UPDATED_USER_ID",
        columnDefinition = "char")
    private String lastUpdatedUserId;

    @Column(name = "LAST_UPDATED_TIMESTAMP")
    @UpdateTimestamp
    private Timestamp lastUpdatedTimestamp;

    @OneToMany(mappedBy = "conversation",
        cascade = CascadeType.ALL)
    private Set<MessageDetailDao> messageDetailDaoSet = new HashSet<>();

    @OneToMany(mappedBy = "fileDetailId.conversation",
        cascade = CascadeType.ALL)
    private Set<FileDetailDao> fileDetailDaoSet = new HashSet<>();

    @OneToMany(mappedBy = "conversation",
        cascade = CascadeType.ALL)
    private Set<ParameterDao> parameterDaoSet = new HashSet<>();

    @OneToMany(mappedBy = "conversation",
        cascade = CascadeType.ALL)
    private Set<NotificationDao> notificationDaoSet = new HashSet<>();

    public ConversationDao() {
    }

    public ConversationDao(String processCode, Date expiryDate,
        String colleagueId, String lastUpdatedUserId) {
        this.processCode = processCode;
        this.reminderEmailSent = "N";
        this.expiryDate = expiryDate;
        this.colleagueId = colleagueId;
        this.lastUpdatedUserId = lastUpdatedUserId;
    }

    public String getConversationId() {
        return conversationId;
    }

    public void setConversationId(String conversationId) {
        this.conversationId = conversationId;
    }

    public String getProcessCode() {
        return processCode;
    }

    public void setProcessCode(String processCode) {
        this.processCode = processCode;
    }

    public String getProfileId() {
        return profileId;
    }

    public void setProfileId(String profileId) {
        this.profileId = profileId;
    }

    public String getReminderEmailSent() {
        return reminderEmailSent;
    }

    public void setReminderEmailSent(String reminderEmailSent) {
        this.reminderEmailSent = reminderEmailSent;
    }

    public Date getExpiryDate() {
        return expiryDate;
    }

    public void setExpiryDate(Date expiryDate) {
        this.expiryDate = expiryDate;
    }

    public Timestamp getDeletionTimestamp() {
        return deletionTimestamp;
    }

    public void setDeletionTimestamp(Timestamp deletionTimestamp) {
        this.deletionTimestamp = deletionTimestamp;
    }

    public Timestamp getLastLoginTimestamp() {
        return lastLoginTimestamp;
    }

    public void setLastLoginTimestamp(Timestamp lastLoginTimestamp) {
        this.lastLoginTimestamp = lastLoginTimestamp;
    }

    public String getColleagueId() {
        return colleagueId.trim();
    }

    public void setColleagueId(String colleagueId) {
        this.colleagueId = colleagueId;
    }

    public Timestamp getCreatedTimestamp() {
        return createdTimestamp;
    }

    public void setCreatedTimestamp(Timestamp createdTimestamp) {
        this.createdTimestamp = createdTimestamp;
    }

    public String getLastUpdatedUserId() {
        return lastUpdatedUserId;
    }

    public void setLastUpdatedUserId(String lastUpdatedUserId) {
        this.lastUpdatedUserId = lastUpdatedUserId;
    }

    public Timestamp getLastUpdatedTimestamp() {
        return lastUpdatedTimestamp;
    }

    public void setLastUpdatedTimestamp(Timestamp lastUpdatedTimestamp) {
        this.lastUpdatedTimestamp = lastUpdatedTimestamp;
    }

    public void addMessageDetailDao(MessageDetailDao messageDetailDao) {
        messageDetailDaoSet.add(messageDetailDao);
        messageDetailDao.setConversation(this);
    }

    public Set<MessageDetailDao> getMessageDetailDao() {
        return messageDetailDaoSet;
    }

    public void addFileDetailDao(FileDetailDao fileDetailDao) {
        fileDetailDaoSet.add(fileDetailDao);
        fileDetailDao.getId().setConversation(this);
    }

    public Set<FileDetailDao> getFileDetailDao() {
        return fileDetailDaoSet;
    }

    public void addParameterDao(ParameterDao parameterDao) {
        parameterDaoSet.add(parameterDao);
        parameterDao.setConversation(this);
    }

    public Set<ParameterDao> getParameterDao() {
        return parameterDaoSet;
    }

    public void addNotificationDao(NotificationDao notificationDao) {
        notificationDaoSet.add(notificationDao);
        notificationDao.setConversation(this);
    }

    public Set<NotificationDao> getNotificationDao() {
        return notificationDaoSet;
    }
}   

}

这会在销毁堆栈之前生成这些相同的select语句100次:-

1TS="20190411.075004.028" 4MSG="binding parameter [1] as [VARCHAR] - [6df49d6f-216b-460d-9282-2d25c098f9fe]" 1EVC="TRACE" 2CLS="BasicBinder"
1TS="20190411.075004.065" 4MSG="extracted value ([convers16_10_0_] : [VARCHAR]) - [6df49d6f-216b-460d-9282-2d25c098f9fe]" 1EVC="TRACE" 2CLS="BasicExtractor"
1TS="20190411.075004.069" 4MSG="extracted value ([file_met1_10_0_] : [VARCHAR]) - [4E90FD20-FC59-41B8-BF8E-88B7D682A87C]" 1EVC="TRACE" 2CLS="BasicExtractor"
1TS="20190411.075004.074" 4MSG="select conversati0_.conversation_id as conversa1_5_1_, conversati0_.created_user_id as created_2_5_1_, conversati0_.created_timestamp as created_3_5_1_, conversati0_.deletion_timestamp as deletion4_5_1_, conversati0_.expiry_date as expiry_d5_5_1_, conversati0_.last_login_timestamp as last_log6_5_1_, conversati0_.last_updated_timestamp as last_upd7_5_1_, conversati0_.last_updated_user_id as last_upd8_5_1_, conversati0_.process_code as process_9_5_1_, conversati0_.profile_id as profile10_5_1_, conversati0_.reminder_email_sent as reminde11_5_1_, filedetail1_.conversation_id as convers16_10_3_, filedetail1_.file_metadata_id as file_met1_10_3_, filedetail1_.conversation_id as convers16_10_0_, filedetail1_.file_metadata_id as file_met1_10_0_, filedetail1_.application_id as applicat2_10_0_, filedetail1_.case_id as case_id3_10_0_, filedetail1_.created_user_id as created_4_10_0_, filedetail1_.content_type as content_5_10_0_, filedetail1_.created_by as created_6_10_0_, filedetail1_.created_timestamp as created_7_10_0_, filedetail1_.document_code as document8_10_0_, filedetail1_.document_owner as document9_10_0_, filedetail1_.document_repository_state as documen10_10_0_, filedetail1_.file_name as file_na11_10_0_, filedetail1_.file_size_bytes as file_si12_10_0_, filedetail1_.file_state as file_st13_10_0_, filedetail1_.file_version as file_ve14_10_0_, filedetail1_.updated_by as updated15_10_0_ from docx_conversation conversati0_ left outer join docx_file_detail filedetail1_ on conversati0_.conversation_id=filedetail1_.conversation_id where conversati0_.conversation_id=?" 1EVC="DEBUG" 2CLS="SQL"

这是怎么回事?

更多信息,原因肯定与dao的这一部分有关:-

@OneToMany(mappedBy = "fileDetailId.conversation",cascade = CascadeType.ALL)
private Set<FileDetailDao> fileDetailDaoSet = new HashSet<>();

FileDetailDao包含对FileDetailId的嵌入式引用

@EmbeddedId
private FileDetailId fileDetailId;

此FileDetailId包含对联接的sessionId的引用:-

@Embeddable
public class FileDetailId implements Serializable {
    @Column(name = "FILE_METADATA_ID", columnDefinition = "char")
    private String fileMetadataId;

    @ManyToOne
    @JoinColumn(name = "CONVERSATION_ID")
    private ConversationDao conversation;
//etc
}

1 个答案:

答案 0 :(得分:0)

我不确定为什么,但是如果我将级联类型更改为REMOVE,它就可以了。...

@OneToMany(mappedBy = "fileDetailId.conversation",cascade = CascadeType.REMOVE)

private Set<FileDetailDao> fileDetailDaoSet = new HashSet<>();