简单的Jdbc模板。 - 插入和检索ID

发布于 2024-08-21 01:50:24 字数 296 浏览 9 评论 0原文

我使用 simpleJdbcTemplate 将数据放入数据库中。

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

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

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

有没有办法使用 simpleJdbcTemplate 插入行并获取 id?更新方法重新调整插入的行数,我想要 ID。感谢您的帮助。

I'm putting the data into database with simpleJdbcTemplate.

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

I dont want to put any data because i dont need it for my unit test purpose.

How can i get the id from the inserted row? I can retriev the current sequence value but if somebody else will do a insert then i will be get a next sequence value.

Is there any way to use simpleJdbcTemplate to insert a row and get id? The update method retuns the number of inserted rows and i would like to have the id. Thank you for your help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

遗弃M 2024-08-28 01:50:24

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

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

然后检索

sji.executeAndReturnKey(args).longValue();

Did you find the answer yet? If not, try to use SimpleJdbcInsert instead.
For example:

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

then retrieve

sji.executeAndReturnKey(args).longValue();
情话难免假 2024-08-28 01:50:24

您需要手动处理序列才能轻松获取 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;
}

You need to manually handle the sequence to get the id easily without tying yourself into any specific RDBMS product.

This means that you have to specify a deployment-specific DataFieldMaxValueIncrementer bean and inject that to your database handling class just as you most likely do with your DataSource. The bean definition should look something like this (this example is for PostgreSQL):

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

Then when you have the incrementer in your class, you can use it in your code to get the id value somewhat like this:

public long saveBeanAndReturnId(Bean b) {
    long id = incrementer.nextLongValue();
    simpleJdbc.update("...");
    return id;
}
山色无中 2024-08-28 01:50:24

我不认为它看起来像那么困难.. :-O

Y 不要尝试类似的事情:

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

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

干杯..!! :)

I dun think its as tough as it seems.. :-O

Y dont you try something like :

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

Now newID wil contains the newly Inserted row ID.

CHEERS..!! :)

三寸金莲 2024-08-28 01:50:24

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


}

Using NamedParameterJdbcTemplate you have a keyholder. It abstracts DBMS key generation.
Check create method.

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


}
药祭#氼 2024-08-28 01:50:24

您应该首先从适当的序列中查询id,然后在插入语句中提供该id。就这么简单。

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

[评论后编辑]

在这种情况下,请删除该触发器。并在进行插入之前直接从序列检索id

好吧,您可以在桌子上触发SELECT ... FOR UPDATE,并获取最后一个id,并将其增加1。如果您的id code> 不是连续的,我猜情况并非如此,您可以保存特定于 Oracle AFAIK 的 ROWID。然后使用它查询id。事实上,这一切都可以解决。

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

You should first query the id from the appropriate sequence, and then provide that id in your insert statement. As simple as that.

Further, we call it integration test, instead of unit test, arguably. You might like to refer to this SO thread to have an idea regarding integration tests and ids.

[Edited after comment]

In that case, get rid of that trigger. And retrieve the id from the sequence directly, prior to make a insert.

Well, you can fire a SELECT... FOR UPDATE on the table, and grab the last id, and increment that by 1. If your id is not sequential, which I guess wouldn't be the case, you can hold the ROWID, specific to Oracle AFAIK. And then query for id using that. Indeed, its all kinda work around.

Note: I strongly suggest you to look at Aaron Digulla's post. See if any of that suffice.

¢好甜 2024-08-28 01:50:24

回答这个问题:您想通过测试实现什么目标?检查更新运行是否没有错误?你每次都会得到一个新的ID吗?该表存在吗?

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

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

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

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

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

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

Answer this question: What are you trying to achieve with your test? Check that the update runs without error? That you get a new ID every time? That the table exists?

Depending on the answer, you must modify your test. If you just want to know that the syntax of the statement is correct, you don't need to do anything but run the statement (it will throw an exception if there is an error making the test fail).

If you want to make sure you get a new ID every time, you must query the sequence two times and check that the second value is different from the first.

If you want to check that a row with a new unique ID is inserted, just run the insert and check that it returns 1. If it works, you'll know that the primary key (the ID) wasn't violated and that a row was inserted. Hence, the "add with unique ID" mechanism must work.

[EDIT] There is no way to test a trigger which adds an ID to a new row because Oracle has no means to return the ID it just created. You could read the sequence but there is no guarantee that nextval-1 will give you the same result that the trigger saw.

You could try select max(ID) but that can fail if anyone else inserts another row and commits it before you can run the query (using the default transaction level READ_COMMITTED).

Therefore I strongly suggest to get rid of the trigger and use the standard 2-step ("get new ID" plus "insert with new ID") algorithm that anyone else uses. It will make your tests more simple and less brittle.

冰葑 2024-08-28 01:50:24

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

simpleJdbcTemplate is deprecated in favour of NamedParameterJdbcTemplate.

Pello X has the correct answer, but his submission is too cumbersome to understand.
Simplified:

If you have a very simple table called SAMPLE with a column called NAME and a primary key that is generated called ID of type 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;

This will return the only generated key in the update or -1 if more than 1 row was affected.

Note that since there was only 1 generated key I didn't care about the column name.

If there is more than 1 key that is generated, look into http://docs.spring.io/spring/docs/3.2.7.RELEASE/javadoc-api/org/springframework/jdbc/support/KeyHolder.html#getKeys%28%29

临风闻羌笛 2024-08-28 01:50:24

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

With Spring's JdbcTemplate you can use its update method with a PreparedStatementCreator and a GeneratedKeyholder to hold the primary key of the newly inserted row.

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
   }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文