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

时间:2018-02-23 15:13:40

标签: java spring

我有一个枚举如下

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

我想在数据库中保存ACTIVE,AWAITING。同时在查询中检索相同的内容

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

问题

  1. 我是否需要在数据库或Active Order / Awaiting Order中保存ACTIVE / AWAITING?
  2. 如何使用JdbcTemplate
  3. 使用本机SQL查询保存枚举值

    我们正在使用MapSqlParameterSource

    感谢。

1 个答案:

答案 0 :(得分:1)

1)您可以存储' ACTIVE / AWAITING'并使用枚举的valueOf方法。

优点:

  1. 无需为映射方法编写其他代码 - 使用标准 enum' valueOf
  2. 数据库中的值更具人类可读性
  3. 强制所有枚举的常量名称都是唯一的,因此消除了这种类型的错误
  4. 缺点:

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

      将数据插入表格:

      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(例如,&#34; A&#34;),但是您需要遍历所有枚举才能找到正确的枚举。
      <登记/> 优点:

      1. 在数据库中存储这些值的空间可能更小
      2. 缺点:

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

          保存使用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()获取不同的值,从而导致数据损坏或需要更新数据库中的旧记录,然后启动应用程序的新版本,这就是为什么我没有将此选项包含在映射选项列表中。