SimpleJdbcTemplate. - вставить и получить идентификатор - PullRequest
6 голосов
/ 10 февраля 2010

Я помещаю данные в базу данных с помощью simpleJdbcTemplate.

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

Я не хочу помещать какие-либо данные, потому что они мне не нужны для моего модульного теста.

Как я могу получить идентификатор из вставленной строки? Я могу получить текущее значение последовательности, но если кто-то сделает вставку, я получу следующее значение последовательности.

Есть ли способ использовать simpleJdbcTemplate для вставки строки и получения идентификатора? Метод update возвращает количество вставленных строк, и я хотел бы получить идентификатор. Спасибо за вашу помощь.

Ответы [ 8 ]

5 голосов
/ 11 февраля 2011

Вы уже нашли ответ? Если нет, попробуйте вместо этого использовать SimpleJdbcInsert. Например:

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

затем получить

sji.executeAndReturnKey(args).longValue();
4 голосов
/ 10 февраля 2010

Вам нужно вручную обработать последовательность, чтобы легко получить идентификатор, не привязывая себя к какому-либо конкретному продукту СУБД.

Это означает, что вы должны указать специфичный для развертывания компонент DataFieldMaxValueIncrementer и добавить его в свой класс обработки базы данных, как вы, скорее всего, делаете с вашим DataSource. Определение компонента должно выглядеть примерно так: (этот пример для 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;
}
3 голосов
/ 27 декабря 2011

Думаю, это так тяжело, как кажется ..: -O

Вы не пытаетесь что-то вроде:

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

Теперь newID будет содержать вновь вставленный идентификатор строки.

CHEERS .. !! :)

2 голосов
/ 15 июля 2013

Используя NamedParameterJdbcTemplate, у вас есть держатель ключа. Абстрагирует генерацию ключей СУБД. Проверьте метод создания.

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


}
1 голос
/ 07 февраля 2014

simpleJdbcTemplate устарела в пользу NamedParameterJdbcTemplate.

У Пелло Х правильный ответ, но его представление слишком громоздко для понимания. Упрощенный:

Если у вас есть очень простая таблица SAMPLE со столбцом NAME и сгенерированным первичным ключом с идентификатором типа 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

1 голос
/ 10 февраля 2010

Ответьте на этот вопрос: чего вы пытаетесь достичь с помощью теста? Проверить, что обновление работает без ошибок? Что вы каждый раз получаете новое удостоверение личности? Что таблица существует?

В зависимости от ответа, вы должны изменить свой тест. Если вы просто хотите знать, что синтаксис оператора правильный, вам не нужно ничего делать, кроме как запустить оператор (он выдаст исключение, если из-за ошибки произойдет сбой теста).

Если вы хотите убедиться, что каждый раз вы получаете новый идентификатор, вы должны запросить последовательность два раза и убедиться, что второе значение отличается от первого.

Если вы хотите проверить, что вставлена ​​строка с новым уникальным идентификатором, просто запустите вставку и убедитесь, что она возвращает 1. Если это работает, вы будете знать, что первичный ключ (идентификатор) не был нарушен и что строка была вставлена. Следовательно, механизм «добавить с уникальным идентификатором» должен работать.

[EDIT] Нет способа протестировать триггер, который добавляет ID в новую строку, потому что у Oracle нет средств для возврата только что созданного идентификатора. Вы можете прочитать последовательность, но нет гарантии, что nextval-1 даст вам тот же результат, что и триггер.

Вы можете попробовать select max(ID), но это может не сработать, если кто-либо вставит другую строку и подтвердит ее, прежде чем вы сможете выполнить запрос (используя уровень транзакции по умолчанию READ_COMMITTED).

Поэтому я настоятельно рекомендую избавиться от триггера и использовать стандартный двухшаговый алгоритм («получить новый идентификатор» плюс «вставить с новым идентификатором»), который кто-либо другой использует. Это сделает ваши тесты более простыми и менее хрупкими.

1 голос
/ 10 февраля 2010

Сначала вы должны запросить id из соответствующего sequence, а затем указать id в своем операторе вставки. Так просто.

Далее, мы можем назвать это интеграционным тестом, а не модульным тестом. Вы можете обратиться к этому потоку SO , чтобы получить представление о интеграционных тестах и ​​идентификаторах.

[Отредактировано после комментария]

В таком случае, избавьтесь от этого триггера. И извлеките id из sequence напрямую, прежде чем сделать insert.

Ну, вы можете запустить SELECT... FOR UPDATE на столе, взять последний id и увеличить его на 1. Если ваш id не является последовательным, что, я думаю, было бы не так, вы может содержать ROWID, характерный для Oracle AFAIK. И затем запросить id, используя это. На самом деле, это все вокруг.

Примечание: Я настоятельно рекомендую вам взглянуть на пост Аарона Дигуллы. Посмотрим, хватит ли этого.

0 голосов
/ 14 октября 2018

С помощью Spring * JdbcTemplate вы можете использовать метод update с PreparedStatementCreator и 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
   }
}
...