在枚举字段(DB)中插入字符串值(java)时获取“列的数据被截断”

Posted

技术标签:

【中文标题】在枚举字段(DB)中插入字符串值(java)时获取“列的数据被截断”【英文标题】:While inserting String value (java) in Enum field (DB) Getting " Data truncated for column" 【发布时间】:2017-02-06 09:59:02 【问题描述】:

在我的 mysql 表中有一个枚举字段“spe_gender”。

mysql> desc tbl_sswltdata_persons;
+-----------------+-----------------------+------+-----+---------+----------------+
| Field           | Type                  | Null | Key | Default | Extra          |
+-----------------+-----------------------+------+-----+---------+----------------+
| spe_id          | bigint(20) unsigned   | NO   | PRI | NULL    | auto_increment |
| spe_sen_id      | bigint(20) unsigned   | NO   | MUL | NULL    |                |
| spe_gender      | enum('male','female') | YES  |     | NULL    |                |
| spe_is_deceased | tinyint(1)            | NO   |     | 0       |                |
| spe_birth_place | varchar(255)          | YES  |     | NULL    |                |
| spe_create_date | datetime              | YES  |     | NULL    |                |
| spe_update_date | datetime              | YES  |     | NULL    |                |
+-----------------+-----------------------+------+-----+---------+----------------+
7 rows in set (0.00 sec)

所以我创建了一个 POJO 类:

public class SswltdataPersons implements Serializable 
    private static final long serialVersionUID = 1L;

    private long spe_id;
    private long spe_sen_id;
    private String spe_gender;
    private String spe_is_deceased;
    private String spe_birth_place;
    private String spe_create_date;
    private String spe_update_date;

    // .........

    public String getSpe_gender() 
        return spe_gender;
    
    public void setSpe_gender(String spe_gender) 
        this.spe_gender = spe_gender;
    

    // ......


当我尝试将数据写入此表时,出现异常

org.springframework.dao.DataIntegrityViolationException: PreparedStatementCallback; SQL 
    [INSERT INTO iwpro_imp.tbl_sswltdata_persons VALUES(?,?,?,?,?,?,?)]; 
    Data truncated for column 'spe_gender' at row 1; nested exception is java.sql.BatchUpdateException: Data truncated for column 'spe_gender' at row 1

我认为问题是在 Enum 字段(在 DB 中)中插入字符串值(通过 java)时。这是我得到异常的方法。

@Transactional(value="transactionManager_iwpro_imp", rollbackFor = Exception.class)
    public void saveAllPersons(final List<SswltdataPersons> list) 


        String sql = "INSERT INTO iwpro_imp.tbl_sswltdata_persons VALUES(?,?,?,?,?,?,?)";

        try
            jdbcTemplate.update("SET foreign_key_checks = 0");

            List<List<SswltdataPersons>> batchLists = Lists.partition(list, batchSize);

            for(final List<SswltdataPersons> batch : batchLists) 
                BatchPreparedStatementSetter bpss = new BatchPreparedStatementSetter() 
                    @Override
                    public void setValues(PreparedStatement ps, int index) throws SQLException 
                        SswltdataPersons dataObject = batch.get(index);
                        ps.setLong(1, dataObject.getSpe_id());
                        ps.setLong(2, dataObject.getSpe_sen_id());
                        ps.setString(3, dataObject.getSpe_gender());
                        ps.setString(4, dataObject.getSpe_is_deceased());
                        ps.setString(5, dataObject.getSpe_birth_place());
                        ps.setString(6, dataObject.getSpe_create_date());
                        ps.setString(7, dataObject.getSpe_update_date());
                    

                    @Override
                    public int getBatchSize() 
                        return batch.size();
                    
                ;
                jdbcTemplate.batchUpdate(sql, bpss);
            

            jdbcTemplate.update("SET foreign_key_checks = 1");

        catch(Exception e)
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            logger.error("\n\nUnexpected Exception:\n", e);
            e.printStackTrace();
        
    

我不能在数据库中插入这个枚举值吗?

【问题讨论】:

您应该在INSERT 语句中使用明确的列列表,以确保您的变量绑定到正确的列。 dataObject有什么数据? 您应该首先检查您的枚举值 java-side 是否真的是“男”或“女”,并且您应该在插入查询中指定列名以确保每个值都存储在正确的列 实际上我正在将数据从一台服务器复制到另一台服务器(两个数据库相同)。所以 dataObject 包含来自服务器 1 的数据,我将在服务器 2 上写入这些数据。在服务器 2 上我遇到异常。 .length() 不适用于 null(会给出 NullPointerException),您在此处插入一个空字符串。 也许可以试试ps.setString(3, dataObject.getSpe_gender().isEmpty() ? null : dataObject.getSpe_gender()); 【参考方案1】:

在您的 java 代码中,将 spe_gender 声明为 Enum 类型

private Gender spe_gender

其中 Gender 是一个枚举类

public enum Gender 
    MALE,
    FEMALE

【讨论】:

如果我把它改成 Gender 类型,那么我将如何写 ps.setString(3, dataObject.getSpe_gender());因为 setString 只接受 (int, String) 在这种情况下,您必须将其转换为字符串,在您的情况下,也必须将其转换为小写,所以它类似于:dataObject.getSpe_gender().name.toLowerCase(),或者只是向枚举添加一个方法以小写形式返回名称【参考方案2】:

为了回答这个问题,您必须举一个实际插入数据的示例。

无论如何,关于你得到的异常,你很可能没有插入“男性”或“女性”,因为它说“第 1 行的列 'spe_gender' 的数据被截断”这意味着你的数据插入不同,实际上比允许的更大(如更多字符)。

另外,检查是否有插入枚举而不是“setString”的实际方法。 -> 编辑:它没有

【讨论】:

我打印了数据,我认为我插入了正确的值。在这里查看 SOP 结果: System.out.println(dataObject.getSpe_gender() + " ::: " + dataObject.getSpe_gender().length());给我女 ::: 6 男 ::: 4 ::: 0 就像我在 cmets 中说的,你插入的是一个空字符串,试试@mick-mnemonic 建议,应该可以 替换 ps.setString(3, dataObject.getSpe_gender().isEmpty());使用 ps.setString(3, dataObject.getSpe_gender().isEmpty() ? "" : dataObject.getSpe_gender());为我工作。 这实际上应该不起作用,给它一个空字符串会给出与以前相同的错误,它应该是null 是的,它为空。那是错字。 ps.setString(3, dataObject.getSpe_gender().isEmpty() ? null : dataObject.getSpe_gender());【参考方案3】:

感谢 Mick Mnemonic 的建议。它奏效了。

替换

ps.setString(3, dataObject.getSpe_gender().isEmpty());

ps.setString(3, dataObject.getSpe_gender().isEmpty() ? null : dataObject.getSpe_gender());

为我工作。谢谢大家。

【讨论】:

当枚举值为空时,设置的值不应该是null而不是""吗? 是的。答案已修改。

以上是关于在枚举字段(DB)中插入字符串值(java)时获取“列的数据被截断”的主要内容,如果未能解决你的问题,请参考以下文章

在运行时从 db 枚举为 jpa 枚举生成值

C#:按字符串获取枚举值?

如何在Django中基于枚举为模型字段设置默认值?

怎么根据一个值获取它在枚举里的值?

如何从Java中的字符串值中获取枚举值

Firebase:在 Kotlin/Java 中使用枚举字段的干净方式?