아빠아버지
523
2019-05-15 20:53:24
13
248

디비에 넘버링을 순차적으로 할 수 있는 방법이 있을까요?


첨부파일을 여러개 올릴 때 file_no필드에 순차적으로 1,2,3,4,5.. 이렇게 들어가지게 만들었고, 테이블도 별도로 분리를 했습니다.

그런데 수정을 할 때 첨부파일을 하나를 제거하면 1,2,4,5 이런식으로 중간에 번호가 빠지게 되서
수정을 할 때 파일번호를 다시 넘버링을 1,2,3,4 이렇게 해 주도록 작업을 하고 있는데

아래 for문으로 작업을 했는데 당연하게...ㅠㅠ
for문이 돌고 난 후 제일 큰 값, 5가 디비에 일괄 업데이트가 되어버리네요..
 당연한 결과겠지만요..ㅠㅠ

for(int i = 1; i <= view.size(); i++) {
	boardDAO.update(dto.getBo_no(), i);
}

아래와 같이 쿼리를 넣었습니다.

UPDATE
  UPLOAD_FILE
SET
    FILE_NO = #{file_no}
WHERE
   BOARD_SEQ = #{board_seq}


위와같이 소스를 짜면 당연하게 제일 큰 값으로 다 덮어져 버리는데..
순차적으로 넘버링이 되도록 수정을 할려고 하는데..
도저히 방향이 생각이 나질 않네요..ㅠㅠ



