SimpleJdbcTemplate进行。 - 插入和检索ID

时间:2010-02-10 08:25:42

标签: java unit-testing spring integration-testing jdbctemplate

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

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

我不想放任何数据,因为我不需要它用于我的单元测试目的。

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

有没有办法使用simpleJdbcTemplate插入行并获取id?更新方法返回插入的行数,我想拥有id。谢谢你的帮助。

8 个答案:

答案 0 :(得分:5)

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

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

然后检索

sji.executeAndReturnKey(args).longValue();

答案 1 :(得分:4)

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

这意味着您必须指定特定于部署的DataFieldMaxValueIncrementer bean,并将其注入数据库处理类,就像您最常使用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;
}

答案 2 :(得分:3)

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

你不尝试这样的事情:

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

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

CHEERS .. !! :)

答案 3 :(得分:2)

使用NamedParameterJdbcTemplate您有一个keyholder。它抽象了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;
    }


}

答案 4 :(得分:1)

您应首先从相应的id查询sequence,然后在插入语句中提供id。就这么简单。

此外,我们称之为集成测试,而不是单元测试。您可能希望参考this SO thread来了解有关集成测试和ID的信息。

[评论后编辑]

在这种情况下,摆脱那个触发器。在制作id之前,直接从sequence检索insert

好吧,您可以在桌面上触发SELECT... FOR UPDATE,然后抓住最后一个id,并将其递增1.如果您的id不是连续的,我猜不会在这种情况下,您可以保留特定于Oracle AFAIK的ROWID。然后使用它查询id。事实上,它的各种解决方法。

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

答案 5 :(得分:1)

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

根据答案,您必须修改测试。如果您只是想知道语句的语法是正确的,那么除了运行语句之外,您不需要做任何事情(如果测试失败,则会抛出异常)。

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

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

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

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

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

答案 6 :(得分:1)

不推荐使用simpleJdbcTemplate,而选择NamedParameterJdbcTemplate。

Pello X有正确答案,但他的提交过于繁琐,无法理解。 简化为:

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

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

答案 7 :(得分:0)

使用Spring的JdbcTemplate,您可以将其update方法与PreparedStatementCreatorGeneratedKeyholder结合使用,以保存新插入的行的主键。

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
   }
}