问题描述
我的需求就是需要循环插入一组数据,因为数据库是按照自增长ID关联的,所以每插入一条数据,都要返回自增长的ID,用来设置关联关系,我用JdbcTemplate可以实现一组数据的插入并返回ID,但是循环两次以上就出错了:org.springframework.jdbc.UncategorizedSQLException:PreparedStatementCallback;uncategorizedSQLExceptionforSQL[insertintoT_METADATA_ABSTRACT(STATIONCODE,ARCHIVETYPE,ENTITYID,ENTITYNAME,ABS,KEYWORDS,CREATOR,CONTRI,BTIME,ETIME,SPATIALCOV,DBCODE,SHARINGLEVEL,TYPE,ISDELETED,ENTITYUPDATEDATE)values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)];SQLstate[null];errorcode[17041];索引中丢失IN或OUT参数::17;nestedexceptionisjava.sql.SQLException:索引中丢失IN或OUT参数::17atorg.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:83)atorg.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)atorg.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:603)atorg.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:843)atcn.csdb.DataCollection.SynDaoTest.insertTest(SynDaoTest.java:48)atsun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethod)atsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)atsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)atorg.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)atorg.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)atorg.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)atorg.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)atorg.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)atorg.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)atorg.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)atorg.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)atorg.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)atorg.junit.runners.ParentRunner$3.run(ParentRunner.java:193)atorg.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)atorg.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)atorg.junit.runners.ParentRunner.access$000(ParentRunner.java:42)atorg.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)atorg.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)atorg.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)atorg.junit.runners.ParentRunner.run(ParentRunner.java:236)atorg.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)atorg.junit.runner.JUnitCore.run(JUnitCore.java:157)atcom.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74)atcom.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:211)atcom.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67)atsun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethod)atsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)atcom.intellij.rt.execution.application.AppMain.main(AppMain.java:120)Causedby:java.sql.SQLException:索引中丢失IN或OUT参数::17atoracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:112)atoracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:146)atoracle.jdbc.driver.OraclePreparedStatement.processCompletedBindRow(OraclePreparedStatement.java:1704)atoracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3280)atoracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:3368)atcom.alibaba.druid.filter.FilterChainImpl.preparedStatement_executeUpdate(FilterChainImpl.java:2721)atcom.alibaba.druid.wall.WallFilter.preparedStatement_executeUpdate(WallFilter.java:566)atcom.alibaba.druid.filter.FilterChainImpl.preparedStatement_executeUpdate(FilterChainImpl.java:2719)atcom.alibaba.druid.filter.FilterAdapter.preparedStatement_executeUpdate(FilterAdapter.java:1069)atcom.alibaba.druid.filter.FilterEventAdapter.preparedStatement_executeUpdate(FilterEventAdapter.java:491)atcom.alibaba.druid.filter.FilterChainImpl.preparedStatement_executeUpdate(FilterChainImpl.java:2719)atcom.alibaba.druid.proxy.jdbc.PreparedStatementProxyImpl.executeUpdate(PreparedStatementProxyImpl.java:145)atcom.alibaba.druid.pool.DruidPooledPreparedStatement.executeUpdate(DruidPooledPreparedStatement.java:253)atorg.springframework.jdbc.core.JdbcTemplate$3.doInPreparedStatement(JdbcTemplate.java:845)atorg.springframework.jdbc.core.JdbcTemplate$3.doInPreparedStatement(JdbcTemplate.java:1)atorg.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:587)我的代码:finalStringsql="insertintoT_METADATA_ABSTRACT(STATIONCODE,ARCHIVETYPE,ENTITYID,ENTITYNAME,ABS,KEYWORDS,"+"CREATOR,CONTRI,BTIME,ETIME,SPATIALCOV,DBCODE,SHARINGLEVEL,TYPE,ISDELETED,ENTITYUPDATEDATE)values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";for(finalMap<String,Object>map:list){KeyHolderkeyHolder=newGeneratedKeyHolder();serviceSysTemplate.update(newPreparedStatementCreator(){@OverridepublicPreparedStatementcreatePreparedStatement(Connectionconnection)throwsSQLException{PreparedStatementps=connection.prepareStatement(sql,newString[]{"ID"});ps.setString(1,map.get("CERNURI").toString());ps.setString(2,map.get("ENTTYPE").toString());ps.setString(3,map.get("ENTID").toString());ps.setString(4,map.get("ENTNAME").toString());if(map.get("ABS")!=null)ps.setString(5,map.get("ABS").toString());elseps.setNull(5,Types.VARCHAR);if(map.get("KEYWORDS")!=null)ps.setString(6,map.get("KEYWORDS").toString());elseps.setNull(6,Types.VARCHAR);ps.setString(7,map.get("CREATOR").toString());if(map.get("CONTRI")!=null)ps.setString(8,map.get("CONTRI").toString());elseps.setNull(8,Types.VARCHAR);if(map.get("BTIME")!=null)ps.setString(9,map.get("BTIME").toString());elseps.setNull(9,Types.VARCHAR);if(map.get("ETIME")!=null)ps.setString(10,map.get("ETIME").toString());elseps.setNull(10,Types.VARCHAR);if(map.get("SPATIALCOV_GEONAME")!=null)ps.setString(11,map.get("SPATIALCOV_GEONAME").toString());elseps.setNull(11,Types.VARCHAR);ps.setString(12,"dbcode2");ps.setString(13,map.get("RESTRCATEGORY").toString());ps.setString(14,map.get("DATACATEGORY").toString());ps.setInt(15,Integer.parseInt(map.get("ISDELETED").toString()));ps.setString(16,map.get("HARVESTDATE").toString());returnps;}},keyHolder);System.out.println(keyHolder.getKey().longValue());}
关键是,如果循环一次,运行正常,循环两次,第二次插入就出现了上面的错误,让我很费解!我还尝试用PreparedStatementCreatorFactory来实现,代码如下:finalStringsql="insertintoT_METADATA_ABSTRACT(STATIONCODE,ARCHIVETYPE,ENTITYID,ENTITYNAME,ABS,KEYWORDS,"+"CREATOR,CONTRI,BTIME,ETIME,SPATIALCOV,DBCODE,SHARINGLEVEL,TYPE,ISDELETED,ENTITYUPDATEDATE)values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";PreparedStatementCreatorFactoryfactory=newPreparedStatementCreatorFactory(sql,newint[]{Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,Types.NUMERIC,Types.VARCHAR});factory.setGeneratedKeysColumnNames(newString[]{"ID"});for(finalMap<String,Object>map:list){PreparedStatementCreatorcreator=factory.newPreparedStatementCreator(newObject[]{map.get("CERNURI"),map.get("ENTTYPE"),map.get("ENTID"),map.get("ENTNAME"),map.get("ABS"),map.get("KEYWORDS"),map.get("CREATOR"),map.get("CONTRI"),map.get("BTIME"),map.get("ETIME"),map.get("SPATIALCOV_GEONAME"),"dbcode2",map.get("RESTRCATEGORY"),map.get("DATACATEGORY"),map.get("ISDELETED"),map.get("HARVESTDATE")});KeyHolderkeyHolder=newGeneratedKeyHolder();serviceSysTemplate.update(creator,keyHolder);System.out.println(keyHolder.getKey().longValue());}
依然出现上面的错误,求大神来解决!
解决方案
解决方案二:
你这个感觉也没多大必要.....要实现插入数据库并返回自增长ID,有个简单的办法1、在插入之前,你先查询你的自增长的nextval,当然,前提是你的这个nextval的值不能与之前重复,如果不存在脏数据,是不会有问题的。2、然后把你查询出来的nextval的值,当做你 T_METADATA_ABSTRACT表的主键ID插入进去不就行了么?而且你查出来的nextval的值可以随时用,也可以返回出去
解决方案三:
是不是该提前备好,你插入之后再查询吗?
解决方案四:
引用1楼shijing266的回复:
你这个感觉也没多大必要.....要实现插入数据库并返回自增长ID,有个简单的办法1、在插入之前,你先查询你的自增长的nextval,当然,前提是你的这个nextval的值不能与之前重复,如果不存在脏数据,是不会有问题的。2、然后把你查询出来的nextval的值,当做你 T_METADATA_ABSTRACT表的主键ID插入进去不就行了么?而且你查出来的nextval的值可以随时用,也可以返回出去
这个方法是我在用的,但是Jdbctemplate既然有这个功能,我觉得至少比这个方法效率高一些吧,因为我要插入很多数据,每条数据都要两条sql语句,有点浪费啊
解决方案五:
引用2楼rui888的回复:
是不是该提前备好,你插入之后再查询吗?
Oracle数据库里面有一个触发器,插入时自动设置ID
解决方案六:
引用3楼ZSMJ_2011的回复:
Quote: 引用1楼shijing266的回复:
你这个感觉也没多大必要.....要实现插入数据库并返回自增长ID,有个简单的办法1、在插入之前,你先查询你的自增长的nextval,当然,前提是你的这个nextval的值不能与之前重复,如果不存在脏数据,是不会有问题的。2、然后把你查询出来的nextval的值,当做你 T_METADATA_ABSTRACT表的主键ID插入进去不就行了么?而且你查出来的nextval的值可以随时用,也可以返回出去这个方法是我在用的,但是Jdbctemplate既然有这个功能,我觉得至少比这个方法效率高一些吧,因为我要插入很多数据,每条数据都要两条sql语句,有点浪费啊
恩,我也就提个建议~嘿嘿能搞清jdbcTemplate更好~