使用 JPA/Hibernate 将 BigDecimal[][] 保存到 MySQL 数据库
Persisting BigDecimal[][] to MySQL database by using JPA/Hibernate
我需要使用 Hibernate 将 BigDecimal[][] 类型保存到 MySQL 数据库。我不知道该怎么做。我试过这个:
@Getter
@Setter
@ToString
@RequiredArgsConstructor
@Embeddable
@TypeDef(name = "coordinates_array",
typeClass = BigDecimalArrayType.class)
public class Geometry {
private String type;
@Type(
type = "coordinates_array",
parameters = @org.hibernate.annotations.Parameter(
name = "sql_array_type",
value = "BigDecimal"
)
)
@Column(
name = "coordinates",
columnDefinition = "BigDecimal[][]"
)
BigDecimal[][] coordinates;}
没有 BigDecimalArrayType class。我如何定义 BigDecimalArrayType?或者有什么可以替代的吗?
也许你可以将 BigDecimal[][] 转换成一个 blob,如果你想保持原样,而不是将 rows/columns 分解到适当的表中。
如我的评论所述,由于您不想以“纯文本”方式保存数组,您可以按照这种方式进行操作。
使用两个字段,一个是持久的(数据库的一部分),另一个是暂时的(仅是应用程序逻辑的一部分)。
持久性将是您的 CoordinateHolder
的 byte[]
,短暂性将是 BigDecimal[][]
.
这里是CoordinateHolder
的class。如您所见,我正在使用 @Transient
来禁止保留字段。
@Embeddable
public class CoordinateHolder implements Serializable
{
@Transient
private BigDecimal[][] transientCoordinates; // Will not be saved in the DB, is part only of the business logic.
public BigDecimal[][] getTransientCoordinates()
{
return transientCoordinates;
}
public void setTransientCoordinates(BigDecimal[][] transientCoordinates)
{
this.transientCoordinates = transientCoordinates;
}
}
这之后让我们来看看实体 class:
@Entity(name = "test_name")
public class TestEntity
{
// Your id...
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Embedded
private CoordinateHolder coordinateHolder;
@Lob
@Column(name = "coordinates", columnDefinition = "BLOB")
private byte[] blobCoordinates;
public void setCoordinates(BigDecimal[][] arr)
{
if (coordinateHolder == null)
{
coordinateHolder = new CoordinateHolder();
}
coordinateHolder.setTransientCoordinates(arr);
}
public BigDecimal[][] getCoordinates()
{
if (coordinateHolder == null)
{
return null;
}
return coordinateHolder.getTransientCoordinates();
}
// This can also be done through Entity listeners which actually do the same thing
// Pre persist is always performed before persisting this entity
@PrePersist
public void prePersisting()
{
System.out.println("Hey I am being persisted. And now I am turning my transient coordinates into BLOB for the db");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out;
try
{
out = new ObjectOutputStream(bos);
out.writeObject(coordinateHolder);
out.flush();
blobCoordinates = bos.toByteArray();
} catch (Exception e)
{
// Do smth with your exception...
e.printStackTrace();
} finally
{
try
{
bos.close();
} catch (IOException ignored)
{
// ignore close exception
}
}
}
// Perform after loading...
@PostLoad
public void postLoading()
{
System.out.println("Hey I am being fetched, I am turning my BLOB into the array holder so that you can use it in your app");
ByteArrayInputStream bis = new ByteArrayInputStream(this.getBlobCoordinates());
ObjectInput in = null;
try
{
in = new ObjectInputStream(bis);
CoordinateHolder o = (CoordinateHolder) in.readObject();
this.setCoordinateHolder(o);
}
catch (Exception e)
{
// Do smth with your exception...
e.printStackTrace();
}
finally
{
try
{
if (in != null)
{
in.close();
}
} catch (IOException ex)
{
// ignore close exception
}
}
}
... Further getters and setters...
}
代码有注释说明,应该可以看懂。这使您可以坚持您所需要的。
我需要使用 Hibernate 将 BigDecimal[][] 类型保存到 MySQL 数据库。我不知道该怎么做。我试过这个:
@Getter
@Setter
@ToString
@RequiredArgsConstructor
@Embeddable
@TypeDef(name = "coordinates_array",
typeClass = BigDecimalArrayType.class)
public class Geometry {
private String type;
@Type(
type = "coordinates_array",
parameters = @org.hibernate.annotations.Parameter(
name = "sql_array_type",
value = "BigDecimal"
)
)
@Column(
name = "coordinates",
columnDefinition = "BigDecimal[][]"
)
BigDecimal[][] coordinates;}
没有 BigDecimalArrayType class。我如何定义 BigDecimalArrayType?或者有什么可以替代的吗?
也许你可以将 BigDecimal[][] 转换成一个 blob,如果你想保持原样,而不是将 rows/columns 分解到适当的表中。
如我的评论所述,由于您不想以“纯文本”方式保存数组,您可以按照这种方式进行操作。
使用两个字段,一个是持久的(数据库的一部分),另一个是暂时的(仅是应用程序逻辑的一部分)。
持久性将是您的 CoordinateHolder
的 byte[]
,短暂性将是 BigDecimal[][]
.
这里是CoordinateHolder
的class。如您所见,我正在使用 @Transient
来禁止保留字段。
@Embeddable
public class CoordinateHolder implements Serializable
{
@Transient
private BigDecimal[][] transientCoordinates; // Will not be saved in the DB, is part only of the business logic.
public BigDecimal[][] getTransientCoordinates()
{
return transientCoordinates;
}
public void setTransientCoordinates(BigDecimal[][] transientCoordinates)
{
this.transientCoordinates = transientCoordinates;
}
}
这之后让我们来看看实体 class:
@Entity(name = "test_name")
public class TestEntity
{
// Your id...
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Embedded
private CoordinateHolder coordinateHolder;
@Lob
@Column(name = "coordinates", columnDefinition = "BLOB")
private byte[] blobCoordinates;
public void setCoordinates(BigDecimal[][] arr)
{
if (coordinateHolder == null)
{
coordinateHolder = new CoordinateHolder();
}
coordinateHolder.setTransientCoordinates(arr);
}
public BigDecimal[][] getCoordinates()
{
if (coordinateHolder == null)
{
return null;
}
return coordinateHolder.getTransientCoordinates();
}
// This can also be done through Entity listeners which actually do the same thing
// Pre persist is always performed before persisting this entity
@PrePersist
public void prePersisting()
{
System.out.println("Hey I am being persisted. And now I am turning my transient coordinates into BLOB for the db");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out;
try
{
out = new ObjectOutputStream(bos);
out.writeObject(coordinateHolder);
out.flush();
blobCoordinates = bos.toByteArray();
} catch (Exception e)
{
// Do smth with your exception...
e.printStackTrace();
} finally
{
try
{
bos.close();
} catch (IOException ignored)
{
// ignore close exception
}
}
}
// Perform after loading...
@PostLoad
public void postLoading()
{
System.out.println("Hey I am being fetched, I am turning my BLOB into the array holder so that you can use it in your app");
ByteArrayInputStream bis = new ByteArrayInputStream(this.getBlobCoordinates());
ObjectInput in = null;
try
{
in = new ObjectInputStream(bis);
CoordinateHolder o = (CoordinateHolder) in.readObject();
this.setCoordinateHolder(o);
}
catch (Exception e)
{
// Do smth with your exception...
e.printStackTrace();
}
finally
{
try
{
if (in != null)
{
in.close();
}
} catch (IOException ex)
{
// ignore close exception
}
}
}
... Further getters and setters...
}
代码有注释说明,应该可以看懂。这使您可以坚持您所需要的。