【问题标题】:Share a JDBC connection pool between many classes在多个类之间共享一个 JDBC 连接池
【发布时间】:2012-01-03 09:31:23
【问题描述】:

我有一些 c3p0 池封装在一个用于执行 SQL 语句的类中。 它是这样初始化的:

public PooledQueryExecutor(String url, Properties connectionProperties) throws DALException {
        try {
            dataSource = new ComboPooledDataSource();
            dataSource.setDriverClass(DRIVER);
            dataSource.setJdbcUrl(url);
            dataSource.setProperties(connectionProperties);
        } catch (PropertyVetoException ve) {
            throw new DALException(ve);
        }
    }

然后 - 在同一个类中 - 我使用一些方法来执行基本任务:

public CachedRowSet executeSelect(String sql) throws DALException {
        // Get a connection, execute the SQL, return the rows that match, return resources to the pool
    }

“问题”是:
我有很多不同的类来代表我收到的网络数据包。大多数类都需要这个 PooledQueryExecutor 来执行数据库操作,但有些则不需要。我是将这个 PooledQueryExecutor 传递给需要它的类的构造函数(80% 的数据包),还是让 PooledQueryExecutor 成为单例?或者也许是“别的东西”?我也想过使用ThreadLocal 来避免污染我的构造函数,但我认为这不是一个好主意,是吗?

编辑:它不是一个网络应用程序,目前没有使用依赖注入框架。

感谢您的宝贵时间!

【问题讨论】:

    标签: java jdbc connection-pooling


    【解决方案1】:

    对象代表网络数据包?他们使用数据库连接做什么?这对我来说感觉不对。您想多谈谈您正在尝试做的事情以及您的架构是什么?

    我倾向于使数据包对象成为域的纯模型——它们可以保持状态,并且它们应该定义行为,但它们不应该从事在数据库中四处搜寻的业务。数据库访问应该是系统的不同部分,存储层或子系统。其中的关键对象很可能是单例(或者,至少,它们将有一个实例,即使它们不是正式的单例),并且能够很自然地包含一个全局连接池。

    然后是域对象如何与存储子系统交互的问题。确实,您在此处遇到的问题与您询问的有关连接池的问题基本相同。一般来说,我希望有某种控制器对象来协调程序的工作;它们很适合与不同层的对象交谈,并将它们相互介绍。

    具体的例子会使这个解释更容易。告诉我们您的数据包!

    【讨论】:

      【解决方案2】:

      我假设您没有使用任何 DI 框架?如果是这种情况,您有几个选择:

      • PooledQueryExecutor 传递给需要它的类的构造函数。从测试和架构的角度来看,这实际上是相当不错的。

      • 让需要 JDBC 的类实现一些简单的接口,例如:


      interface PooledQueryExecutorAware {
      
          void setPooledQueryExecutor(PooledQueryExecutor executor);
      
      }
      

      然后您甚至可以遍历类并发现哪些实现了这个并在需要的地方注入PooledQueryExecutor。您是在这里重新发现 DI 的一步,但没关系。

      • 类似的方法是创建一个抽象基类,该基类需要 PooledQueryExecutorAware 作为依赖项,并让 protected final 字段保存它。

      • 每个类都知道PooledQueryExecutor - 不推荐,不必要的耦合

      • 单例是你能做的最糟糕的事情,无法测试且难以理解的代码。请不要。

      • ThreadLocal?忘掉它。请记住,明确为王。

      还可以查看JdbcTemplate。它是 Spring 的一部分,但您只能包含 spring-jdbc.jar 和其他少数几个而不使用整个框架。我认为它可以轻松替换您的PooledQueryExecutor

      【讨论】:

      • 目前没有 DI 框架。我实际上是在使用反射创建数据包实例(有数千个,它们都使用相同的构造函数==>“IncomingPacket incomingPacketInstance = incomingPacketConstructor.newInstance(pooledQueryExecutor);”),所以标记使用数据库的数据包的接口是不是一个真正的选择(保持干净的“反射代码”)。如果我放一些“私有静态 PooledQueryExecutor db;”怎么办?在基类 (IncomingPacket) 中。我只需要设置一次,就可以为 JUnit 设置一个模拟对象。
      • 您提供了一些非常有趣的细节。我认为“界面”方法现在更好。只需遍历incomingPacketInstances 的集合并使用instanceof。将来,如果您需要更多依赖项,可以添加更多*Aware 接口。 static 字段(不能是final)将来会很痛苦,相信我。
      • 我将使用接口方法,一旦我在一个数据包中拥有多个我可能(!)需要的对象,它确实会更好。谢谢!
      • @AndrewBourgeois:如果你想保持你的反射代码干净,创建一个抽象的IncomingPacketPostProcessor 有几个实现。每个实现都会获得一个新的IncomingPacket 实例,并允许执行任何修改,例如发现接口和扫描字段。请注意,这与重新发明 DI 容器非常接近。
      • 我不想把你推到不需要它的 Spring/DI 中。当然,您可以使用注解或手动自动装配带有AutowireCapableBeanFactory 的任何对象。但是,只要只注入一个依赖项,本地解决方案就足够了。但是一旦你发现自己注入了多个异构依赖项,使用现成的 DI 可能会更容易。
      【解决方案3】:

      一种常见的方法,例如Web 服务器是让 JNDI 启动并运行,然后从 JNDI 获取数据源。 Simpel JDNI 实现存在于独立应用程序中。

      如果您在程序中使用依赖注入,那么这是一个可以在需要的地方注入资源的绝佳示例。这意味着 Java EE 6 或启用了 Spring/Guice/CDI 的应用程序。

      【讨论】:

        【解决方案4】:

        我更喜欢设置(注入)池。这样你就可以决定某些实例是否应该获得不同的池,你可以用记录器等包装池,并且清楚哪些类需要池。

        我也认为这使代码更容易测试。

        【讨论】:

          猜你喜欢
          • 2019-12-04
          • 2010-11-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-01-01
          • 1970-01-01
          相关资源
          最近更新 更多