我目前正在使用Cassandra作为PlayFramework项目中的数据库。我正在寻找一个反应性的驱动程序,似乎我的选择仅限于Phantom和Quill。 我对nosql数据库的经验仅限于MongoDB,之前我没有使用任何Quill或Phantom。
查看comparison here,似乎最终可能会在Phantom中编写更多代码。此外,使用DSL来描述模型似乎是违反直觉的(来自繁重的休眠/ JPA背景) - 但这可能只是我。
我想知道是否有人可以提供实用的建议/用例,其中一个人会优于另一个人以及每个人需要注意的事项?
答案 0 :(得分:8)
作为幻影作者的一个略微偏见的观点,我非常了解幻影中的设计目标。 Quill图书馆网站上现有的Quill和Phantom之间存在比较,自然偏向另一个方向。
Phantom旨在成为应用程序级别层的完美选择,其中Quill旨在成为最高级的字符串生成器,当您在Cassandra上构建大型应用程序时,这不是一个非常有用的比较。
使用幻像的优点
关于类型安全以及DSL对Cassandra功能的改进程度,确实没有竞争对手。 DSL非常“亲密”。了解您的数据结构并为Cassandra功能提供全面支持。它在编译时知道对Cassandra有什么可能,以及什么不是。
Quill devs认为幻影有更多的依赖关系,但这并不完全准确,因为大多数都是可选的,包括播放迭代和流支持等。你不想要的就是那么简单。
Quill比较简单地指出:"您可以通过扩展DSL来扩展Phantom以添加新功能,尽管它可能不是一个简单的过程。",这有点不准确。作为游戏中的新玩家,Quill在Cassandra功能支持方面是一个玩具,你经常会发现自己需要添加功能。幻影毫无疑问有其缺口,但它是一个更为成熟的替代品,而且需要延期的次数非常少。
我们已经针对更复杂的功能在几天或几周内解决了大多数错误,但通常您可能需要的一切都已经存在,目前Quill中找不到许多功能,甚至需要几个小时写下来。
我不是来自强大的JPA背景,但Cassandra和幻像之间的映射是一个非常强大的层,因为它允许您直接从映射自动生成表的整个模式DSL。它还允许DSL在编译时完全模仿Cassandra的行为,它将知道哪些查询对于您选择的主键是可能的等等,quill根本没有这样的支持。
Phantom拥有非常强大的应用程序级抽象层,例如连接器,数据库,数据库的自动生成,以及帮助您将应用程序运行到生产中的东西。
Quill背后的代码要复杂得多,虽然我是第一个对其背后的工程能力给予强烈信任的人,但当我认为用户友好时,这个故事并没有得到很好的支持。
Quill尝试一次性做更多事情。它是一代产品的迷你引擎,在他们决定完全专注于SQL dbs并放弃对其他任何东西的支持之前,scalaquery试图在几年前做了一些事情。它是现代Slick的前身,并使用了类似的QDSL引用方法。
Quill是一个泄漏的抽象。由于他们的目标是支持更广泛的数据库,因此他们对数据库特性的特殊性的支持非常低劣。下面是一个例子:
从比较中的基本示例中可以看出:
val getAllByCountry = quote {
(country: String) => query[WeatherStation]
.filter(_.country == country)
}
}
到目前为止,如果我们包含必要的映射代码,那么大概都比幻影等价物更简洁。
select.where(_.country eqs country).fetch()
但让我们进一步探索。如果你试图像这样取一个国家怎么办?或者如果您尝试获取PagingState
信息该怎么办?或者输入现有的PagingState
以在UI上显示内容。
至少在比较中,Quill无法向用户提供他们的体验最终结果的真实预览。很自然地假设,无论何时进入工具页面,它都会将自己描述为同类产品中的最佳工具,因为我们肯定会在幻影背后做到这一点,但这绝不是完整的故事。
更简洁,更酷的事情:
select.where(_.country eqs country).fetchRecord()
select.where(_.country eqs country).one()
部分选择怎么样?
select(_.country, _.city).where(_.country eqs country)
Phantom在语义上区分使用Cassandra在运行时可能发生的所有事情,它首先尝试使用编译时技巧和域知识来防止运行时错误。你怎么能拥有Quill等价物呢?
此外,Quill完全能够直接从case class
生成查询。
case class WeatherStation(
country: String,
city: String,
stationId: String,
entry: Int,
value: Int
)
object WeatherStation {
val getAllByCountry = quote {
(country: String) =>
query[WeatherStation].filter(_.country == country)
}
val getAllByCountryAndCity = quote {
(country: String, city: String) =>
getAllByCountry(country).filter(_.city == city)
}
val getAllByCountryCityAndId = quote {
(country: String, city: String, stationId: String) =>
getAllByCountryAndCity(country, city).filter(_.stationId == stationId)
}
}
但是它缺乏关于你的架构的任何知识。如果国家不是小学的一部分怎么办?该查询无效,幻影不会让你编译它,这只是最基本的例子。
Phantom可以直接从表中自动生成您的CQL,它可以动态生成整个数据库,专业版甚至可以自动迁移表并帮助您处理模式不一致,并为您提供非常高级的UI和监控接口,您可以动态升级和降级模式。
<强>缺点强>
Phantom确实使得TypeCodec
之类的内容略微冗长,但是从幻像2.9.0开始,我们引入了一个非常强大的宏机制来编码Cassandra中没有的类型完全依赖TypeCodec
!
Phantom需要最少的样板来定义表DSL,并且本质上并不能很好地与共享表列一起使用。它可以做到,但它不是最漂亮的代码,也不是最糟糕的代码。
<强>总体强>
答案 1 :(得分:0)
我们从Quill开始,然后由于Phantom的功能和易于改变而去了Phantom。但是,我们遇到了严重的负载测试问题,发现它没有释放CPU线程和网络连接。我们在本地mac机器和AWS EC2-Cluster AMI Linux服务器上进行了测试。基本上资源没有被释放,并且随之而来的是内存不足的异常。如果这个问题得到解决,Phantom会很棒。目前我不建议将Phantom用于任何需要高性能生产系统的人。
在制作的最后一分钟,我们不得不改变所有代码并切换回Quill,这对我来说很痛苦。
我已经与Phantom打开了一个问题,希望他们可以尽快解决这个问题。附上一个项目,通过并行运行一个简单的JSON / REST scala项目来测试Quill和Phantom之间的负载。
https://github.com/yleun/cassandra-loadtest
如果Phantom可以解决这个内存不足的问题,它可能会成为Quill的优秀数据库客户端,但是现在它还没有生产就绪,我希望其他人在遇到问题后不要再遇到问题。花大量时间用幻影建造。