此数据库不支持 getGeneratedKeys 功能
Posted
技术标签:
【中文标题】此数据库不支持 getGeneratedKeys 功能【英文标题】:getGeneratedKeys feature is not supported by this database 【发布时间】: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 显示错误的原因。
【参考方案1】:
我根本不是 JDBC 专家,所以我无法直接回答这个问题,但我可以告诉您,SQL Anywhere 服务器确实具备这种能力。如果 JDBC 的东西不起作用,您可以使用 @@identity
变量。获取select @@identity
,它将返回最后一条语句的自动生成值。
免责声明:我在 SAP 工作,从事 SQL Anywhere 工程。
【讨论】:
谢谢格雷姆!不幸的是,这不包括另一个用户在您运行选择之前执行了插入的情况。如果他们有,你会得到错误的值,在这种情况下,这将是非常糟糕的。如果有一种 (JDBC) 方法可以在 SELECT 完成之前锁定表,那将是理想的。 不,事实并非如此。抱歉,我的描述不完整 -select @@identity
返回最后一个插入语句在当前连接上完成 的自动生成值。因此,如果您的连接插入一行,那么另一个连接插入一行,您的连接上的select @@identity
返回插入的行 you 的 id。
非常有趣。不过,我使用了一个连接池——我认为,两个用户可能会共享一个连接,除非有某种方法可以防止这种情况发生?以上是关于此数据库不支持 getGeneratedKeys 功能的主要内容,如果未能解决你的问题,请参考以下文章
getGeneratedKeys() 上的 Grails Hibernate4 升级错误
如何让 Statement.getGeneratedKeys 工作
sql jdbc getgeneratedkeys 返回列“id”未找到,列类型未知