반응형

스프링부트에서 메일 발송 기능 구현 중 다음과 같은 에러가 발생하였다.

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'mailService': Unsatisfied dependency expressed through field 'javaMailSender'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.mail.javamail.JavaMailSender' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:596) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE] 
.
.
.
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.mail.javamail.JavaMailSender' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1646) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1205) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1166) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:593) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]

 

소스코드

기본적인 maven dependency추가 후 @Autowired했음

 

문제해결

@Bean으로 다음과 같이 protocol, host, port 지정 해줌

    @Bean
    public JavaMailSenderImpl mailSender() {
        JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();

        javaMailSender.setProtocol("smtp");
        javaMailSender.setHost("127.0.0.1");
        javaMailSender.setPort(25);

        return javaMailSender;
    }
반응형
반응형

스프링부트 with JPA 프로젝트 작업중 신기한게 로컬환경에서는 에러가 안났는데 alpha, real환경에만 배포하면 위와 같은 에러 메세지가 나왔다....

Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Either use @Param on all parameters except Pageable and Sort typed once, or none at all!

문제의 원인이 무었이었는고 하니...

JPA 에서 매개변수 2개를 받는 메서드에 한 변수에만 @Param을 지정해서 사용하여서 발생하였다...

jobId 매개변수에도 @Param을 명시적으로 주니 정상적으로 해결 되었다.

void upsertAnalysisData(@Param("jobId") int jobId, @Param("audience") AudienceAnalysis audienceAnalysis);

혹시나 비슷한 에러가 발생한다면 JPA Repository부분에 특정 매개변수에만 @Param을 주어서 사용하진 않았는지 확인해보자!

반응형
반응형
Cookie cookie = new Cookie("", "");
response.addCookie(cookie);

쿠키 생성시 위와 같이 name에 빈 값을 넣어 굽게 되면 다음과 같은 에러가 발생한다.

java.lang.IllegalArgumentException: Cookie name may not be null or zero length

고로 쿠키 네임에는 null이나 length가 0인 값이 들어 갈 수 없다!

반응형
반응형

DB에 넣으려는 값의 타입과 자바 모델 객체의 타입이 다를 때 발생

아래 에러로그를 보면 video_id 컬럼에서 에러가 나는데

DB에는 long(bigint) type인데 application에서는 video_id를 string type으로 처리하고 있었고

string type의 video_id를 DB에 insert 하려다 보니 에러 발생