0
0
  • 답변 13

  • zepinos
    18k
    2019-05-15 21:00:07 작성 2019-05-15 21:01:45 수정됨

    보기 좋게 하려는 건가요? 반드시 필요한 일이 아니라면 그냥 비어있는게 나아요.


    삭제되는 번호보다 큰 숫자만 -1 하도록 업데이트 한 번 해줘도 되지만, 사실 중요한 것도 아닌데 뭔가 규칙성 있게 보이려고 하는 욕심이라면...무시하는 쪽을 권합니다.

    1
  • 아빠아버지
    523
    2019-05-15 21:19:33

    zepinos님 답변 감사합니다.
    제가 질문을 드린 요지는..
    게시판에서 다중파일을 업로드 할 경우 처음 글을 작성할 때 for 문으로 업로드된 갯수만큼 반복해서 insert를 합니다.

    게시물을 수정 할 때 디비에 있는 게시판 아이디당 업로드된 첨부파일 갯수를 가져와서 반복문을 돌면서 첨부파일을 추가해주는식으로 다중파일 업로드 게시판을 구현하고 있는데

    중간에 넘버링이 빠져버리면 배열 범위 초과 오류가 나버려서요..ㅠㅠ


    대략 방향이

    1. 게시글 작성(첨부파일 추가 1,2,3,4,5... 여러개)

    2. 게시글 수정 시 jsp에서 받은 번호대로 db값 삭제와 파일 삭제

    3. db에 빠진 file_no값 정렬(1,2,3,5 를 1,2,3,4)
    4. 게시글 수정시 첨부한 첨부파일을 file_no의 마지막 값에 이어서 첨부파일 넘버링하기..

    이런식으로 단계를 잡아서 작업을 하고 있습니다.

    아직 경험이 없어서..ㅠㅠ 
    첨부파일 한 건은 간단한데, 다중으로 할려니 머리가 복잡해지네요..ㅠㅠ

    디비는 
    첨부파일 테이블을 별도로 만들어서 
    board_seq번호로 구분하고, file_no로 업로드를 하는 식으로 작업을 하고 있습니다.

    혼자서 할려니 진짜 쉽지가 않네요.ㅠㅜ

    0
  • zepinos
    18k
    2019-05-15 21:34:38 작성 2019-05-15 21:35:50 수정됨

    나열한 기능을 만족하기 위해 파일 번호가 순차적으로 존재할 필요가 없죠. 그래서 무시하란 말씀을 드리는 거구요.


    몇 가지 구현방법으로 나눌 수 있지만, 사실 파일이 업로드 되는 순간 파일에 숫자를 붙여주는건 일련번호이자 고유키의 기능을 하는게 가장 좋습니다. 파일 삭제 시 삭제된 번호를 저장했다가 이 번호만 지우고, 추가된 것들은 새로 채번해서 넣으면 되죠. 가령 예를 들면  < form> 안의 < input type="file"> 형태로 여러 파일을 받는 형태라면, 배열 혹은 리스트 형태로 서버에 업로드 되어 저장이 될 것이고, 수정 페이지에서는 이미 올라간 파일은 화면에 표시가 될 것이고 파일 옆 삭제 버튼을 누르면 Ajax 로 바로 삭제 처리를 하거나 삭제된 목록을 hidden 값으로 모아두면 됩니다. 수정에서 추가되는 것들 역시 올라가는 것 모두 sequence  하게 숫자를 부여히면 기존과 겹칠 일도 없습니다. 물론 파일 테이블에는 게시물 번호가 컬럼으로 존재하기 때문에 해당 게시물의 파일들은 쉽게 불러올 수 있고 출력 시에 번호로 정렬하면 올린 순서대로 표시도 됩니다. 이러한 작업을 거치면서 구멍난 번호를 채우는 작업은 전혀 필요 없구요.


    삭제 이후 번호를 다시 채우는 일이 왜 필요한지 위의 내용만으론 전 납득이 안가네요. 마찬가지로 제 말이 이해가 안되시면 다시 댓글 달아주세요.

    1
  • 아빠아버지
    523
    2019-05-15 21:58:25 작성 2019-05-15 21:59:08 수정됨

    제가 생각한 방법이..

    1. 글 작성시 파일을 올린다.(1,2,3,4,5 총 5개)
    2. 디비에 저장되서 넘버링이 된다..
    3. 글 수정시 3번 파일을 삭제하고, 첨부파일을 2개를 더 업로드를 한다
       - 삭제를 하고 다시 업로드를 할 경우 아래와같이 소스를 만들었는데..
    file_old_no는 삭제할 파일 번호를 가져오는 것이고, fileView는 디비에서 가져온 넘버링 값인데 중간에 번호가 빠진 상태에서 파일을 업로드하면 

    //수정할 첨부파일이 있을 경우 실행하는 로직.
    if(file_old_no.get(0) != 0 || file.size() > 0) {
       //업로드 된 첨부파일 갯수만큼 돌면서 첨부파일 DB와 파일들을 삭제한다.
       for(int i = 0; i < file_old_no.size(); i++) {
         System.out.println("file_old_no : " + file_old_no.get(i));
         System.out.println("file : " + file.get(i).getOriginalFilename());
         System.out.println("file.size : " + file.size());
         System.out.println("fileView.get(i) : " + fileView.get(file_old_no.get(i)-1).getFile_no());
        System.out.println("i : " + i);
       }
    }

    아래와 같은 오류가 나버리더라구요..

    제가 방향을 잘못 잡고 있거나, 뭔가 잘못 이해를 한 부분이 있는 것 같은데.. 뭐가문제인지 모르겠어요.ㅠㅠ

    May 15, 2019 9:53:30 PM org.apache.catalina.core.StandardWrapperValve invoke
    심각: Servlet.service() for servlet [appServlet] in context with path [/intranet] threw exception [Request processing failed; nested exception is java.lang.IndexOutOfBoundsException: Index: 0] with root cause
    java.lang.IndexOutOfBoundsException: Index: 0
    	at java.util.Collections$EmptyList.get(Collections.java:4454)
    	at com.woongjin.intranet.board.service.Impl.BoardServiceImpl.boardUpdate(BoardServiceImpl.java:70)
    	at com.woongjin.intranet.board.controller.BoardController.update(BoardController.java:103)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.lang.reflect.Method.invoke(Method.java:498)
    	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:220)
    	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:134)
    	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:116)
    	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
    	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
    	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)
    	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
    	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
    	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:661)
    	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
    	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
    	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:493)
    	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:137)
    	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
    	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:660)
    	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
    	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:798)
    	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:808)
    	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1498)
    	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    	at java.lang.Thread.run(Thread.java:745)
    
    

      

    0
  • zepinos
    18k
    2019-05-15 22:09:23

    오류 메세지만 보면 file_old_no.get(0) 이 문제인거 같은데, 해당 list 가 size() 가 0 인 상태 아닌가요? 말씀하신 게념과는 관련 없구요. 

    0
  • 초초보보
    83
    2019-05-15 22:12:22

    auto increment 설정 해놓은 필드의 값을 삭제하고 다시 추가하면 삭제된 번호에 이어서 증가되는 문제이신건가요?

    1234에서 4번 삭제하고 새로 추가하면 12356이렇게 되어서? 


    0
  • 아빠아버지
    523
    2019-05-15 22:12:30
    file_old_no.get(0) 부분은 
    첨부파일을 올리지 않았을 경우 null로 들어와 버려서 
    컨트롤러 단에서 
    @RequestParam(value = "file_old_no", required=false, defaultValue = "0") List<Integer> file_old_no
    이런식으로 기본값을 0으로 세팅을 해 줬고, 0이 아니거나 0보다 큰 숫자일 경우 첨부파일이 있다고 하고 한 상태입니다.
    0
  • 아빠아버지
    523
    2019-05-15 22:13:18

    auto_increment는 따로 설정을 하지 않은 상태입니다.
    제가 생각하기에는 굳이 auto increment를 할 필요가 없을 것 같다고 생각해서요.

    0
  • zepinos
    18k
    2019-05-15 22:21:13 작성 2019-05-15 22:23:50 수정됨

    이 경우 auto increment 가 가장 유요한 경우입니다. max + 1 은 성능적으로도, 기능적으로도 이 경우는 좋지 않습니다. oracle 이나 sql server 등 sequence 을 지원한다면 sequence 가 더 좋습니다. mysql 이라도 ai 설정을 하고 시작 번호를 가장 큰 값보다 더 큰 숫자로 설정하시면 됩니다.


    그리고 Collections.java:4454 가 .get(0) 하는 if 문이 있는 위치 아닌가요? 그 윗줄에서 .size() 출력해보세요.

    0
  • 초초보보
    83
    2019-05-15 22:24:55

    아아 auto increment 설정된 필드가 저렇게 값이 이어서 될 땐 저도 겪어봐서 도움드리려 했는데 아니시라면..

    죄송하네요.. ㅋㅋ 


    0
  • 아빠아버지
    523
    2019-05-15 22:30:54

    아.. 그런가요??
    그럼 이빨빠진것은 그냥 무시하고, 디비 구조를 auto_increment로 변경을 해서 다시 수정 해 봐야겠네요.

    마리아 디비를 사용하고 있는데 어차피 mysql과 같다고 알고있어서 똑같이 사용을 하면 될 것 같네요.

    그런데 마지막에 시작 번호를 가장 큰 값보다 더 큰 숫자로 설정하면 된다는 뜻이 글 수정시 첨부파일을 삭제하고 다시 등록 할 경우에 
    max값을 가져와서 서비스단에서 +1을 해 주면 된다는 말씀이신가요?

    근데..궁금한 점이..
    게시글 하나에 첨부파일이 5개가 등록되고, 
    또다시 게시글을 등록할 대 첨부파일을 3개를 등록하면 


    처음에는 1번 게시물에 1,2,3,4,5
    2번 게시물에는 6,7,8
    이런식으로 저장이 되게 하면 된다는 뜻으로 이해를 했는데 맞게 이해한건지 궁금합니다.

    그리고 max값을 가져와 그 값보다 더 큰 숫자로 설정하라는것이 
    두번째 글을 작성할때나 첫번째 글을 등록하고 수정시 첨부파일을 삭제하고 새로 올릴 때 무조건 auto_increment의  max값을 쿼리로 한번 구한 후, 서비스단에서 +1을 해 준 후 디비에 저장을 하라는 말씀이신가요???


    auto_increment는 자동으로 증가가 되는걸로 알고 있는데..

    그러면 글을 수정할 때 첨부파일을 올리거나 새로 글을 작성할 때 자동으로 최고값에서 플러스가 되는걸로 알고 있는데 그 부분은 그냥 신경을 안써도 되는건지, 아니면 서비스단에서 플러스 넘버링 작업을 해 줘야 하는건지 궁금합니다.


    글재주가 없어서 글 작성하는게 쉽지가 않네요.ㅠㅠ

    0
  • zepinos
    18k
    2019-05-15 22:40:49

    저도 지금 탭으로 댓글 달고 있어서 자세히 적기가 힘드네요.


    1. 마지막에 시작 번호를 가장 큰 값보다 더 큰 숫자로 설정하면 된다는 뜻


    이건 max + 1 을 하라는게 아니라 auto increment 지정 시 시작값을 지정하지 않으면 1부터 시작하는데, 이미 데이터가 있을 경우 충돌이 나므로 ai 지정할 때 한 번만...시작값을 겹치지 않게 수동으로 큰 값으로 지정하란 의미입니다. 이후부터는 신경 안써도 됩니다.


    2. 처음에 파일 다섯개를 올렸습니다. 1~5 까지 파일번호가 주어졌겠죠. 수정페이지에서 2, 4 번 파일을 지우고 2개의 추가파일을 올렸습니다. 그럼 form 에서 2, 4 두 개의 값이 숨겨져서 보내져야 하고 두 개의 파일이 바이너리로 보내져야 할 겁니다. 그럼 controller 에서 두 종류의 값을 받아서...

    먼저 2, 4 에 해당하는 정보를 조회해서 실제 파일을 지우고 db 에서 2, 4 번호의 레코드를 지웁니다.

    그리고 업로드 된 두 개의 파일을 지정된 위치에 저장하고 db 에 두 레코드를 추가합니다. 이 때 ai 로 번호가 지정되어 있으니 각각 6, 7 이 될 겁니다.

    결국 남아있는 파일 목록은 1, 3, 5, 6, 7 이 될 것이고 이 번호로 정렬하면 업로드한 순서대로 나열도 됩니다.

    0
  • 아빠아버지
    523
    2019-05-15 22:49:24

    zepinos님// 초초보보님//
    늦은 시간인데 정신없이 적은 글에 친절하고 자세하게 답변 달아주셔서 너무너무 감사드립니다.

    글을 작성하면서도 조언 해 주신대로 수정을 하면서 테스트를 해 봤는데 
    등록부터 다시 수정을 하고 있어서 정확히 테스트를 하기까지는 시간이 좀 걸릴 것 같네요..

    바쁘신데 귀중한 시간 내 주셔서 정말정말 감사드립니다.
    두 분 답변으로 인해 방향을 좀더 명확하게 잡을 수 있었습니다.

    차후에 막히거나 궁금한 점이 있을 때 작은 조언이라도 감사히 받겠습니다.

    가까운데 계시다면 감사의 표현으로 차라도 한 잔 사 드리고  싶은데..

    아무튼..너무너무 감사드립니다.^^

    즐거운 밤 되세요.
    저는 소스 수정하고, 테스트 해 보러 가겠습니다.

    0
  • 로그인을 하시면 답변을 등록할 수 있습니다.