Post

DataIntegrityViolationException

DataIntegrityViolationException

DataIntegrityViolationException

웹페이지에 게시물을 등록할 때 파일 첨부 기능을 같이 할 수 있도록 게시물 등록을 담당하고 있는 html의 자바스크립트를 수정하고 있던 중 게시물과 첨부파일을 등록하면 DataIntegrityViolationException에러가 나타나면서 등록 기능을 하지 못하였다.

10_25_log_error_dataIntegrity

로그에서 출력된 에러 메세지는 DataIntegrityViolationException에러가 발생하였으며 그 뒤엔 A different object with the same identifier value was already associated with the session라는 메세지가 이어져 있었다.

위의 에러 메세지를 살펴보았을 때 /view/s라는 객체가 이미 세션에 존재해 있는데, 똑같은 객체가 다시 세션에 들어왔기에 이러한 에러가 나타난 듯하다.
즉 이미 존재하는 엔티티 pk와 동일한 pk를 가진 객체가 들어와 나타난 에러이다.


  • Board 엔티티
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
@Entity
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ToString(exclude = "imageSet")
public class Board extends BaseEntity{

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long bno;

    private String title;

    private String content;

    private String user;

    @OneToMany(mappedBy = "board",
               fetch = FetchType.LAZY,
               cascade = CascadeType.ALL,
               orphanRemoval = true)
    @Builder.Default
    @BatchSize(size = 20)
    private Set<BoardImage> imageSet = new HashSet<>();

    public void addImage(String uuid, String fileName){
        BoardImage boardImage = BoardImage.builder()
                .uuid(uuid)
                .fileName(fileName)
                .board(this)
                .ord(imageSet.size())
                .build();
        imageSet.add(boardImage);
    }

    public void clearImage(){
        getImageSet().forEach(boardImage -> boardImage.changeBoard(null));
        this.imageSet.clear();
    }

    public void Change(String title, String content){
        this.title = title;
        this.content = content;
    }

    public void MapperSetBno(Long bno){
        this.bno = bno;
    }
}
  • BoardImage 엔티티
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@Entity
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ToString(exclude = "board")
public class BoardImage implements Comparable<BoardImage> {

    @Id
    private String uuid;

    private String fileName;
    private int ord;

    @ManyToOne
    private Board board;

    @Override
    public int compareTo(BoardImage other){
        return this.ord - other.ord;
    }

    public void changeBoard(Board board){
        this.board = board;
    }
}

BoardBoardImage이 둘은 게시물(Board) 등록할 때 첨부파일(BoardImage)가 있으면 같이 등록할 수 있도록 일대다 연관관계를 맺고 있다.
그래서 아무리봐도 서로 PK값을 건드리는 코드는 보이지 않았고, 심지어 에러 현상은 첨부파일 처음 하나만 등록했을 때는 정상적으로 등록이 되었고 다음에 등록할 때는 하나든 다수이든 이 에러현상이 나타났다.

그래서인지 에러 메세지 뒷부분인 /view/s이 부분이 신경쓰게 되었는데, 이 코드는 이미지 썸네일을 웹페이지에 볼 수 있도록 컨트롤러 Get매핑 값이었다.
그래서 정상적으로 들어간 등록 데이터를 데이터베이스에 조회를 해보자 왜 이런 에러가 나타난지 알 수 있었다.

  • 데이터베이스

10_25_database_error_uuid_filename


해결 과정

업로드한 파일의 이름을 uuidfileName가 합쳐져 새롭게 이름이 생성이 되면서 다시 데이터베이스에는 이 둘을 나누어 각각 다른 데이터에 저장을 할 수 있도록 로직을 구성하였다.
그런데 웹페이지에 업로드된 파일 이름이 컨트롤러 Get매핑 값까지 합쳐져 uuid에는 컨트롤러 매핑값, fileName에는 uuid가 잘못 들어가게 된 것이다.
당연히 두번째로 파일을 첨부할 때에는 엔티티에서 설정한 pk값인 uuid/view/s가 동일하니 엔티티 pk가 동일한 객체가 들어왔다고 위의 에러가 나타난 것이다.

그래서 html등록 화면에서 업로드되는 파일 태그 안에 따로 data속성을 이용해서 컨트롤러 매핑값을 뺀 uuidfileName를 입력하여 다시 게시물과 첨부파일을 등록한 결과 정상적으로 기능하였다

결국 이 에러 현상은 자신이 로직을 잘못 구성하였기에 발생하였지만, 그래도 DataIntegrityViolationException에러가 어떠한 원인 때문에 발생하는지 알 수 있는 기회였기에 오늘 복기 해보았다.


This post is licensed under CC BY 4.0 by the author.