【发布时间】:2015-03-13 08:50:48
【问题描述】:
我有一个 PlayFramework 服务器(使用 Anorm),它针对具有多个架构的数据库进行操作,所有架构都具有相同的表。
我的大部分“访问数据库”函数看起来像:
def findById(zoneName: String, id: Long): Option[Employee] = {
DB.withConnection { implicit connection =>
SQL("""select *
from """+zoneName+"""employee
where employee._id = {id}"""
.on(
'_id -> id
).as(simpleParser.singleOpt)
}
}
但我知道这是一种错误的方法,因为它不是 SQL 注入安全的,而且在每个函数中编写当然很乏味。
我想使用字符串插值来纠正这个问题,它适用于我的 id 变量,但不适用于 zoneName:
def findById(zoneName: String, id: Long): Option[Employee] = {
DB.withConnection { implicit connection =>
SQL"""select *
from $zoneName.employee
where employee._id = 1"""
.as(simpleParser.singleOpt)
}
}
给我:
info] ! @6lenhal6c - Internal server error, for (GET) [/limbo/br/employee/1] ->
[info]
[info] play.api.Application$$anon$1: Execution exception[[PSQLException: ERROR: syntax error at or near «$1»
[info] Position: 25]]
[info] at play.api.Application$class.handleError(Application.scala:296) ~[play_2.11-2.3.8.jar:2.3.8]
[info] at play.api.DefaultApplication.handleError(Application.scala:402) [play_2.11-2.3.8.jar:2.3.8]
[info] at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$3$$anonfun$applyOrElse$4.apply(PlayDefaultUpstreamHandler.scala:320) [play_2.11-2.3.8.jar:2.3.8]
[info] at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$3$$anonfun$applyOrElse$4.apply(PlayDefaultUpstreamHandler.scala:320) [play_2.11-2.3.8.jar:2.3.8]
[info] at scala.Option.map(Option.scala:146) [scala-library-2.11.5.jar:na]
[info] Caused by: org.postgresql.util.PSQLException: ERROR: syntax error at or near «$1»
[info] Position: 25
[info] at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2198) ~[postgresql-9.3-1102.jdbc4.jar:na]
[info] at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1927) ~[postgresql-9.3-1102.jdbc4.jar:na]
[info] at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:255) ~[postgresql-9.3-1102.jdbc4.jar:na]
[info] at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:561) ~[postgresql-9.3-1102.jdbc4.jar:na
也使用${zoneName} 进行了测试,结果相同。
任何有关如何编写此内容的帮助或建议将不胜感激,在此先感谢您!
【问题讨论】:
-
您可以设置
search_path以包含您在调用函数之前“当前”处理的架构。或者,如果您使用不同的数据库用户,则将该用户的默认search_path设置为该用户应使用的架构名称。 -
我考虑过这个选项,但我放弃了它,因为将来我需要支持超过 1 个模式的查询
-
那么我认为除了在运行时连接正确的模式之外,您别无选择。老实说,这个设置看起来确实有点奇怪。您试图通过在不同模式中使用“相同”表来解决什么问题?也许有更好的方法来解决那个
-
也许有更好的解决方案,是的。我所做的是让几家公司(或同一家公司的分支机构)使用同一个数据库。我的服务器是访问这些数据的 RESTful 提供程序。通过这种方式,我将数据从一家公司保存到另一家公司,但我保留了进行暗示多个模式的查询的可能性。正如您所建议的,也许一种方法是让 db 用户使用 search_path 并使用正确的用户进行查询?还是保留分开的数据库?
-
你提前知道哪些查询会是跨模式的吗?如果这样做,您可以在“默认”模式中创建视图,以结合来自其他模式的信息。这样,您可以更改请求中的
search_path以匹配当前租户,而不必担心在单个查询中访问来自不同架构的对象。
标签: anorm string-interpolation