JPA 및 휴지 상태를 사용하여 MySQL JSON 열을 Java 엔티티 속성에 매핑하는 방법
MySQL 컬럼이 JSON 타입으로 선언되어 있는데 JPA/Hibernate로 매핑하는 데 문제가 있습니다.백엔드에서 스프링 부츠를 사용하고 있습니다.
다음은 제 코드의 일부입니다.
@Entity
@Table(name = "some_table_name")
public class MyCustomEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(name = "json_value")
private JSONArray jsonValue;
프로그램에서 오류를 반환하고 열을 매핑할 수 없다는 메시지를 표시합니다.
mysql 테이블에서 열은 다음과 같이 정의됩니다.
json_value JSON NOT NULL;
다음과 같이 하는 것이 좋습니다.
- Map에서 String으로 변환기(아트리뷰트 변환기)를 작성하거나 그 반대도 마찬가지입니다.
- Map을 사용한 도메인(엔티티) 클래스의 mysql JSON 열 유형 매핑
암호는 아래입니다.
Json ToMap Converted.java
@Converter
public class JsonToMapConverter
implements AttributeConverter<String, Map<String, Object>>
{
private static final Logger LOGGER = LoggerFactory.getLogger(JsonToMapConverter.class);
@Override
@SuppressWarnings("unchecked")
public Map<String, Object> convertToDatabaseColumn(String attribute)
{
if (attribute == null) {
return new HashMap<>();
}
try
{
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(attribute, HashMap.class);
}
catch (IOException e) {
LOGGER.error("Convert error while trying to convert string(JSON) to map data structure.");
}
return new HashMap<>();
}
@Override
public String convertToEntityAttribute(Map<String, Object> dbData)
{
try
{
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(dbData);
}
catch (JsonProcessingException e)
{
LOGGER.error("Could not convert map to json string.");
return null;
}
}
}
도메인(엔티티 매핑) 클래스의 일부
...
@Column(name = "meta_data", columnDefinition = "json")
@Convert(attributeName = "data", converter = JsonToMapConverter.class)
private Map<String, Object> metaData = new HashMap<>();
...
이 솔루션은 나에게 완벽하게 효과가 있다.
이러한 타입을 모두 수동으로 작성할 필요는 없습니다.Maven Central을 통해 입수할 수 있는 것은 다음과 같습니다.
<dependency> <groupId>com.vladmihalcea</groupId> <artifactId>hibernate-types-52</artifactId> <version>${hibernate-types.version}</version> </dependency>
자, 이제 모든 것이 어떻게 돌아가는지 설명하겠습니다.
다음 엔티티가 있다고 가정합니다.
@Entity(name = "Book")
@Table(name = "book")
@TypeDef(
name = "json",
typeClass = JsonType.class
)
public class Book {
@Id
@GeneratedValue
private Long id;
@NaturalId
private String isbn;
@Type(type = "json")
@Column(columnDefinition = "json")
private String properties;
//Getters and setters omitted for brevity
}
위의 코드 스니펫에서 다음 두 가지를 주의해 주십시오.
- 그
@TypeDef
새로운 커스텀 휴지 타입을 정의하는 데 사용됩니다.json
이것은, 에 의해서 처리됩니다. - 그
properties
Atribute에는json
컬럼 타입으로 매핑되어 있습니다.String
바로 그거야!
엔티티를 저장하는 경우:
Book book = new Book();
book.setIsbn("978-9730228236");
book.setProperties(
"{" +
" \"title\": \"High-Performance Java Persistence\"," +
" \"author\": \"Vlad Mihalcea\"," +
" \"publisher\": \"Amazon\"," +
" \"price\": 44.99" +
"}"
);
entityManager.persist(book);
휴지 상태에서는 다음 SQL 문이 생성됩니다.
INSERT INTO
book
(
isbn,
properties,
id
)
VALUES
(
'978-9730228236',
'{"title":"High-Performance Java Persistence","author":"Vlad Mihalcea","publisher":"Amazon","price":44.99}',
1
)
또한 다시 로드하여 수정할 수도 있습니다.
Book book = entityManager
.unwrap(Session.class)
.bySimpleNaturalId(Book.class)
.load("978-9730228236");
book.setProperties(
"{" +
" \"title\": \"High-Performance Java Persistence\"," +
" \"author\": \"Vlad Mihalcea\"," +
" \"publisher\": \"Amazon\"," +
" \"price\": 44.99," +
" \"url\": \"https://www.amazon.com/High-Performance-Java-Persistence-Vlad-Mihalcea/dp/973022823X/\"" +
"}"
);
다음 명령을 사용하여 최대 절전 모드로 전환UPDATE
설명:
SELECT b.id AS id1_0_
FROM book b
WHERE b.isbn = '978-9730228236'
SELECT b.id AS id1_0_0_ ,
b.isbn AS isbn2_0_0_ ,
b.properties AS properti3_0_0_
FROM book b
WHERE b.id = 1
UPDATE
book
SET
properties = '{"title":"High-Performance Java Persistence","author":"Vlad Mihalcea","publisher":"Amazon","price":44.99,"url":"https://www.amazon.com/High-Performance-Java-Persistence-Vlad-Mihalcea/dp/973022823X/"}'
WHERE
id = 1
깃헙에서 모든 코드를 사용할 수 있습니다.
@J. Wang이 응답할 수 없는 경우:
이 의존관계를 추가해 보세요(최대 절전 모드 5.1 및 5.0, 기타 버전 확인은 이쪽).
<dependency>
<groupId>com.vladmihalcea</groupId>
<artifactId>hibernate-types-5</artifactId>
<version>1.2.0</version>
</dependency>
엔티티에 이 행을 추가합니다.
@TypeDef(name = "json", typeClass = JsonStringType.class)
따라서 엔티티 클래스의 풀버전은 다음과 같습니다.
@Entity
@Table(name = "some_table_name")
@TypeDef(name = "json", typeClass = JsonStringType.class)
public class MyCustomEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Type( type = "json" )
@Column( columnDefinition = "json" )
private List<String> jsonValue;
}
spring boot 1.5.9 및 hibernate-types-5 1.2.0을 사용하여 코드를 테스트합니다.
json 배열 내의 값이 단순한 문자열일 경우 다음과 같이 수행할 수 있습니다.
@Type( type = "json" )
@Column( columnDefinition = "json" )
private String[] jsonValue;
헤릴 무라토비치의 대답은 좋지만JsonToMapConverter
구현해야 합니다.AttributeConverter<Map<String, Object>, String>
,것은 아니다.AttributeConverter<String, Map<String, Object>>
여기 나에게 맞는 코드가 있습니다.
@Slf4j
@Converter
public class JsonToMapConverter implements AttributeConverter<Map<String, Object>, String> {
@Override
@SuppressWarnings("unchecked")
public Map<String, Object> convertToEntityAttribute(String attribute) {
if (attribute == null) {
return new HashMap<>();
}
try {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(attribute, HashMap.class);
} catch (IOException e) {
log.error("Convert error while trying to convert string(JSON) to map data structure.", e);
}
return new HashMap<>();
}
@Override
public String convertToDatabaseColumn(Map<String, Object> dbData) {
try {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(dbData);
} catch (JsonProcessingException e) {
log.error("Could not convert map to json string.", e);
return null;
}
}
}
Kotlin에서는 위의 제안들을 다음과 같이 변형/조합하여 사용할 수 있었습니다.
@Entity
@Table(name = "product_menu")
@TypeDef(name = "json", typeClass = JsonStringType::class)
data class ProductMenu(
@Type(type = "json")
@Column(name = "menu_json", columnDefinition = "json")
@Convert(attributeName = "menuJson", converter = JsonToMapConverter::class)
val menuJson: HashMap<String, Any> = HashMap()
) : Serializable
import com.fasterxml.jackson.core.JsonProcessingException
import com.fasterxml.jackson.databind.ObjectMapper
import org.slf4j.LoggerFactory
import java.io.IOException
import javax.persistence.AttributeConverter
class JsonToMapConverter : AttributeConverter<String, HashMap<String, Any>> {
companion object {
private val LOGGER = LoggerFactory.getLogger(JsonToMapConverter::class.java)
}
override fun convertToDatabaseColumn(attribute: String?): HashMap<String, Any> {
if(attribute == null) {
return HashMap()
}
try {
val objectMapper = ObjectMapper()
@Suppress("UNCHECKED_CAST")
return objectMapper.readValue(attribute, HashMap::class.java) as HashMap<String, Any>
} catch (e: IOException) {
LOGGER.error("Convert error while trying to convert string(JSON) to map data structure.")
}
return HashMap()
}
override fun convertToEntityAttribute(dbData: HashMap<String, Any>?): String? {
return try {
val objectMapper = ObjectMapper()
objectMapper.writeValueAsString(dbData)
} catch (e: JsonProcessingException) {
LOGGER.error("Could not convert map to json string.")
return null
}
}
}
언급URL : https://stackoverflow.com/questions/44308167/how-to-map-a-mysql-json-column-to-a-java-entity-property-using-jpa-and-hibernate
'programing' 카테고리의 다른 글
spring-boot-configuration-processor란 무엇입니까?왜 사람들은 도서관에서 도서관을 제외할까?의존관계 트리에서는 왜 보이지 않는가? (0) | 2023.03.18 |
---|---|
스프링 부트 application.properties에서 신뢰 저장소 정보 지정 (0) | 2023.03.18 |
react-i18 next:initReactI18 next를 사용하여 i18 다음 인스턴스로 패스해야 합니다. (0) | 2023.03.18 |
테이블에서 값이 null이 아닌 열을 선택하려면 어떻게 해야 합니까? (0) | 2023.03.18 |
url 인수(쿼리 문자열)를 Angular의 HTTP 요청에 전달하려면 어떻게 해야 합니까? (0) | 2023.03.13 |