트러블 슈팅

김태은·2024년 11월 15일

여기는 이제 컴파일 오류 등 많은 오류를 해결하는 과정을 적는 페이지가 될 것이다.



AccessDeniedException

  • 해당 컴파일 오류
    AccessDeniedException
    에러 메세지

내가 해석한 문제 : 리드미 파일이 어떠한 것 때문에 문제가 된다.

  1. 처음 생각한 문제 해결법 리드미 파일을 지운다.

2.두번째로는 AccessDeniedException 명을 검색하여 해결법을 찾고, 해보는 것!
AccessDeniedException 을 검색한 결과 Amazon SQS API 직접 호출 시 발생하는 “AccessDenied” 또는 “AccessDeniedException” 라는 것을 알게 되었다.
사실 모르는 용어가 많아서 정확히는 이해하지 못하지만 불러올 때, 문제가 된다는 걸 알게 되었다.
위 내용으로 해결 법은

- SQS 액세스 정책 또는 AWS Identity and Access Management(IAM) 정책에는 해당 작업에 대한 액세스를 명시적으로 허용하는 허가가 포함되어야 합니다.

- 작업을 수행하는 데 필요한 권한에만 최소 권한을 부여하는 것이 가장 좋습니다. 자세한 내용을 알아보려면 최소 권한 적용을 참조하세요.

- SQS 대기열이 다른 계정에 있는 경우, SQS 액세스 정책과 IAM 정책 모두 액세스를 명시적으로 허용해야 합니다.

중요: 두 정책에서 명시적 거부는 명시적 허용보다 우선합니다.

- 정책에서 조건 요소를 사용하는 경우 해당 조건이 액세스를 제한하는지 확인하세요.

- 사용자 또는 역할이 SCP를 사용하는 AWS Organizations 조직에 속해 있는 경우, SCP가 사용자나 역할을 차단하지 않는지 확인하세요.

AccessDeniedException 해결법 참조

나는 IAM 을 건들려 보기로하고 더 내용을 찾아 보았다.

IAM 엔터티(사용자 또는 역할)에 대한 권한 경계를 AWS지원합니다. 권한 경계는 관리형 정책을 사용하여 자격 증명 기반 정책을 통해 IAM 엔터티에 부여할 수 있는 최대 권한을 설정하는 고급 기능입니다. 엔터티의 권한 경계는 자격 증명 기반 정책 및 관련 권한 경계 모두에서 허용되는 작업만 수행하도록 허용합니다.

IAM 설명... 참조

너무 나에겐 어려운 내용...
째든 내가 이해한 건 IAM에 Deny 를 씀으로써 해당 문제를 해결할 수 있을거다? 정도였다.

적용 가능한 정책이 Deny 설명문을 포함한다면 요청은 명시적으로 거부됩니다. 정책이 Allow 설명문과 Deny 설명문을 포함한 요청에 적용된다면 Deny 설명문은 Allow 설명문에 우선합니다. 이 요청은 명시적으로 거부됩니다.

적용 가능한 Deny 설명문이 없고 적용 가능한 Allow 설명문도 없다면 묵시적 거부가 발생합니다. IAM 보안 주체가 기본적으로 액세스를 거부하기 때문에 명시적으로 작업을 허용해야 합니다. 그렇지 않으면 액세스는 묵시적으로 거부됩니다.

권한 부여 전략을 설계한다면 Allow 설명문으로 정책을 생성하여 보안 주체가 성공적으로 요청하도록 허용합니다. 그러나 명시적 또는 묵시적 거부 조합을 선택할 수 있습니다.

예를 들어, 허용되는 작업, 암시적으로 거부된 작업 및 명시적으로 거부된 작업을 포함하는 다음 정책을 생성할 수 있습니다. AllowGetList 설명문은 접두사 Get 및 List(으)로 시작하는 IAM 작업에 대한 읽기 전용 액세스를 허용합니다. iam:CreatePolicy와(과) 같은 IAM의 다른 모든 작업은 암시적으로 거부됩니다. DenyReports 설명문은 iam:GetOrganizationsAccessReport와 같이 Report 접미사가 포함된 작업에 대한 액세스를 거부하여 IAM 보고서에 대한 액세스를 명시적으로 거부합니다. 누군가가 이 보안 주체에 다른 정책을 추가하여 iam:GenerateCredentialReport와 같은 IAM 보고서에 대한 액세스 권한을 부여하는 경우, 보고서 관련 요청은 이 명시적 거부로 인해 계속 거부됩니다.

