使用 JdbcTemplate 插入多行

Posted

技术标签:

【中文标题】使用 JdbcTemplate 插入多行【英文标题】:Inserting multiple rows using JdbcTemplate 【发布时间】:2011-03-11 02:13:51 【问题描述】:

如何使用在 mysql 上运行的 JdbcTemplate 以可扩展的方式执行以下 SQL。在这种情况下,可扩展意味着:

    服务器上只执行一条 SQL 语句 它适用于任意数量的行。

声明如下:

INSERT INTO myTable (foo, bar) VALUES ("asdf", "asdf"), ("qwer", "qwer")

假设我有一个带有 foobar 字段的 POJO 列表。我意识到我可以遍历列表并执行:

jdbcTemplate.update("INSERT INTO myTable(foo, bar) VALUES (?, ?)", paramMap)

但这并没有满足第一个标准。

我相信我也可以执行:

jdbcTemplate.batchUpdate("INSERT INTO myTable(foo, bar) VALUES (?, ?)", paramMapArray)

但据我所知,这只会编译 SQL 一次并执行多次,再次失败第一个标准。

似乎同时满足这两个标准的最后一种可能性是自己使用StringBuffer 简单地构建 SQL,但我想避免这种情况。

【问题讨论】:

我们可以只使用 JDBC 做同样的事情吗?? 这与 JdbcTemplate 甚至 JDBC 无关。你不能在 SQL、句号(或标准 SQL,无论如何)中做到这一点,所以你当然不能在 JdbcTemplate 中做到。 @skaffman:我更新了我的问题,说我正在使用 mySQL。也许这是一个 mySQL-only 功能,但它在dev.mysql.com/doc/refman/5.1/en/insert.html 中描述了大约四分之一:“使用 VALUES 语法的 INSERT 语句可以插入多行。为此,请包含多个列值列表,每个列表都包含在括号中并用逗号分隔。示例:“ @Teja:是的,可以在纯 JDBC 中完成,但这不是问题所在。我已经用第三种可能性更新了这个问题,那就是手动构建 SQL。 如果您使用 InnoDB,那么 batchUpdate 应该 仅在最后一次插入后更新索引表。使用单个语句获得的唯一效率提升是您必须向 MySQL 服务器发送更少的数据。我怀疑您是否能够使用标准 JdbcTemplate 进行多次插入,但您始终可以扩展 JdbcTemplate 并滚动您自己的批量插入方法,该方法手动构建插入字符串。 【参考方案1】:

您可以像下面这样使用 BatchPreparedStatementSetter

public void insertListOfPojos(final List<MyPojo> myPojoList) 

    String sql = "INSERT INTO "
        + "MY_TABLE "
        + "(FIELD_1,FIELD_2,FIELD_3) "
        + "VALUES " + "(?,?,?)";

    getJdbcTemplate().batchUpdate(sql, new BatchPreparedStatementSetter() 

        @Override
        public void setValues(PreparedStatement ps, int i)
            throws SQLException 

            MyPojo myPojo = myPojoList.get(i);
            ps.setString(1, myPojo.getField1());
            ps.setString(2, myPojo.getField2());
            ps.setString(3, myPojo.getField3());

        

        @Override
        public int getBatchSize() 
            return myPojoList.size();
        
    );


【讨论】:

在使用 :NamedParameters 而不是 ? 时出现“参数索引超出范围(1 > 参数数量,即 0)”。与 NamedParameterJdbcTemplate 一起使用的一些更新?【参考方案2】:

多行插入(使用“行值构造函数”)实际上是 SQL-92 标准的一部分。看 http://en.wikipedia.org/wiki/Insert_(SQL)#Multirow_inserts.

有些数据库不支持这种语法,但很多支持。根据我的经验,Derby/Cloudscape、DB2、Postgresql 和较新的 Hypersonic 2.*+ 版本确实支持这一点。

您对让它作为 PreparedStatement 工作的担忧是可以理解的,但我看到类似的情况,Spring JDBC 确实为某些查询自动处理项目集合(比如 where in (?)),但我不能保证这种情况。

我确实找到了一些可能有用的信息(无法在这篇文章中添加第二个链接) 这可能会有所帮助。

我可以告诉您,从最严格的意义上说,您的第二个要求(适用于任意数量的参数)可能无法满足:我使用的每个数据库都会施加查询长度限制,这将发挥作用。

【讨论】:

不允许我在上面发布的那个 URL 是:fusesource.com/docs/router/2.2/transactions/…【参考方案3】:

在我看来 JdbcTemplate 的 batchUpdate() 方法在这种情况下可能会有所帮助(从这里复制 http://www.mkyong.com/spring/spring-jdbctemplate-batchupdate-example/):

//insert batch example
public void insertBatch(final List<Customer> customers)

  String sql = "INSERT INTO CUSTOMER " +
    "(CUST_ID, NAME, AGE) VALUES (?, ?, ?)";

  getJdbcTemplate().batchUpdate(sql, new BatchPreparedStatementSetter() 

@Override
public void setValues(PreparedStatement ps, int i) throws SQLException 
    Customer customer = customers.get(i);
    ps.setLong(1, customer.getCustId());
    ps.setString(2, customer.getName());
    ps.setInt(3, customer.getAge() );


@Override
public int getBatchSize() 
    return customers.size();


  );
 

【讨论】:

非常感谢,这正是我要找的!【参考方案4】:

你也可以试试 jdbcInsert.executeBatch(sqlParamSourceArray)

   // define parameters
jdbcInsert = new SimpleJdbcInsert(jdbcTemplate);
jdbcInsert.withTableName("TABlE_NAME");
SqlParameterSource[] sqlParamSourceArray = new SqlParameterSource[apiConsumer
        .getApiRoleIds().size()];
for (int i = 0; i < myCollection.size(); i++) 
    
  sqlParamSourceArray[i] = new MapSqlParameterSource().addValue("COL1");
      ......................

// execute insert
int[] keys = jdbcInsert.executeBatch(sqlParamSourceArray);

【讨论】:

这个答案是错误的! jdbcInsert.executeBatch() 不返回密钥。它返回the array of number of rows affected as returned by the JDBC driver。请参阅 javadocs。 docs.spring.io/spring-framework/docs/current/javadoc-api/org/…【参考方案5】:

您不能在 JDBC 中执行此操作,期间。在 MySQL 中它只是语法糖,但该语句的效果将与发出多个 INSERT 语句相同。所以你可以使用batchUpdate,它会产生同样的效果。

【讨论】:

不正确。 MySQL 的“扩展插入”(如问题中所述)比批量插入(您提前准备但一次插入一行)更快。它不是 MySQL 中的语法糖。

以上是关于使用 JdbcTemplate 插入多行的主要内容,如果未能解决你的问题,请参考以下文章

JDBC Template

spring 如何获取 jdbctemplate

使用MockIto模拟声明

使用 jdbcTemplate.batchUpdate 混淆批量插入

使用带有 @GeneratedValue 生成的 PrimaryKey 的 jdbctemplate 插入行

为啥spring jdbcTemplate batchUpdate逐行插入