【问题标题】:Having trouble reading String from MySQL table to Eclipse将字符串从 MySQL 表读取到 Eclipse 时遇到问题
【发布时间】:2021-02-04 16:10:24
【问题描述】:

我有一个优惠券项目,但在尝试向 Eclipse 读取优惠券时遇到问题。我有一个类别表,它们连接到我的“CATEGORY_ID”行中的优惠券表,这是一个整数。使用 add 方法时,我将我的 ENUM 转换为 int 以便将其添加到 CATEGORY_ID 没有问题。

我的问题是在尝试阅读它时,我尝试将其转换为 STRING 以获取文本值,但是,我得到了一个异常。

这是我的代码:

枚举类:

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;
}
}

将优惠券添加到表 COUPONS 的方法:

// 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) 上,我尝试 a 并将 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)

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

【问题讨论】:

    标签: java jdbc enums resultset


    【解决方案1】:

    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))
    

    或者您需要将元素的实际名称存储在表中。

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

    【讨论】:

    • 我应该在我的 ENUM 类中使用这个方法吗?我将如何使用特定方法的结果集
    • 是的,这是针对枚举类别的。我会更新答案
    【解决方案2】:

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

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

    从 JavaDoc(你可以find here)它说:

    ...名称必须与用于声明枚举的标识符完全匹配 在这种类型中保持不变。 (无关的空白字符不是 允许。)...

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

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

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

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

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

    public static Category findCategoryById(int index)
    

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

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


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

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

    【讨论】:

    • 感谢您提供的详细信息,它帮助很大!现在我有了更好的理解。
    猜你喜欢
    • 1970-01-01
    • 2015-08-31
    • 2015-01-03
    • 1970-01-01
    • 1970-01-01
    • 2020-05-25
    • 2011-06-12
    • 2012-07-22
    • 2018-12-09
    相关资源
    最近更新 更多