본문 바로가기

개발하면서 겪은 어려움들

Redis JPA 연동하기 에러편 - Did you forget to provide one using @Id

728x90

현재 나는 코들린을 쓰고 있으며 버전은 아래와 같다.

 val kotlinVersion = "1.9.0"
    kotlin("jvm") version kotlinVersion
    kotlin("plugin.spring") version kotlinVersion apply false
    kotlin("plugin.jpa") version kotlinVersion apply false
    id("org.springframework.boot") version "3.1.1" apply false
    id("io.spring.dependency-management") version "1.1.0"
    id("org.jlleitschuh.gradle.ktlint") version "11.3.1"

 

Redis를 처음 해보니까 여러 블로그들을 보면서 Entity를 만들었고 코드는 아래와 같았다.

@Id는 다른 JPA Entity처럼 존재해야 했고, Indexed를 추가해야 해당 값으로 검색이 가능하다 하니 추가했다.

나는 이메일로 검색해야 될 일이 있었기 때문이다.... findById같은거 까먹고 저기에만 꽂혀있었음. 패키지 이름은 회사가 들어있어서 가림

package 패키지 이름

import jakarta.persistence.Id
import org.springframework.data.redis.core.RedisHash
import org.springframework.data.redis.core.TimeToLive
import org.springframework.data.redis.core.index.Indexed
import java.util.concurrent.TimeUnit

@RedisHash(value = "auth")
class AuthenticationToken(

    @Indexed // 값으로 검색할 시 추가
    val email: String,

    var token: String,

    @TimeToLive(unit = TimeUnit.HOURS)
    var ttl: Long = 1,

    @Id // 키값이 되며 refresh_token:{id}위치에 auto-increment
    var id: String = ""
)

 

근데 이렇게 넣으면 자꾸 redis에 이상하게 들어갔다.

나는 이메일, 토큰값, 만료시간이 필요한데 안꺼내졌다..

그리고 get으로 꺼내지지도 않았다. hash로 저장되지도 않았다. 그리고 왜 auth:에 만료시간이 설정되는건지..?

내가 원하던 그림은 auth:email:user222@test.comhash type이어야 했다.

127.0.0.1:6379> keys *
1) "auth:"
2) "auth:email:user222@test.com"
3) "auth::idx"
4) "auth"
127.0.0.1:6379> get auth:email:user222@test.com
(error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> hgetall auth:email:user222@test.com
(error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> HGETALL auth:email:user222@test.com
(error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> type "auth:email:user222@test.com
Invalid argument(s)
127.0.0.1:6379> type auth:email:user222@test.com
set
127.0.0.1:6379> smembers auth:email:user222@test.com
1) ""
127.0.0.1:6379> ttl auth::idx
(integer) -1
127.0.0.1:6379> ttl auth:
(integer) 3531

GPT한테 물어봐도 니가 저장 2번하는거 아니냐 시전.. + 원하는 답을 찾을 수 없었음

 

 

나는 기본 Id는 무조건 존재해야 했고 이메일은 따로 컬럼으로 써야 하는 줄 알았는데 !!! 아니였다.

그래서 삽질 끝에 아래 코드로 변경했는데, 안되는거다...? 

package 패키지 이름

import jakarta.persistence.Id
import org.springframework.data.redis.core.RedisHash
import org.springframework.data.redis.core.TimeToLive
import java.util.concurrent.TimeUnit

@RedisHash(value = "auth")
class AuthenticationToken(

    @Id
    val email: String,

    var token: String,

    @TimeToLive(unit = TimeUnit.HOURS)
    var ttl: Long = 1,
)
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'authenticationServiceImpl' defined in file [경로/authentication/service/AuthenticationServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'authenticationTokenRepository' defined in 패키지 이름.repository.AuthenticationTokenRepository defined in 
@EnableRedisRepositories declared on RedisRepositoriesRegistrar.
EnableRedisRepositoriesConfiguration: Entity 패키지 이름.authentication.domain.AuthenticationToken requires to have an explicit id field; Did you forget to provide one using @Id

 

이런 에러가 뜨는거다.... @EnableRedisRepositories는 RedisConfig 클래스에서 사용한다.

그래서 아니 아이디가 있는데 왜 안돼? 싶은데 에러 메세지를 보고 혹시나 해서 Import 패키지를 변경했다.

import jakarta.persistence.Id
		↓
import org.springframework.data.annotation.Id

 

 

그랬더니 잘 된다!

그래서 현재 코드는 이렇다. 

package 패키지 이름

import org.springframework.data.annotation.Id
import org.springframework.data.redis.core.RedisHash
import org.springframework.data.redis.core.TimeToLive
import java.util.concurrent.TimeUnit

@RedisHash(value = "auth")
class AuthenticationToken(

    @Id
    val email: String,

    var token: String,

    @TimeToLive(unit = TimeUnit.HOURS)
    var ttl: Long = 1,
)

 

package 패키지 이름

import com.stclab.cloud.cloudapi.authentication.domain.AuthenticationToken
import org.springframework.data.repository.CrudRepository
import org.springframework.stereotype.Repository

@Repository
interface AuthenticationTokenRepository : CrudRepository<AuthenticationToken, String> {
    fun save(authenticationToken: AuthenticationToken): AuthenticationToken
}

redis에도 내가 원하는대로 잘 들어간다.

hash type으로 저장이 되었고 value를 보면 잘 들어갔다.

Redis Value값 확인
- string: GET 명령어 사용
- hash: HGETALL 명령어 사용
- ist: LRANGE 명령어 사용
- set: SMEMBERS 명령어 사용
- zset: ZRANGE 또는 관련된 다른 명령어 사용
127.0.0.1:6379> keys *
1) "auth:user222@test.com"
2) "auth"
127.0.0.1:6379> keys *
1) "auth:user222@test.com"
2) "auth"
127.0.0.1:6379> hgetall auth:user222@test.com
1) "ttl"
2) "1"
3) "token"
4) "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyMjIyQHN0Y2xhYi5jb20iLCJlbWFpbCI6InVzZXIyMjJAc3RjbGFiLmNvbSJ9.rXP_99rmxtlEa0Mu7u_KEFjv5xHru0M9HFGo_O2f3F4"
5) "_class"
6) "패키지이름.domain.AuthenticationToken"
7) "email"
8) "user222@test.com"
127.0.0.1:6379> type auth
set
127.0.0.1:6379> smembers auth
1) "user222@test.com"
127.0.0.1:6379> ttl auth:user222@test.com
(integer) 214

 

ttl도 잘 적용되었다. 214초 남았다!

또 이메일이 Id이다 보니 repository에서 findById로 검색도 잘 됐다.

 

결론은, 자세한 이유는 아직 파악을 못했다. 내가 봤던 거의 모든 블로그에도 jakarta로 import 되어 있었다..

@EnableRedisRepositories는 스프링프레임워크에서 사용하는거라서 그런가? 싶기도 하고..

아무튼 redis를 jpa로 구현하면서 Did you forget to provide one using @Id에러를 발견한다면

Id Import를 jakarta에서 springframework 바꿔보길 추천한다.

728x90