OSGi中的嵌入式Derby,使用连接池创建多个连接

时间:2014-12-16 14:14:17

标签: java database osgi database-connection derby

我想创建一个类的实例,该类可以访问底层的嵌入式derby数据库,并使用声明式服务将此类传递给绑定到我的数据库包的每个bundle。

我在derby文档中看到,为多个线程共享一个连接存在许多缺陷。所以我想为我正在创建的类的每个实例创建一个连接。由于我只想要一种非常简单的方法来创建多个连接并管理它们,因此使用“MiniConnectionPoolManager”here似乎是个不错的选择。德比的示例代码如下所示:

org.apache.derby.jdbc.EmbeddedConnectionPoolDataSource dataSource = new org.apache.derby.jdbc.EmbeddedConnectionPoolDataSource();
dataSource.setDatabaseName("c:/temp/testDB");
dataSource.setCreateDatabase("create");
MiniConnectionPoolManager poolMgr = new MiniConnectionPoolManager(dataSource, maxConnections);
...
Connection connection = poolMgr.getConnection();
...
connection.close();

但是文档并没有涵盖很多东西,而且我是初学者使用数据库。我的问题是:

  1. 当我创建一个新类时,需要数据库连接来执行insert,update&其他行为。我应该传递'poolMgr'并从新创建的类中调用poolMgr.getConnection()吗?

  2. 我应该何时关闭此连接?我不知道bundle(用户)将使用新类多长时间,所以我应该将新创建的连接保存在私有全局变量中并强制用户执行unregister类,然后我可以关闭连接?或者,当我的数据库包被停用时,我应该关闭所有连接。

  3. 还可以理解其他建议来管理访问一个数据库的不同类。提前谢谢。

    编辑:

    只要应用程序正在运行,我的数据库包中的主类始终处于活动状态。它是请求进出的新类(执行数据库操作)实例的bundle。而且由于它将部署在嵌入式系统中,我只能使用占地面积小的应用程序。

1 个答案:

答案 0 :(得分:3)

您应该在需要时从连接池获得连接,并尽快关闭连接。连接池的工作是重用连接,而不是你的连接。

换句话说:在停用消费者捆绑包之前,不要保持连接处于活动状态。

连接池通常实现DataSource接口,您应该通过它使用池。在这种情况下,您可以轻松替换池实现,而无需更改代码。 E.g:

@Component
public class MyComponent {

    // Connection pool based DataSource
    @Reference
    DataSource dataSource;

    public void myFunction() {
        try (Connection c = dataSource.getConnection()) {
            // Database operations
        } catch (SQLException e) {
            // TODO
        }
    }
}

当您发现自己多次重复相同的代码(获取连接,捕获SQLException)时,您可以编写一个接受功能接口的简单组件。 E.g:

@Component
@Service
public class SQLHelper {

    @Reference // This is a connection pool DataSource
    private DataSource dataSource;

    public <R> R execute(Callback<R> callback) {
        try (Connection c = dataSource.getConnection()) {
            return callback.call(c);
        } catch (SQLException e) {
            throw new UncheckedSQLException(e);
        }
    }
}

您的功能界面如下所示:

public interface Callback<R> {

    R call(Connection connection);

}

你会像这样使用它:

sqlHelper.execute((Connection c) -> {
    // Do some stuff with the connection
});

使用交易

如果你想使用原子事务,我建议你应该将 org.apache.derby.jdbc.EmbeddedXADataSource org.apache.commons.dbcp.managed.BasicManagedDataSource一起使用< / em>来自commons-dbcp。之后,您可以通过JTA处理交易。

很难直接使用JTA API。您应该选择一个可以帮助您传播事务的库。