예시 코드

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowGetList",
            "Effect": "Allow",
            "Action": [
                "iam:Get*",
                "iam:List*"
            ],
            "Resource": "*"
        },
        {
            "Sid": "DenyReports",
            "Effect": "Deny",
            "Action": "iam:*Report",
            "Resource": "*"
        }
    ]
}

deny로 해결하는 법 참조

2_1. 위 방법대로 해결
하지만, 또 다른 난관... 해당 부분이 어디있고, 어디를 고쳐야하는가....
바로 막혀버렸다...

어떻게 하다 생각 중.. 도입부에 Amazon 키워드가 생각났다.
내가 Amazon과 연관된건, 프로젝트 생성시 jdk 버전 - vendor 부분이였다.

2_2. 그래서 프로젝트에 vendor 부분을 이클립스로 수정해보기로 했다!
결과... 그대로 실패....

  1. 방법은 readme를 지워야 했기에... 나의 코드 짤때의 회고를 놓칠 수 없어 튜터님께 물어본 결과!

해결

지우지 않고, 폴더를 옮기면 되는것! scr 폴더는 코드만이 있어야해서, readme는 같이 못있는다는 결론! scr 상위 폴더로 옮기니 해결!

  • 이게 아마 readme 가 통신? 하는 부분에서 코드가 아닌것이 올라와서, 이를 해결하려면 2. 해결 방법처럼 deny 로 처리를 하거나, 문제가 되는 파일을 옮겨야한다는 걸 알게 되었다.

회고 :
처음있는 컴파일 오류는 아니였지만, 코드의 문법이 틀려서 생긴 컴파일 오류만 접한 나에겐 꽤 힘들었다. 다만, 매니저님 말씀대로 혼자서 어느정도 이런 오류를 해결해봐야한다는게 무슨 뜻인지 알게 되었다.
다음에도 이런 문제가 생기면 잘 해결할 수 있지 않을까? 싶다.



엑세스 권한이 없습니다.

-컴파일 오류

이건 위처럼 경고메세지가 와다다 나오지 않고 딱 한줄.. 엑세스 권한이 없습니다...
어디가 잘 못된지 모르니.. 해당 문제는 검색도 힘든 상황이라.. 도움!

해결 : 오류의 문제는 정확히 설명하기 힘들지만, 해결은 src파일 위에 out폴더를 강제로 지웠다.
ps out 폴더는 src에서 코드를 실행하면 다시 생성되는 폴더라 지워도 상관없다!

... 이런식에 오류는 볼때마다 벌벌 떨린다... 많이 접하면 능숙하게 한다는 매니저님의 말씀을 잘 새겨들어 오류를 많이 접하고, 해결을 만약 하지못하더라도 많이 찾아봐야겠다...



github 인텔리제이 연동문제

전에도 한번 있었던 인텔리제이의 hithub연동 문제이다. 저번에 작성을 제대로 못한 것 같아 다시 작성한다.

해당 이슈는 github은 Main으로 초기 브런치?값이 정해져있는 반면, 인텔리제이는 master로 되어있다.

이 이슈를 고치는 법은 간단하다. 인텔리제이의 master 네이밍을 main으로 수정하면 된다.

scope - try-catch문

scope 때문에 컴파일 오류가 이전에 한두번 났던 적이있어서, 해당오류를 쉽게는 찾았다.

다만, 해당 부분에서도 scope가 적용되는 줄은 몰랐다.

해당부분은 바로! try-catch문 이었다. 전에 과제에선 예외처리를 생략하여, 해당 문제를 인지할 수 없었다.

try 실행문에 적은 변수는 finally에서 변수로써의 역할을 하지못하여, try문에 모든 실행문을 넣었고,

당연히 finally문도 쓰지못했다. 다음에는 try와 finally문을 같이 쓸 수 있는 방법을 고심해봐야 겠다.

Scanner - nextInt

