Rad*_*Rad 17 java mysql orm json jpa
我们有一个包含大量列的大表.在我们转移到MySQL Cluster之后,由于以下原因无法创建表:
ERROR 1118(42000):行大小太大.所使用的表类型的最大行大小(不包括BLOB)是14000.这包括存储开销,请查看手册.您必须将某些列更改为TEXT或BLOB
举个例子:
@Entity @Table (name = "appconfigs", schema = "myproject")
public class AppConfig implements Serializable
{
@Id @Column (name = "id", nullable = false)
@GeneratedValue (strategy = GenerationType.IDENTITY)
private int id;
@OneToOne @JoinColumn (name = "app_id")
private App app;
@Column(name = "param_a")
private ParamA parama;
@Column(name = "param_b")
private ParamB paramb;
}
Run Code Online (Sandbox Code Playgroud)
它是用于存储配置参数的表.我想我们可以将一些列组合成一个并将其存储为JSON对象并将其转换为某个Java对象.
例如:
@Entity @Table (name = "appconfigs", schema = "myproject")
public class AppConfig implements Serializable
{
@Id @Column (name = "id", nullable = false)
@GeneratedValue (strategy = GenerationType.IDENTITY)
private int id;
@OneToOne @JoinColumn (name = "app_id")
private App app;
@Column(name = "params")
//How to specify that this should be mapped to JSON object?
private Params params;
}
Run Code Online (Sandbox Code Playgroud)
我们定义的地方:
public class Params implements Serializable
{
private ParamA parama;
private ParamB paramb;
}
Run Code Online (Sandbox Code Playgroud)
通过使用它,我们可以将所有列合并为一个并创建我们的表.或者我们可以将整个表分成几个表.我个人更喜欢第一种解决方案.
无论如何我的问题是如何映射Params列,它是文本并包含Java对象的JSON字符串?
Ale*_*ini 43
您可以使用JPA转换器将您的实体映射到数据库.只需在params字段中添加与此类似的注释:
@Convert(converter = JpaConverterJson.class)
Run Code Online (Sandbox Code Playgroud)
然后以类似的方式创建类(这会转换一个通用的Object,你可能想要专门化它):
@Converter(autoApply = true)
public class JpaConverterJson implements AttributeConverter<Object, String> {
private final static ObjectMapper objectMapper = new ObjectMapper();
@Override
public String convertToDatabaseColumn(Object meta) {
try {
return objectMapper.writeValueAsString(meta);
} catch (JsonProcessingException ex) {
return null;
// or throw an error
}
}
@Override
public Object convertToEntityAttribute(String dbData) {
try {
return objectMapper.readValue(dbData, Object.class);
} catch (IOException ex) {
// logger.error("Unexpected IOEx decoding json from database: " + dbData);
return null;
}
}
}
Run Code Online (Sandbox Code Playgroud)
就是这样:您可以使用此类将任何对象序列化为表中的json.
小智 9
如果在响应客户端(如rest API响应)时需要将json类型属性映射为json格式,添加@JsonRawValue如下:
@Column(name = "params", columnDefinition = "json")
@JsonRawValue
private String params;
Run Code Online (Sandbox Code Playgroud)
这可能不会为服务器端使用做 DTO 映射,但客户端会得到正确格式化为 json 的属性。
正如我在本文中解释的那样,JPA AttributeConverter太局限了,无法映射JSON对象类型,特别是如果您要将其保存为JSON二进制文件。
您不必手动创建所有这些类型,只需使用以下依赖关系通过Maven Central获取它们:
Run Code Online (Sandbox Code Playgroud)<dependency> <groupId>com.vladmihalcea</groupId> <artifactId>hibernate-types-52</artifactId> <version>${hibernate-types.version}</version> </dependency>有关更多信息,请查看hibernate-types开源项目。
现在,解释一下它是如何工作的。
我写了一篇关于如何在PostgreSQL和MySQL上映射JSON对象的文章。
对于PostgreSQL,您需要以二进制形式发送JSON对象:
public class JsonBinaryType
extends AbstractSingleColumnStandardBasicType<Object>
implements DynamicParameterizedType {
public JsonBinaryType() {
super(
JsonBinarySqlTypeDescriptor.INSTANCE,
new JsonTypeDescriptor()
);
}
public String getName() {
return "jsonb";
}
@Override
public void setParameterValues(Properties parameters) {
((JsonTypeDescriptor) getJavaTypeDescriptor())
.setParameterValues(parameters);
}
}
Run Code Online (Sandbox Code Playgroud)
该JsonBinarySqlTypeDescriptor如下所示:
public class JsonBinarySqlTypeDescriptor
extends AbstractJsonSqlTypeDescriptor {
public static final JsonBinarySqlTypeDescriptor INSTANCE =
new JsonBinarySqlTypeDescriptor();
@Override
public <X> ValueBinder<X> getBinder(
final JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicBinder<X>(javaTypeDescriptor, this) {
@Override
protected void doBind(
PreparedStatement st,
X value,
int index,
WrapperOptions options) throws SQLException {
st.setObject(index,
javaTypeDescriptor.unwrap(
value, JsonNode.class, options), getSqlType()
);
}
@Override
protected void doBind(
CallableStatement st,
X value,
String name,
WrapperOptions options)
throws SQLException {
st.setObject(name,
javaTypeDescriptor.unwrap(
value, JsonNode.class, options), getSqlType()
);
}
};
}
}
Run Code Online (Sandbox Code Playgroud)
而JsonTypeDescriptor像这样:
public class JsonTypeDescriptor
extends AbstractTypeDescriptor<Object>
implements DynamicParameterizedType {
private Class<?> jsonObjectClass;
@Override
public void setParameterValues(Properties parameters) {
jsonObjectClass = ( (ParameterType) parameters.get( PARAMETER_TYPE ) )
.getReturnedClass();
}
public JsonTypeDescriptor() {
super( Object.class, new MutableMutabilityPlan<Object>() {
@Override
protected Object deepCopyNotNull(Object value) {
return JacksonUtil.clone(value);
}
});
}
@Override
public boolean areEqual(Object one, Object another) {
if ( one == another ) {
return true;
}
if ( one == null || another == null ) {
return false;
}
return JacksonUtil.toJsonNode(JacksonUtil.toString(one)).equals(
JacksonUtil.toJsonNode(JacksonUtil.toString(another)));
}
@Override
public String toString(Object value) {
return JacksonUtil.toString(value);
}
@Override
public Object fromString(String string) {
return JacksonUtil.fromString(string, jsonObjectClass);
}
@SuppressWarnings({ "unchecked" })
@Override
public <X> X unwrap(Object value, Class<X> type, WrapperOptions options) {
if ( value == null ) {
return null;
}
if ( String.class.isAssignableFrom( type ) ) {
return (X) toString(value);
}
if ( Object.class.isAssignableFrom( type ) ) {
return (X) JacksonUtil.toJsonNode(toString(value));
}
throw unknownUnwrap( type );
}
@Override
public <X> Object wrap(X value, WrapperOptions options) {
if ( value == null ) {
return null;
}
return fromString(value.toString());
}
}
Run Code Online (Sandbox Code Playgroud)
现在,您需要在类级别或在package-info.java包级别描述符中声明新类型:
@TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
Run Code Online (Sandbox Code Playgroud)
实体映射将如下所示:
@Type(type = "jsonb")
@Column(columnDefinition = "json")
private Location location;
Run Code Online (Sandbox Code Playgroud)
如果您使用的是Hibernate 5或更高版本,则Postgre92Dialect自动注册该JSON类型。
否则,您需要自己注册:
public class PostgreSQLDialect extends PostgreSQL91Dialect {
public PostgreSQLDialect() {
super();
this.registerColumnType( Types.JAVA_OBJECT, "json" );
}
}
Run Code Online (Sandbox Code Playgroud)
小智 5
很简单
@Column(name = "json_input", columnDefinition = "json")
private String field;
Run Code Online (Sandbox Code Playgroud)
并在 mysql 数据库中您的列 'json_input' json 类型
| 归档时间: |
|
| 查看次数: |
56328 次 |
| 最近记录: |