基于声明服务的小指南:

  • 将derby jar安装到您的OSGi容器中
  • 同时安装pax-derby捆绑包!通过这样做,您将拥有DataSourceFactory OSGi服务
  • 安装everit-dsf-bundle及其依赖项!您将看到两个新的DS组件。通过webconsole为名为XADataSource的配置创建配置!所有配置选项都有说明。
  • 将JTA事务管理器安装到OSGi容器中!你有几个选择。我
  • 安装everit-commons-dbcp-component及其依赖项!您将看到两个新的DS组件。在Web控制台中配置受管理的一个,并将以前创建的XADataSource设置为目标!如果您在同一事务的范围内请求和关闭连接,事务池将负责提供相同的连接。 通常使用嵌入Geronimo TM的Aries Transaction Manager。
  • everit-transaction-helper安装到您的OSGi容器中!您将看到一个带有TransactionHelper接口的新OSGi服务(由可配置的DS组件提供)。

现在你有了编写代码的所有内容。您的组件类似于以下内容:

@Component
@Service
public class MyComponent {

    @Reference
    private DataSource dataSource;

    @Reference
    private TransactionHelper th;

    public void myFunction() {
        th.required(() -> {
            try (Connection c = dataSource.getConnection()) {
                // My SQL statements
            } catch (SQLException e) {
                // TODO
            }
        }
    }
 }

如果您不需要交易处理,您可以:

  • 使用标准EmbeddedDataSource
  • 使用任何非交易连接池
  • 跳过TransactionManager和TransactionHelper捆绑包的安装
  • 跳过代码
  • 中TransactionHelper的使用

http://cookbook.everit.org/persistence/index.html提供了更复杂的指南(也负责架构创建并使用基于OO的查询)。

<强>更新

您不必为每个SQL语句获取连接。你应该得到一个连接,在一个&#34;时刻执行尽可能多的SQL语句。而不是在连接上打电话。

  • 如果必须紧接着运行三个SQL语句,则应该请求连接,执行三个SQL语句,然后在连接上调用close
  • 如果您在池中请求的同一功能中关闭请求的连接,则可能是正确的。您可以将其他函数作为参数调用,但是它们只应该使用它来运行SQL语句而不是返回。
  • 您不应该保持连接并等待其他用户操作。这是连接池的工作。当您在池提供的连接上调用close时,连接不会在物理上关闭,而只会检索到池中。
  • 您应该将连接对象保留在本地变量中。如果对连接对象使用成员变量,则应该怀疑代码有问题(唯一的例外是如果将Connection传递给生存时间很短的对象并且该对象在成员中保存连接变量以获得更清晰的代码。)
  • 请注意,如果您使用Java 6或更早版本,则应关闭finally块中的连接以避免未关闭的连接。

MiniConnectionPoolManager可能是嵌入式设备的绝佳解决方案,因为它确实是&#34; mini&#34;。唯一的问题是它没有实现DataSource接口,所以您的业务代码shuold直接使用MiniCPM类。通过这样做,如果您发现错误或者稍后需要更复杂的池,则切换到其他连接池将更加困难。

如果您决定使用MiniCPM,我建议您编写一个实现DataSource的组件,并将getConnection()函数委托给MiniCPM实例。 E.g:

@Component
@Service
public class MiniCPMDataSourceComponent implements DataSource {

    @Reference
    protected ConnectionPoolDataSource cpDataSource;

    private MiniConnectionPoolManager wrapped;

    @Activate
    public void activate() {
        this.wrapped = new MiniConnectionPoolManager(cpDataSource);
    }

    @Override
    public Connection getConnection() {
        return wrapped.getConnection();
    }

    @Override
    public Connection getConnection(String user, String password) {
        throw new UnsupportedOperationException();
    }

    @Deactivate
    public void deactivate() {
        wrapped.dispose();
    }
}

您可以使用最大连接数和超时(MiniCPM支持)等配置可能性来装饰此组件。如果使用此组件提供的服务,则可以在不更改业务代码的情况下切换连接池。此外,您的业务包不会直接连接到MiniCPM。