java.sql.SQLException: Data truncated for column 'video_id' at row 1 at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:129) ~[mysql-connector-java-8.0.17.jar:8.0.17] at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97) ~[mysql-connector-java-8.0.17.jar:8.0.17] at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122) ~[mysql-connector-java-8.0.17.jar:8.0.17] at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:953) ~[mysql-connector-java-8.0.17.jar:8.0.17] at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1092) ~[mysql-connector-java-8.0.17.jar:8.0.17] at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1040) ~[mysql-connector-java-8.0.17.jar:8.0.17] at com.mysql.cj.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:1340) ~[mysql-connector-java-8.0.17.jar:8.0.17] at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:1025) ~[mysql-connector-java-8.0.17.jar:8.0.17] at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61) ~[HikariCP-3.2.0.jar:na] at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java) ~[HikariCP-3.2.0.jar:na] at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:175) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final] at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3192) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final] at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3706) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final] at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:90) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final] at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final] at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:478) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final] at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:356) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final] at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final] at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1483) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final] at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:512) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final] at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3321) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final] at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2517) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final] at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:447) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final] at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:178) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final] at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$300(JdbcResourceLocalTransactionCoordinatorImpl.java:39) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final] at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:271) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final] at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:104) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final] at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:533) ~[spring-orm-5.1.10.RELEASE.jar:5.1.10.RELEASE] at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:746) ~[spr
반응형
반응형

해당 글은 '실무로 배우는 시스템 성능 최적화' 책의 내용을 발췌한 내용입니다. 최근 해당 책을 읽다가 이전에 내가 했던 고민과 비슷한 사례에서 비롯한 성능 저하 사례가 있어 포스팅 해본다. 보통 스프링부트에서 API를 만들 때 RestTemplate을 만들어서 사용하실텐데 매번 RestTemplate객체를 new로 생성해서 사용해야하는지 싱글톤 객체로 만들어 놓고 사용해야 하는지 고민하던 때가 있었다. 처음 멋 모를 때는 API Controller마다 new로 생성해서 사용했었는데 RestTempalate가 스레드 간 공유해도 안전한 클래스라는걸 알고 난 이후에 @Bean으로 싱글톤 객체를 생성해 사용했었다. new 객체를 매번 생성할 때도 나는 아래와 같은 장애상황을 겪진 못했지만 아래와 같이 내부락이 발생할 수 있으므로 싱글톤 객체로 만들어 사용할 수 있도록 하자. 또한 @Bean 애노테이션으로 만든 싱글톤 객체보다 빈 대신 static을 사용한 싱글턴 구조를 만드는게 더 좋다고 하는데 궁금하시다면 조치부분을 참고.

스프링 프레임워크의 객체를 잘못 사용한 성능 저하 사례

현상

오픈 전 6시간 동안 진행하는 안정성 테스트 과정에서 1시간이 경과한 후 응답시간이 급격히 저하되는 현상이 발생했다.

접근 방식

오라클 JVM을 사용하고 있어 응답시간이 느려졌을 때 jstack으로 스택을 5회 수집해서 분석했다. 성능 저하 시 전체 사용자 요청을 처리 중인 스레드 중 90% 이상이 애플리케이션 내부 락 대기 중이었다.

시스템의 애플리케이션 서버는 프론트 서버와 백엔드 서버로 구성돼 있는데, 프론트 서버에 들어온 서비스 요청은 다시 HTTP를 사용해 다시 백엔드 업무 서버를 호출하는 구조다. 내부 락은 프론트 서버 내에서 백엔드 서버의 서비스를 호출할 때 사용하는 RestTemplate 객체를 생성하는 과정(RestTeamplate.init())에서 발생하고 있었다. 이에 RestTemplate 클래스에 대해 인터넷 검색을 한 결과, 애플리케이션에서 RestTemplate을 잘못 사용하고 있음을 알 수 있었다.

원인

스프링 프레임워크에서 제공하는 HTTP 클라이언트 템플릿인 RestTemplate 클래스는 객체 생성 시 내부에 무거운 Charset.availableCharsets 메서드가 실핸된다. 더구나 Charset.availableCharsets 메서드는 여러 스레드가 동시에 사용했을 때 스레드 간에 락 경합이 생겨서 급격한 성능 저하를 유발한다. HTTP로 백엔드 시스템의 서비스를 호출할 때마다 RestTemplate객체를 새로 생성해서 사용함으로써 Charset.availableCharsets 메서드에 의한 성능 저하가 발생한 것이다.

조치

RestTemplate은 스레드 간에 공유해도 안전한 클래스이므로 싱글턴 구조로 객체를 한 개만 생성한 후 스레드 간에 공유해서 사용하도록 수정한다. 그래서 객체 생성이 인스턴스마다 한 번만 이뤄져 락 경합이 제거됐다(RestTemplate 클래스를 스프링 프레임워크의 빈으로 사용할 수도 있으나 RestTemplate 클래스를 사용하는 MobileClient 클래스 또한 프레임워크의 일부라서 빈 대신 static을 사용한 싱글턴 구조를 만들었다.

결과

6시간 안정성 테스트 동안 응답시간이 증가하는 현상 없이 일정하게 유지됐다.

ref : 실무로 배우는 시스템 성능 최적화

반응형
반응형

mac로컬 환경에서 가끔 스프링부트 어플리케이션 실행시 다음과 같은 에러가 발생한다.

Unable to start embedded Tomcat servlet container 
_org.springframework.boot.context.embedded.EmbeddedServletContainerException_: Unable to start embedded Tomcat servlet container
org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer.start(_TomcatEmbeddedServletContainer.java:165_)
org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.startEmbeddedServletContainer(_EmbeddedWebApplicationContext.java:293_)
.
.
.
org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer.start(_TomcatEmbeddedServletContainer.java:159_)

... 10 common frames omitted

해결방법

maven clean, build 다시 하고 문제가 발생할 경우 다음과 같이 처리해준다. 

터미널 켜서 명령어 : lsof -n -i4TCP:8080 치고 pid확인해서 (어플리케이션 포트 설정이 8080인 경우)
kill -9 pid 로 해당 프로세스를 강제종료시켜주고 다시 실행해보자. 
반응형
반응형

토이프로젝트를 하던 중 쿠키에 특정 값을 만들어 굽는 작업이 필요했다.

따라서 HttpServletResponse에 addCookie를 하여 쿠키를 구워줬지만 브라우저 개발자도구에서 눈을 씻고 찾아봐도 보이지가 않았다...

 

문제는 Cookie의 path를 설정해주지 않아서였다...

 

쿠키의 path를 설정해주지 않으면 현재 경로에서만 only valid하도록 처리되기 때문에

리다이렉트 되면서 유효하지 않기에 사라져 버리는 것이다.

 

[ 문제코드 ]

쿠키에 setPath를 지정해주지 않음...

 

[ 문제 해결 ] 

setPath를 루트로 지정

 

ref : https://stackoverflow.com/questions/35828087/setting-cookie-not-working-in-spring-web-mvc-4

반응형
반응형

Spring boot에서 JPA를 이용해 Update query 개발시 다음과 같은 에러가 나는 경우가 발생

org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.hql.internal.QueryExecutionRequestException: Not supported for DML operations [update bng.moobe.entity.User u set u.nickname = :__$synthetic$__1 where u.email = :__$synthetic$__2]; nested exception is java.lang.IllegalStateException: org.hibernate.hql.internal.QueryExecutionRequestException: Not supported for DML operations [update bng.moobe.entity.User u set u.nickname = :__$synthetic$__1 where u.email = :__$synthetic$__2]
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:370) ~[spring-orm-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:255) ~[spring-orm-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:527) ~[spring-orm-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61) ~[spring-tx-5.1.9.RELEASE.jar:5.1.9.RELEASE]

 

JPA @Query를 사용해 update시에는 @Modifying annotation을 추가해주어야 한다.

하지만 이것으로 끝이 아니다...다시 실행해보면 이번엔 다음과 같은 에러 메세지가 발생한다.

org.springframework.dao.InvalidDataAccessApiUsageException: Executing an update/delete query; nested exception is javax.persistence.TransactionRequiredException: Executing an update/delete query

이 문제를 해결하기 위해서는 @Transactional 애노테이션도 함께 추가해주어야 한다.

@Transactional 애노테이션 추가

 

ref : https://stackoverflow.com/questions/10220262/updating-boolean-value-in-spring-data-jpa-using-query-with-hibernate

반응형
반응형

스프링이나 자바프로젝트에서 jdbc tempate으로 hive명령어 날릴 때 쿼리문에 ';'(세미콜론)을 붙혀 statement를 execute하지 않도록 하자. 세미콜론이 쿼리에 들어 있으면 다음과 같은 에러를 뱉을 것이다.

Caused by: org.apache.hive.service.cli.HiveSQLException: Error while compiling statement: FAILED: ParseException line 1:519 cannot recogni input near ';' '<EOF>' '<EOF>' in expression specification

        at org.apache.hive.service.cli.operation.Operation.toSQLException(Operation.java:326)

        at org.apache.hive.service.cli.operation.SQLOperation.prepare(SQLOperation.java:102)

        at org.apache.hive.service.cli.operation.SQLOperation.runInternal(SQLOperation.java:171)

        at org.apache.hive.service.cli.operation.Operation.run(Operation.java:268)

        at org.apache.hive.service.cli.session.HiveSessionImpl.executeStatementInternal(HiveSe

이유는 스택오버플로우의 답변으로 대신한다.


Using ; in a query for most databases doesn't work as it is usually not part of the statement syntax itself, but a terminator for command line or script input to separate statements. The command line or script processor sees a semi-colon as the signal that the statement is complete and can be sent to the server.
Also in JDBC a single statement prepare (or execute) should only be one actual statement so multiple statements are not allowed and so there is also no need to have a semi-colon, and as for some (most?) databases the semi-colon isn't part of the statement syntax, it is simply a syntax error to have one included.
If you want to execute multiple statements, you need to use separate executes. Technically, MySQL does have an option to support multiple executions which can be enabled by a connection property. This behavior is not compliant with the JDBC specification/API and makes your code less portable. See allowMultiQueries on Driver/Datasource Class Names, URL Syntax and Configuration Properties for Connector/J

--------

Having semicolons in JDBC statements is very error prone in general. Some JDBC drivers do not support this (e.g. IBM's JDBC driver for DB2 10.x throws an exception if you close your SQL statement with ";").

 

참고 : https://stackoverflow.com/questions/18515471/can-i-execute-multiple-queries-separated-by-semicolon-with-mysql-connector-j

반응형

+ Recent posts