我正在使用 simpleJdbcTemplate 将数据放入数据库。
simpleJdbcTemplate.update("insert into TABLE values(default)");
我不想放任何数据,因为我不需要它来进行单元测试。
如何从插入的行中获取 id?我可以检索当前序列值,但如果其他人会进行插入,那么我将获得下一个序列值。
有什么方法可以使用 simpleJdbcTemplate 插入一行并获取 id?更新方法重新调整插入的行数,我想拥有 id。谢谢您的帮助。
我正在使用 simpleJdbcTemplate 将数据放入数据库。
simpleJdbcTemplate.update("insert into TABLE values(default)");
我不想放任何数据,因为我不需要它来进行单元测试。
如何从插入的行中获取 id?我可以检索当前序列值,但如果其他人会进行插入,那么我将获得下一个序列值。
有什么方法可以使用 simpleJdbcTemplate 插入一行并获取 id?更新方法重新调整插入的行数,我想拥有 id。谢谢您的帮助。
你找到答案了吗?如果没有,请尝试SimpleJdbcInsert改用。例如:
SimpleJdbcInsert sji = new SimpleJdbcInsert(dataSource)
.withTableName(TableName)
.usingColumns(new String[]{your columns})
.usingGeneratedKeyColumns(you auto-increment id colums);
然后检索
sji.executeAndReturnKey(args).longValue();
我不认为它看起来很艰难.. :-O
你不要尝试类似的东西:
int newID = simpleJdbcTemplate.queryForInt("INSERT INTO TABLE(Column_Names)
values (default)
RETURNING ID");
现在newID将包含新插入的行 ID。
干杯..!!:)
您需要手动处理序列以轻松获取 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;
}
使用 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;
}
}
您应该首先id从适当的查询sequence,然后id在您的插入语句中提供它。就如此容易。
此外,可以说,我们将其称为集成测试,而不是单元测试。您可能想参考这个 SO 线程以了解有关集成测试和 id 的想法。
[评论后编辑]
在这种情况下,摆脱那个触发器。并在 make 之前直接id从 中检索。sequenceinsert
好吧,您可以在桌子上触发 a SELECT... FOR UPDATE,然后抓住最后一个id,并将其增加 1。如果您id的不是顺序的,我猜不会是这种情况,您可以保留ROWIDOracle AFAIK 特有的 ,然后查询id使用它。确实,这一切都可以解决。
注意: 我强烈建议您查看 Aaron Digulla 的帖子。看看这些是否足够。
回答这个问题:您想通过测试达到什么目的?检查更新是否正常运行?每次都换新身份证?该表存在吗?
根据答案,您必须修改您的测试。如果您只想知道语句的语法是否正确,则无需执行任何操作,只需运行该语句(如果出现错误导致测试失败,它将抛出异常)。
如果要确保每次都获得一个新的 ID,则必须查询该序列两次,并检查第二个值是否与第一个不同。
如果您想检查是否插入了具有新唯一 ID 的行,只需运行插入并检查它是否返回 1。如果它有效,您将知道主键(ID)没有被违反,并且行已插入。因此,“使用唯一 ID 添加”机制必须有效。
[编辑] 无法测试将 ID 添加到新行的触发器,因为 Oracle 无法返回它刚刚创建的 ID。您可以读取序列,但不能保证nextval-1会给您与触发器看到的相同结果。
您可以尝试select max(ID),但如果其他人在您运行查询之前插入另一行并提交它(使用默认事务级别READ_COMMITTED),则可能会失败。
因此,我强烈建议摆脱触发器并使用其他人使用的标准两步(“获取新 ID”加上“插入新 ID”)算法。它将使您的测试更简单,更不脆弱。
不推荐使用 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
使用 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
}
}