마지막은 challengelv1 과제 중에 나타난다. 이 문제는 메서드안에서 다시 메서드를 불러오는 과정에서 문제가 발생했다.

그러면 안되지만, 한 클래스에 해당 객체를, 같은 클래스 안에 넣는 아주아주 나쁜!

째든,

nextInt는 \n 을 마지막에 입력된다는 걸 이미 알고 있어, 그래서 평소에 nextInt를 쓰면 nextLine을 써 줬다. 하지만 catch한 부분에서도 필요하다는 것을 몰라서 난 오류!

한마디로 nextLine을 하지 못해서 발생한 이슈!

nextLine을 catch 실행문에 적으면 에러를 잡을 수 있다.

git - local vs origin 의 commit 상태 갭 문제

git으로 branch를 만들어 호기롭게 이슈별로 commit을 하고 싶었다 ㅠ 그뿐이였다...

하지만 처음에 git 으로 branch를 기능(이슈)별로 만들라고 했으면, 연관성 없는 기능은 어짜피 혼자 있어도 구동이 되고, merge시에 충돌이 나지 않을텐데...

이런 부분을 생각 안하고 하나의 이슈를 완성했다고 생각되면 바로 main에 merge를 시켰다...

만약, 완벽하게 완성을 하고 다신 안건드릴 자신이 있다면 위 방법도 괜찮았을 수도 있지만, 나는 초보...

하나의 이슈를 완성했다고 판단하여 다른 이슈로 넘어가 작업 중... 까먹은 것이 생각남을 반복하다... 위에 사진처럼 수많은 commit log를 남겼다.. 그리고..

온라인 저장 origin 과 local이 서로 다른 상황이 발생하였다...

문제

Your branch and 'origin/main' have diverged,
and have 2 and 4 different commits each, respectively.

멋모르고, merge를 했다가 온 통 빨강색인 나의 프로젝트를 볼 수 있었다...

허허

해결

git reset --hard 명령어를 실행하였다. 해당 명령어는 head를 이전 커밋으로 이동하고 그 이후는 삭제하는 명령어이다.

그리고 데이터에 손상이 있을 수 있다고 하여 로컬의 파일을 백업을 하였다.

git push --force 그리고 해당 명령어를 실행! 이 명령어는 로컬 기준으로 원격 브랜치의 커밋 히스토리가 덮어씌워주는 명령어이다.

물론, 나의 경우는 git reset --hard 이 필요가 없었던거 같았지만, 결국엔 프로젝트를 지킬 수 있었다!

jdbc - JdbcTemplate vs Connection 데이터 베이스 설정

우선 사용자의 프로그램에 데이터 베이스를 연동한 것이, 스프링에 repository가 데이터 베이스와의 연결과는 조금 다를 수도, 혹은 같은 수도 있는 것을 알게해줬다.

JdbcTemplate은 캠프 강의에서 자동으로 데이터 베이스에 연결이 된다고 설명을 들은 적이 있었다.(물론 스프링 안에 application 에는 설정 해줘야한다.) 그래서 난 모든 jdbc 에 사용되는 객체는 데이터 베이스에 자동 연결이 되는 줄 알았다.

결론은 JdbcTemplate은 자동연결이 맞다! Connection은 설정을 해줘야한다!

JdbcTemplate의 메서드가 너무 생소하여, 다른 메서드를 이용하자! 라는 생각으로 Connection을 써봤고, JdbcTemplate 보다는 코드의 길이가 길어졌지만, 이해는 할 수 있었다. 자! 실행!

데이터 베이스의 위치를 찾을 수 없다는 메세지!( 이때, 캡처를 하지 못함;;)

재연을 위해 다시 오류를 만듬 'Connection connection = null;'

문제

2024-12-09T18:22:16.128+09:00 ERROR 14688 --- [schedule] [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: java.lang.NullPointerException: Cannot invoke "java.sql.Connection.prepareStatement(String)" because "connection" is null] with root cause

물론 정확히 이거 였다! 는 아니지만 ...

해결

private Connection getConnection() throws ClassNotFoundException, SQLException {
        Class.forName("com.mysql.cj.jdbc.Driver");

        // 1. Connection
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/schedule", "root", "testroot1234!@#$");
        return connection;
    }

