【发布时间】:2015-04-29 16:07:45
【问题描述】:
我正在运行 SQL Anywhere 16.0 并尝试使用 Spring JDBC 模板。我需要做的很简单:在表中插入一行,然后取回自动生成的 ID 值。
public int log() {
SimpleJdbcInsert insertActor =
new SimpleJdbcInsert(ds)
.withTableName("DBA.REQUESTS")
.usingGeneratedKeyColumns("REQUEST_ID");
Map<String, Object> parameters = new HashMap<String, Object>();
parameters.put("USER_ID", userId);
parameters.put("DATA_TYPE_ID", getProductSku());
parameters.put("PRICE", price);
// ...more parameters
Number requestIdNumber = insertActor.executeAndReturnKey(parameters);
return requestIdNumber.intValue();
}
但是 Spring 反复给我错误
org.springframework.dao.InvalidDataAccessResourceUsageException:
The getGeneratedKeys feature is not supported by this database
我使用的驱动应该支持 JDBC 4.0(库是 dbjdbc16.dll,它在路径中,sajdbc4.jar 在 Tomcat lib 目录中)。来自 Tomcat 的相关数据库连接信息是
<Resource auth="Container" description="Pooled connection to the web database"
driverClassName="sybase.jdbc4.sqlanywhere.IDriver"
maxActive="30" maxIdle="5" maxWait="10000" name="jdbc/web"
removeAbandoned="true"
removeAbandonedTimeout="60"
type="javax.sql.DataSource"
url="jdbc:sqlanywhere:Server=web;UID=xxx;PASSWORD=xxx;port=xxxx;LINKS=tcpip(PORT=xxxx)"/>
数据源的 Spring 应用程序上下文是
<jee:jndi-lookup id="dbDataSource" jndi-name="jdbc/web"
expected-type="javax.sql.DataSource" />
所以我的问题是,有没有办法更好地配置东西,以便这种类型的语句起作用? 或如果数据库在某些基本层面上确实不支持这一点,我是否有一个不难看的替代方法来插入值并取回生成的 id。
更新:似乎数据库驱动程序不支持此功能。此处和其他地方的建议是执行 INSERT 而不是紧随其后的 SELECT。当然,问题是如果另一个用户在这两个语句之间插入表中,您将得到错误的值,在这种情况下会非常糟糕。
我现在的解决方法是在相关 DAO 上使用类级锁定,并根据几列(不仅仅是 IDENTITY)进行选择,这样我就可以 99.9% 确定我得到了相同的行.工作就足够了。也就是说,我更喜欢有一种锁定表的事务方式。我不认为标记函数@Transactional 会为此工作,对吧,因为这只会延迟提交,直到所有语句都成功?
【问题讨论】:
-
this question 有帮助吗?
-
不,不幸的是,这正是我所做的。
-
您的驱动是否支持返回生成的密钥?这是 JDBC 4.0 规范中的一个可选特性。您可以通过使用
DatabaseMetaData.supportsGetGeneratedKeys方法检查JDBC 数据库元数据来确定它是否存在。 -
啊——可选功能——解释了它。该方法给出“否”作为答案,这就是 Spring 显示错误的原因。
标签: jdbc spring-jdbc sqlanywhere