8

我正在使用 simpleJdbcTemplate 将数据放入数据库。

simpleJdbcTemplate.update("insert into TABLE values(default)");

我不想放任何数据,因为我不需要它来进行单元测试。

如何从插入的行中获取 id?我可以检索当前序列值,但如果其他人会进行插入,那么我将获得下一个序列值。

有什么方法可以使用 simpleJdbcTemplate 插入一行并获取 id?更新方法重新调整插入的行数,我想拥有 id。谢谢您的帮助。

4

8 回答 8

5

你找到答案了吗?如果没有,请尝试SimpleJdbcInsert改用。例如:

SimpleJdbcInsert sji = new SimpleJdbcInsert(dataSource)
    .withTableName(TableName)
    .usingColumns(new String[]{your columns})
    .usingGeneratedKeyColumns(you auto-increment id colums);

然后检索

sji.executeAndReturnKey(args).longValue();
于 2011-02-11T06:07:10.447 回答
4

我不认为它看起来很艰难.. :-O

你不要尝试类似的东西:

int newID = simpleJdbcTemplate.queryForInt("INSERT INTO TABLE(Column_Names) 
                                            values (default) 
                                            RETURNING ID");

现在newID将包含新插入的行 ID。

干杯..!!:)

于 2011-12-27T14:53:30.180 回答
4

您需要手动处理序列以轻松获取 id,而无需将自己绑定到任何特定的 RDBMS 产品。

这意味着您必须指定一个特定于部署的DataFieldMaxValueIncrementerbean 并将其注入到您的数据库处理类中,就像您很可能对DataSource. bean 定义应如下所示(此示例适用于 PostgreSQL)

<bean id="incrementer" class="org.springframework.jdbc.support.incrementer.PostgreSQLSequenceMaxValueIncrementer">
    <property name="dataSource" ref="dataSource" />
    <property name="incrementerName" value="seq_name" />
</bean>

然后,当您的类中有增量器时,您可以在代码中使用它来获取 id 值,如下所示:

public long saveBeanAndReturnId(Bean b) {
    long id = incrementer.nextLongValue();
    simpleJdbc.update("...");
    return id;
}
于 2010-02-10T08:37:21.347 回答
3

使用 NamedParameterJdbcTemplate 你有一个密钥持有者。它抽象了 DBMS 密钥生成。检查创建方法。

package info.pello.spring.persistence;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.support.GeneratedKeyHolder;

import java.util.ArrayList;
import java.util.List;

/**
 * 
 */

/**
 * DAO for customer entity
 * @author Pello Xabier Altadill Izura
 * @greetz Blue Mug
 *
 */
public class CustomerDAO {

    // I use both jdbcTemplate/namedParameterJdbcTemplate depending on needs
    private JdbcTemplate jdbcTemplate;
    private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
    private final static String CREATE_SQL = "insert into customer (name,address,email) values(:name,:address,:email)";

    /**
     * gets Customer data from DataBase
     * @param customerId
     * @return
     */
    public Customer read (int customerId) {
        Customer customer = null;

        return customer;
    } 

    /**
     * gets all Customer data from DataBase
     * @return list of customers
     */
    public List<Customer> readAll () {

        List<Customer> customerList = new ArrayList<Customer>();

        return customerList;
    } 

    /**
     * creates new Customer
     * @param newCustomer
     * @return
     */
    public int create (Customer newCustomer) {
        GeneratedKeyHolder generatedKeyHolder = new GeneratedKeyHolder();

        MapSqlParameterSource namedParameters = new MapSqlParameterSource();
        namedParameters.addValue("name", newCustomer.getName());
        namedParameters.addValue("address", newCustomer.getAddress());
        namedParameters.addValue("email", newCustomer.getEmail());

        namedParameterJdbcTemplate.update(CREATE_SQL,
                            namedParameters,
                            generatedKeyHolder);

        newCustomer.setId(generatedKeyHolder.getKey().intValue());
        return newCustomer.getId();
    }

    /**
     * updates customer information 
     * @param customer
     * @return
     */
    public int update (Customer customer) {
        int result = 0;


        return result;
    }

    /**
     * delete customer  
     * @param customerId
     * @return
     */
    public int delete (int customerId) {

        int result = 0;


        return result;
    }

    /**
     * @return the jdbcTemplate
     */
    public JdbcTemplate getJdbcTemplate() {
        return jdbcTemplate;
    }

    /**
     * @param jdbcTemplate the jdbcTemplate to set
     */
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    /**
     * @return the namedParameterJdbcTemplate
     */
    public NamedParameterJdbcTemplate getNamedParameterJdbcTemplate() {
        return namedParameterJdbcTemplate;
    }

    /**
     * @param namedParameterJdbcTemplate the namedParameterJdbcTemplate to set
     */
    public void setNamedParameterJdbcTemplate(
            NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
        this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
    }


}
于 2013-07-15T17:00:32.507 回答
1

您应该首先id从适当的查询sequence,然后id在您的插入语句中提供它。就如此容易。

此外,可以说,我们将其称为集成测试,而不是单元测试。您可能想参考这个 SO 线程以了解有关集成测试和 id 的想法。

[评论后编辑]

在这种情况下,摆脱那个触发器。并在 make 之前直接id从 中检索。sequenceinsert

好吧,您可以在桌子上触发 a SELECT... FOR UPDATE,然后抓住最后一个id,并将其增加 1。如果您id的不是顺序的,我猜不会是这种情况,您可以保留ROWIDOracle AFAIK 特有的 ,然后查询id使用它。确实,这一切都可以解决。

注意: 我强烈建议您查看 Aaron Digulla 的帖子。看看这些是否足够。

于 2010-02-10T08:30:43.773 回答
1

回答这个问题:您想通过测试达到什么目的?检查更新是否正常运行?每次都换新身份证?该表存在吗?

根据答案,您必须修改您的测试。如果您只想知道语句的语法是否正确,则无需执行任何操作,只需运行该语句(如果出现错误导致测试失败,它将抛出异常)。

如果要确保每次都获得一个新的 ID,则必须查询该序列两次,并检查第二个值是否与第一个不同。

如果您想检查是否插入了具有新唯一 ID 的行,只需运行插入并检查它是否返回 1。如果它有效,您将知道主键(ID)没有被违反,并且行已插入。因此,“使用唯一 ID 添加”机制必须有效。

[编辑] 无法测试将 ID 添加到新行的触发器,因为 Oracle 无法返回它刚刚创建的 ID。您可以读取序列,但不能保证nextval-1会给您与触发器看到的相同结果。

您可以尝试select max(ID),但如果其他人在您运行查询之前插入另一行并提交它(使用默认事务级别READ_COMMITTED),则可能会失败。

因此,我强烈建议摆脱触发器并使用其他人使用的标准两步(“获取新 ID”加上“插入新 ID”)算法。它将使您的测试更简单,更不脆弱。

于 2010-02-10T08:37:49.843 回答
1

不推荐使用 simpleJdbcTemplate,取而代之的是 NamedParameterJdbcTemplate。

Pello X 有正确答案,但是他的提交太麻烦了,看不懂。简化:

如果您有一个名为 SAMPLE 的非常简单的表,其中有一个名为 NAME 的列和一个生成的名为 ID 类型为 bigint 的主键:

MapSqlParameterSource namedParameters = new MapSqlParameterSource().addValue("name", name);

KeyHolder keyHolder = new GeneratedKeyHolder();
int numberOfAffectedRows = namedParameterJdbcTemplate.update("insert into SAMPLE(name) values(:name)", namedParameters, keyHolder);

return numberOfAffectedRows == 1 ? keyHolder.getKey().longValue() : -1L;

这将返回更新中唯一生成的密钥,如果超过 1 行受到影响,则返回 -1。

请注意,由于只有 1 个生成的密钥,我并不关心列名。

如果生成的密钥超过 1 个,请查看http://docs.spring.io/spring/docs/3.2.7.RELEASE/javadoc-api/org/springframework/jdbc/support/KeyHolder.html#getKeys %28%29

于 2014-02-07T14:37:34.173 回答
0

使用 Spring JdbcTemplate,您可以将其update方法与 aPreparedStatementCreator和 a一起使用GeneratedKeyholder来保存新插入行的主键。

public class SomeDao(){
   @Autowired
   private JdbcTemplate jdbcTemplate;
   //example of a insertion returning the primary key
   public long save(final String name){
       final KeyHolder holder = new GeneratedKeyHolder();//the newly generated key will be contained in this Object
       jdbcTemplate.update(new PreparedStatementCreator() {
      @Override
      public PreparedStatement createPreparedStatement(final Connection connection) throws SQLException {
        final PreparedStatement ps = connection.prepareStatement("INSERT INTO `names` (`name`) VALUES (?)",
            Statement.RETURN_GENERATED_KEYS);
        ps.setString(1, name);
        return ps;
      }
    }, holder);
    return holder.getKey().longValue();//the primary key of the newly inserted row
   }
}
于 2018-10-14T02:06:39.120 回答