请教一个代理 JDBC 连接方案的可行性

2019-03-06 17:50:39 +08:00
 Lighfer

上头要求要实现一个通用的数据库访问服务,其他业务系统所有的数据库访问都会通过该服务来执行,但是又不希望在开发阶段拆分出来(是的,我也很纳闷为什么非要这样,已经提出过其他方案都被打回了),因此,想到如下的实现方案:

  1. 实现一个执行服务,该服务中维护连接池(HikariCP),及池内 Connection 等的状态
  2. 实现一个 DataSource 模块,代理 Connection、Statement、PreparedStatement、CallableStatement、ResultSet 的所有方法,将调用转发到执行服务,可采用 RPC 的方式,并需要带上一个唯一标识符,假设是 UUID
  3. 执行服务收到调用后,根据 UUID 找到对应的 Connection,如果没有的话就从连接池中获取一个 Connection,并标记该 Connection 处于使用中的状态,不允许被其他调用使用
  4. 业务系统按照正常的方式(JPA)进行开发,但是需要修改数据库连接的数据源,改由 DataSource 模块提供
  5. 对于使用中的 Connection,都要维护其打开的 Statement、PreparedStatement、CallableStatement、ResultSet,直到调用 close,调用 close 后除 Connection 外其他释放资源,将 Connection 归还到连接池

该方案目前想到的一个问题比较不好处理的问题:ResultSet 有可能是懒加载的,也就意味着一条查询可能会需要多次从执行服务中获取结果集,对于插入和更新同理

个人觉得该方案理论上是可行的,且不算是特别复杂,但是又担心有哪些隐形的坑,所以想请教各位帮忙分析下,万分感谢!

2021 次点击
所在节点    Java
1 条回复
Lighfer
2019-03-07 17:05:07 +08:00
虽然没人回我.. 但是还是自己回一个结论吧:该方案不可行,根本原因如下:

如果要实现数据库访问和业务开发独立,就意味着业务系统对数据的处理(如:映射 ResultSet 为对应的 Java 对象)和最终执行访问数据库的 JDBC 连接不是在一个服务内
JDBC 执行结果最终是返回 ResultSet,而 ResultSet 在该场景下存在两个问题
1. ResultSet 不可序列化,意味着远程服务调用没法直接返回
2. 数据库驱动对 ResultSet 的实现是持有数据库连接的,因为 ResultSet 从数据库中取值不一定是一次性加载,可能会在调用`ResultSet.next`根据需要多次通过 Connection 取值,这意味着远程返回给业务系统的 ResultSet 是不可能持有 Connection 的

针对问题 1:可以采用对不同的数据库驱动实现的 ResultSet 进行封装,这个还是属于可解决问题
针对问题 2:只能(在我看来只能)在业务系统上对的 ResultSet 的所有方法代理,转发给远程实际的 ResultSet 执行,但是这会导致两个系统之间的交互非常频繁,大大增加资源消耗和延迟。

也就是说,由于业务系统不持有数据库连接,如果要实现通用的数据库访问服务,那么就需要保证业务系统每一次调用都能直接获得完整的结果,这就需要对 ResultSet 的处理在数据库访问服务这一侧实现,而这部分逻辑是业务相关的,是在业务系统这一侧实现的。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/541833

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX