用自动生成的ID插入一条新记录
我想用MyBatis将一条新记录插入到一个简单的数据库表中,但我得到一个奇怪的异常。 Mybe它与我没有使用POJO有关。用自动生成的ID插入一条新记录
MyBatis的版本:3.4.5
我的表:
CREATE TABLE IF NOT EXISTS image
(
id BIGINT PRIMARY KEY,
content BYTEA
) WITHOUT OIDS;
MyBatis的映射器:
@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);
的方式我试图使用它:
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)
...
我不想创建这一个“内容”参数的getter/setter方法POJO类,但我认为这个问题与缺失POJO。
解决方案是什么?
编辑
@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
返回长执行。
[...]而不是建议的生成密钥。那么看起来你最终想获得关键值,这意味着回到原来的@SelectKey
,需要一个POJO和一个目标属性来生成值。它甚至适用于带有生成密钥的批量插入。
我近来可用于实际参数名称发现(那么你的代码将工作是)如果settings section of the documentation以下说明:
useActualParamName
允许通过在方法中声明其 实际名称引用语句的参数签名。要使用此功能, 您的项目必须使用-parameters选项在Java 8中进行编译。 (从:3.4.1)有效值:true
|false
默认:true
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})")
否则参数偏移一个。
按照你的建议,我删除ID从SQL,但它并没有帮助。我得到了这个奇怪的异常:org.apache.ibatis.binding.BindingException:找不到参数'content'。可用参数是[array,id] – zappee
我删除了@SelectKey,并向方法签名添加了一个长输入参数,如下所示:long insertImage(long id,byte [] content)。但是现在这是我得到的异常:org.apache.ibatis.binding.BindingException:找不到参数'id'。可用的参数是[arg1,arg0,param1,param2]在日志中的这4个参数来自哪里的时候,我有一点点的自信。 – zappee
感谢您的回复。 Finnally我创建了一个ID,注释,文件名和长度属性的POJO。将这些元数据与文件内容一起存储是有意义的。 POJO解决了我的问题。谢谢。 – zappee