将字符串从 MySQL table 读取到 Eclipse 时遇到问题

Having trouble reading String from MySQL table to Eclipse

我有一个优惠券项目,但在尝试将优惠券读取到 Eclipse 时遇到问题。我有一个 table 的类别,这些类别与我的优惠券 table 在行“CATEGORY_ID”中是一个整数。使用 add 方法时,我将我的 ENUM 转换为 int 以便毫无问题地将其添加到 CATEGORY_ID。

我的问题是在尝试读取它时,我尝试将其转换为 STRING 以获取文本值,但是,出现异常。

这是我的代码:

枚举CLASS:

public enum Category {

FOOD(1), ELECTRICITY(2), RESTAURANT(3), VACATION(4), HOTEL(5);

private Category(final int cat) {
    this.cat = cat;
}

private int cat;

public int getIDX() {
    return cat;
}

private Category(String cat1) {
    this.cat1 = cat1;
}

private String cat1;

public String getName() {
    return cat1;
}
}

将优惠券添加到 table 优惠券的方法:

// sql = "INSERT INTO `couponsystem`.`coupons` (`COMPANY_ID`,`CATEGORY_ID`,`TITLE`, `DESCRIPTION`, 
          `START_DATE`, `END_DATE`, `AMOUNT`, `PRICE`, `IMAGE`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);";

@Override
    public void addCoupon(Coupon coupon) throws SQLException {
        Connection connection = pool.getConnection();

    try {
        PreparedStatement statement = connection.prepareStatement(ADD_COUPON);
        statement.setInt(1, coupon.getCompanyID());
        statement.setInt(2, coupon.getCategory().getIDX());
        statement.setString(3, coupon.getTitle());
        statement.setString(4, coupon.getDescription());
        statement.setDate(5, (Date) coupon.getStartDate());
        statement.setDate(6, (Date) coupon.getEndDate());
        statement.setInt(7, coupon.getAmount());
        statement.setDouble(8, coupon.getPrice());
        statement.setString(9, coupon.getImage());
        statement.execute();

    } finally {
        pool.restoreConnection(connection);
    }
}

领取优惠券的方法:

// GET_ONE_COUPON = "SELECT * FROM `couponsystem`.`coupons` WHERE (`id` = ?);";


@Override
    public Coupon getOneCoupon(int couponID) throws SQLException {
    Connection connection = pool.getConnection();

        Coupon result = null;
        
        List<Category> cats = new ArrayList<Category>(EnumSet.allOf(Category.class));
        

        try {

            PreparedStatement statement = connection.prepareStatement(GET_ONE_COUPON);
            statement.setInt(1, couponID);
            ResultSet resultSet = statement.executeQuery();
            resultSet.next();
            result = new Coupon(resultSet.getInt(1), resultSet.getInt(2), Category.valueOf(resultSet.getString(3)),
                    resultSet.getString(4), resultSet.getString(5), resultSet.getDate(6), resultSet.getDate(7),
                    resultSet.getInt(8), resultSet.getDouble(9), resultSet.getString(10));

        } finally {
            pool.restoreConnection(connection);
        }

        return result;

在列索引 (3) 上,我尝试将 ENUM 转换为字符串以获取文本值,这是我遇到异常的地方。

异常:

Exception in thread "main" java.lang.IllegalArgumentException: No enum constant coupon.beans.Category.5
    at java.base/java.lang.Enum.valueOf(Enum.java:240)
    at coupon.beans.Category.valueOf(Category.java:1)
    at coupon.dbdao.CouponsDBDAO.getOneCoupon(CouponsDBDAO.java:125)
    at coupon.Program.main(Program.java:65)

希望我的问题很清楚。我可以添加更多信息。

valueOf 需要一个与枚举元素名称相对应的字符串,例如“FOOD”,但看起来您传递的是一个数字。如果你想从枚举中传递 id(数字),你需要一种在数字和枚举元素之间进行转换的方法。像这样

//in the enum Category
public static Category categoryFor(int id) {
  switch (id) {
    case 1:
      return FOOD;
      case 2: 
      return ELECTRICITY;
      //... more case
      default:
      return HOTEL;
  }
}

然后像这样称呼它

Category.categoryFor(resultSet.getInt(2))

或者您需要在 table.

中存储元素的实际名称

此外,您不应在查询中使用 *、“SELECT * ...”,而应使用列名列表,以便清楚您在 java 代码中映射的列, "SELECT COMPANY_ID, CATEGORY_ID,TITLE,..."

正如我正确理解的那样,您将 category 存储在 coupon 中作为 代码模型 中的枚举常量。在将它存储到数据库时,您正在使用您提供的方法将其映射到一个整数值。

罪魁祸首在 Category.valueOf(resultSet.getString(3)) 方法/部分。 Enum.valueOf 方法是 Java 提供的枚举的默认方法,它使用 String 作为参数 - 可能因此您也使用 resultSet.getString(3) 而不是 resultSet.getInt(3) 这会更直观。

从 Java 文档(您可以 find here)它说:

... The name must match exactly an identifier used to declare an enum constant in this type. (Extraneous whitespace characters are not permitted.) ...

这意味着要使 valueOf 方法正常工作,您需要使用以下值之一作为参数调用它:食品、电力、餐厅、假期、酒店。使用 1、2、... 或 5 等 int 值调用它会导致您面临 IllegalArgumentException

有两种解决方法可以解决这个问题:

  • 通过在 category 值之前调用 toString 方法,更改数据库模型以将枚举值/常量作为字符串存储在 table 中插入数据库(然后你的代码从数据库中读取 coupons 可以保持不变)。

  • 或者您需要提供您自己的“valueOf”方法的自定义实现 - 例如findCategoryById - 它将使用整数值作为其参数。通过编写您自己的 findCategoryById 方法,您将 coupons 插入数据库的代码可以保持不变。

要实现您自己的 findCategoryById Category 枚举中方法的签名应如下所示:

public static Category findCategoryById(int index)

然后您可以通过 Category.values() 遍历所有可用常量,并将 cat 与传递给方法的参数和基于它的匹配值 return 进行比较。

如果 none 匹配,您可以简单地 return null 或者也可以抛出一个 IllegalArgumentException。我个人更喜欢后者,因为它遵循“快速失败”方法,并且可以避免令人讨厌且耗时的错误搜索。


注意: Java 中的枚举也有一个自动生成/自动分配的序号。您可以通过对枚举的值调用 ordinal 方法来简单地请求它。在您的情况下,序数匹配自分配的 cat 值,因此您可以使用它们,而不是自己维护 cat 属性。

在使用序数时,值得一提的是在枚举中指定常量的顺序很重要!当您更改常量的顺序时,序数也会如此。因此,在使用序数时也需要小心。因此,您可能更愿意坚持使用当前的方法(一点也不差,而且被广泛使用),因为它避免了序数的排序问题。