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

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

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

声明如下:

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 并滚动您自己的批量插入方法,该方法手动构建插入字符串。

标签: java sql spring jdbc 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 (?)),但我不能保证这种情况。

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

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

【讨论】:

【解决方案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);

【讨论】:

【解决方案5】:

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

【讨论】:

  • 不正确。 MySQL 的“扩展插入”(如问题中所述)比批量插入(您提前准备但一次插入一行)更快。它不是 MySQL 中的语法糖。
猜你喜欢
  • 2012-10-04
  • 2017-07-24
  • 1970-01-01
  • 2011-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多