使用描述和密钥保存枚举 - MySQL 和 Java



我有一个枚举如下

public enum OrderStatusEnum {
ACTIVE("A","Active Order"),
AWAITING("I","Awaiting Order")
}

我想在数据库中保存活动,等待。在查询时也检索相同的内容

当实体被设置为枚举并通过 Jdbc 模板保存时,我面临异常。数据截断异常

问题

  1. 我是否需要在数据库中保存活动/等待或活动订单/等待订单?
  2. 如何使用 Jdbc 模板使用本机 SQL 查询保存枚举值

我们正在使用MapSqlParameterSource.

谢谢。

1)你可以存储"ACTIVE/AWAITING"并使用valueOf枚举方法。

优点:

  1. 无需为映射方法编写额外的代码 - 使用标准enumvalueOf.
  2. 数据库中的值更易于人类阅读
  3. 强制所有
  4. 枚举的常量名称都是唯一的,因此消除了这种类型的错误

缺点:

  1. 可能有更多的空间将这些值存储在数据库中
  2. 重命名枚举的常量将导致需要更新数据库记录

例如:

将数据插入表中:

jdbcTemplate.update(
"INSERT INTO orders (id, order_status, description) VALUES (?, ?, ?)",
new Object[] {
order.getId(),
order.getStatus().toString(),
order.getDescription()
}
);

加载数据:

public List<Order> findAllOrders() 
{
return jdbcTemplate.query(
"SELECT * FROM orders",
new String[]{},
(rs, rowNum) -> new Order(rs.getInt("id"), OrderStatus.valueOf(rs.getString("order_status")), rs.getString("description"))
);
}

这里的巧妙之处在于你不需要编写valueOf方法,它存在于任何枚举中,请参阅 https://docs.oracle.com/javase/8/docs/api/java/lang/Enum.html#valueOf-java.lang.Class-java.lang.String-

2)您可以使用shortName(例如"A"),但您需要遍历所有枚举才能找到正确的枚举。

优点:

  1. 在数据库中存储这些值的空间可能更少

缺点:

  1. 需要为映射方法编写额外的代码
  2. 数据库中的值远不如人类可读
  3. 有可能添加 2 个具有相同短名称的枚举常量,这将导致数据损坏

例如:

为了节省使用order.getStatus().getShortName()
用于加载使用:getStatus(rs.getString("order_status"))

private OrderStatus getStatus(String shortName)
{
switch(shortName)
{
case "A":
return OrderStatus.ACTIVE;
case "I":
return OrderStatus.AWAITING;
default:
throw new RuntimeException("Cannot find order status for short name: " + shortName);
}
}

更新OrderStatus枚举声明:

public enum OrderStatus
{
ACTIVE("A","Active Order"),
AWAITING("I","Awaiting Order");
private String shortName;
private String description;
private OrderStatus(String shortName, String description)
{
this.shortName = shortName;
this.description = description;
}
public String getShortName()
{
return shortName;
}
public String getDescription()
{
return description;
}   
}

更新 2:OrderStatus 与其所需的数据库表示形式之间的映射应由您明确进行。如果你想使用shortName进行映射,你应该以某种方式在代码中表达它,否则它怎么知道你想如何映射它?您可以使用另一种映射方式,这意味着存在不同的方法。例如,有一种方法可以保存OrderStatus.ordinal(),然后使用OrderStatus.values()[rs.getInt("order_status")]进行转换。在这种情况下,您可能会使用更少的空间来存储值,具体取决于您的 DBMS,但如果您将添加更多枚举常量,则现有常量可能会为OrderStatus.SOME_ENUM_CONSTANT.ordinal()获得不同的值,这会导致数据损坏或需要更新数据库中的旧记录然后启动新版本的应用程序,这就是为什么我没有将此选项包含在映射选项列表中。

最新更新