연결만을 위한 메서드를 생성! 물론 이것을 생성자에 넣는 것이 가장 좋은 방법이지만, 이미 jdbctemplate 를 생성자에 담아, 위처럼 메서드로 만들어 진행하였다.

jdbc - JdbcTemplate 데이터 베이스 설정?

보시다시피, 처음 쓰는 메서드에도 약하고, 데이터 베이스에 연결 그리고 연동과 연결의 차이를 잘 모른다.

문제

        SimpleJdbcInsert jdbcInsert = new SimpleJdbcInsert(jdbcTemplate);
        jdbcInsert.withSchemaName("schedule").withTableName("schedule").usingGeneratedKeyColumns("id");

를 했을 때, 나타나는 오류이다.

해결

해당 문제의 원인은 정확히는 알 수 없었지만, 영빈 gpt의 힘으로 withSchemaName("schedule")을 삭제하여 해결할 수 있었다. 추측으로는 데이터 베이스 설정에서 데이터 소스의 url이 해당 데이터 베이스의 스키마 까지 이미 포함을 하고있어서 생긴 오류인 것으로 생각된다.

git - 줄바꿈 경고

문제

warning: in the working copy of 'build.gradle', LF will be replaced by CRLF the next time Git touches it
warning: in the working copy of 'src/main/resources/application.properties', LF will be replaced by CRLF the next time Git touches i

해당 문제는 확실하지는 않지만, jdbctempalte를 쓰고 생긴 오류인 것으로 기억한다. gpt에게 물어본 결과 해당 문제는 빌더의 추가로 줄바꿈의 설정이 서로 다를 때 나타난다고 한다.

ps CRLF: 윈도우에서 사용하는 줄바꿈 방식.

해결

git config --global core.autocrlf true Git에서 자동 변환을 CRLF로 맞춰주는 명령어, 해당 명령어는 윈도우일 때, 적합하다고 한다.

jdbc - ResultSet.update() 컴파일 오류

문제와 해결

resultSet.update 해당 메서드를 사용시, 마지막에 resultSet.updateRow();를 해줘야 resultSet.update 로 수정한 값들이 다시 재 저장이 된다.

jdbc - ResultSet

문제와 해결

 PreparedStatement ps = connection.prepareStatement(sql,
                ResultSet.TYPE_SCROLL_SENSITIVE,
                ResultSet.CONCUR_UPDATABLE);

Statement 객체를 생성할 때, ResultSet의 동시성과 유형을 설정? 해야 한다고 한다... 무슨 말인지 모르겠다. - 메모

째든 그래서, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE 추가

API - PathVariable

문제

public ResponseEntity<ResponseDto> test(@PathVariable Long id) throws SQLException, ClassNotFoundException {

        // 서비스 호출
        ResponseDto responseDtos = scheduleViewService.scheduleView(id);

        return new ResponseEntity<>(responseDtos, HttpStatus.OK);
    }

@PathVariable Long id 으로 했을 때, 오류!

해당 부분은 강의의 내용을 그대로 따라 했던거 같은데 어떤 이유에서인지, 명시를 해달라고 한다.

해결

public ResponseEntity<ResponseDto> test(@PathVariable("id") Long id) throws SQLException, ClassNotFoundException {

        // 서비스 호출
        ResponseDto responseDtos = scheduleViewService.scheduleView(id);

        return new ResponseEntity<>(responseDtos, HttpStatus.OK);       
    }

@Transactional

@Transactional
    public ScheduleResponseDto postSchedule(ScheduleRequestDto dto,String email) {

        Optional<User> optionalUser = usereRepository.findByEmail(email);
        // optionalUser.orElseThrow(()-> new ResponseStatusException(HttpStatus.NOT_FOUND,"로그인 후 이용가능 합니다." )); - 이미 로그인이 된 상태이므로 생략
        User user = optionalUser.get();

        Schedule schedule = scheduleRepository.save(new Schedule(user,dto.getTitle(), dto.getContents())); // 새로만든다 - 세팅
        //TODO Schedule 생성시에 user의 정보를 담아주지 않으면 schedule 테이블의 user_id 가 널 값을 가지게 된다. - 놓치지 쉬운 부분!!
        // 연관성을 부여하고 대입을 안하면 말짱황 // 1번째 시도 requestDto에 user_id 값을 넣으려했지만, 생성자의 실행문을 어떻게 채워야할지 감이 안잡힘
        // 그래서 user 객체를 넘겨줌
        return new ScheduleResponseDto(
                user.getUserName(), schedule.getTitle(),
                schedule.getContents(),schedule.getFixdate(),
                schedule.getFlexdate()
        );
    }

