插入带有自动生成ID的新记录

时间:2017-10-12 14:02:54

标签: java mybatis ibatis

我正在尝试使用MyBatis将新记录插入到一​​个简单的数据库表中,但我得到一个奇怪的异常。 Mybe与我没有使用POJO有关。

MyBatis版本:3.4.5

我的表:

@Insert("INSERT INTO image (id, content) VALUES (#{id}, #{content})")
@SelectKey(statement = "SELECT NEXTVAL('image_seq')", keyProperty = "id", before = true, resultType = long.class)
long insertImage(byte[] content);

MyBatis mapper:

byte[] fileContent = IOUtils.toByteArray(inputStream);
long id = imageDao.insertImage(fileContent);

我尝试使用它的方式:

java.lang.ClassCastException: java.lang.Long cannot be cast to [B
    at org.apache.ibatis.type.ByteArrayTypeHandler.setNonNullParameter(ByteArrayTypeHandler.java:26)
    at org.apache.ibatis.type.BaseTypeHandler.setParameter(BaseTypeHandler.java:53)
    at org.apache.ibatis.scripting.defaults.DefaultParameterHandler.setParameters(DefaultParameterHandler.java:87)
    at org.apache.ibatis.executor.statement.PreparedStatementHandler.parameterize(PreparedStatementHandler.java:93)
    at org.apache.ibatis.executor.statement.RoutingStatementHandler.parameterize(RoutingStatementHandler.java:64)
    at org.apache.ibatis.executor.SimpleExecutor.prepareStatement(SimpleExecutor.java:86)
    at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:49)
    at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117)
    at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:76)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:198)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:185)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
...

我得到的例外:

[B

我不想为这个"内容"创建带有getter / setter方法的POJO类。 param但我认为这个问题与缺少POJO有关。

解决方案是什么?

修改

我正在尝试调试mybatis代码,我找到了" parameterTypes"在{{1}}中: enter image description here

2 个答案:

答案 0 :(得分:0)

  

java.lang.Long无法强制转换为[B

这表示您正在尝试将long转换为byte[]

查看org.apache.ibatis.type.ByteArrayTypeHandler的来源:

public void  setNonNullParameter(PreparedStatement ps, int i, byte[] parameter, JdbcType jdbcType) throws SQLException {
    ps.setBytes(i, parameter);
}

我认为您需要从插入注释中删除{id}(因为此值是自动生成的)。

@Insert("INSERT INTO image (content) VALUES (#{content})")

否则参数会移一。

答案 1 :(得分:0)

当你想在代码中再次使用生成的值时,

@SelectKey很有用,但似乎你不会。

那么为什么不把所有内容保存在SQL中:

INSERT INTO image (id, content) VALUES ((SELECT NEXTVAL('image_seq')), #{content})

有关参数的例外,参数必须使用@Param注释命名

int insertImage(@Param("content") byte[] content);

int insertImage(@Param("id) Long id, @Param("content") byte[] content)

请注意,INSERT以及UPDATE和DELETE语句返回int类型,即插入/更新/删除的行数,[...]

编辑:除非您考虑到这一点,否则将执行java 8 PreparedStatement.executeLargeUpdate返回long。

[...]而不是建议生成的密钥。然后,您似乎最终想要获取键值,这意味着返回到带有@SelectKey的方块,并且需要POJO和生成值的目标属性。它甚至适用于带有生成密钥的批量插入。

我最近发现,如果按照settings section of the documentation中的说明操作,可以使用实际参数名称(那么您的代码将按原样运行):

  

useActualParamName允许引用语句参数   方法签名中声明的实际名称。要使用此功能,   您的项目必须使用-parameters选项在Java 8中编译。   (自:3.4.1)有效值:true | false默认值:true