해당 코드는 수정한 코드로 이전에 @Transactional 어노테이션이 없다고 생각해보자!

그리고 해당 오류는 컴파일 오류라 하기도 그렇고, exception 에 포함 된다고 하기 어려워, 해당 내용을 적어야하나 고민하다 적는다!

문제

해당코드에서 문제는 update 가 db에 저장이 되지 않고, 조회만 한다는 것이였다!

JPA 영속성 컨텍스트의 범위 곧, 생명주기를 제대로 파악하지 못해서 난 오류?이다.

영속성컨텍스트도 싱클톤이 생명주기를 가지 듯, 비슷한 개념을 가지고 있다.

영속성컨텍스트를 배웠으면 알듯이 컨텍스트 밖에서 일어나는 것은 비영속성으로 db 데이터에 어떤 영향도 주지 못한다!

그래서 영속성컨텍스트가 중요한데, 해당 코드에서 난 1차캐씽에 조회한 db 데이터가 저장되고, 바로 update 쿼리가 실행되는 줄 알았으나...

이때 영속성 컨텍스트는 소멸한다...

해결

확실하게 영속성컨텍스트의 범위?를 모르겠으면, @Transactional 어노테이션을 붙여주여 하나의 작업 단위로 만들어주는게 정신 건강에 이로울 것으로 생각된다.

--- 🚩 메모
추가적으로 flush를 활용해서, 해당 문제를 해결할 수 있을 것 같다는 막연한 생각이 드는 데, 이는 공부를 해봐야 알 거 같다!
메모 🚩 ---

JPA - entity 연관 관계

    @ManyToOne
    @JoinColumn(name="user_id")
    //TODO 유저 클래스의 id와 schedule 컬럼에 user_id 이 만들어져 연관관계를 가진다.
    private User user;

//  TODO 기본 틀
//    @ManyToOne
//    @JoinColumn(name = "member_id")
//    private Member member;

    public Schedule(User user,String title, String contents) {
        this.user = user;
        this.title = title;
        this.contents = contents;
    }

해당 코드는 수정한 코드로 이전에 Schedule 생성자의 매개변수에서 user 가 없다고 생각해보자!

그리고 위 코드 또한, 컴파일 오류라 하기도 그렇고, exception 에 포함 된다고 하기 어려워, 해당 내용을 적어야하나 고민하다 적는다!

문제

entity 패키지에 각 entity 들의 연관 관계(단방향으로)를 잘 설정해주고, service에서 schedule 객체를 생성했을 때, 연관 관계가 데이터 상에서 실직적으로는 연관 관계가 없는 것으로 나타났다!

모르고 위처럼 처음 만들었을 때, 저장된 Schedule 객체를 조회 시, user 에 대한 정보는 null 값으로 나오게 되는 문제가 생겼다.

즉 위에서 말한거 처럼 데이터 상에서 실직적으로는 연관 관계가 없는 것으로 나타났다!

해결

이는 초반 코드에서 연관 관계 설정한 User 객체를 Schedule의 객체 생성자에 매개변수에 넣지 않아서 생겼던 문제였다.

간단하게 해당 객체를 생성자에 넣어주면 해결 되는 문제였다!

이처럼 생성자에 연관관계를 가지는 객체를 넣어줌으로써 진정으로 저장된 데이터가 참조를 할 수 있게 끔 되는 것이다!

ps

  • 1:다 관계에서 다 에 @ManyToOne 어노테이션을 붙이고, @JoinCloumn 어노테이션을 사용하여 연관관계를 설정한다.
  • 단방향으로 설정(@ManyToOne 만을 사용 o , @OneToMany 어노테이션은 사용 x) 했을 시, 1 을 조회 할 수 있다!
profile
Spring_4

0개의 댓글