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

标签 java database osgi database-connection derby

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

我在derby文档中看到,为多个线程共享一个连接有很多陷阱。因此,我正在考虑为要创建的类的每个实例创建一个连接。由于我只希望使用一种非常简单的方法来创建多个连接并对其进行管理,因此使用“MiniConnectionPoolManager” here似乎是一个不错的选择。 derby的示例代码如下所示:

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();

但是文档不涉及很多内容,而且我是使用数据库的初学者。我的问题是:
  • 当我创建一个新类时,它将需要数据库连接来执行插入,更新和其他操作。我应该传递“poolMgr”并从新创建的类中调用poolMgr.getConnection()吗?
  • 我什么时候应该关闭此连接?我不知道 bundle 包(用户)将使用新类多长时间,因此我应将新创建的连接保存在私有(private)全局变量中,并强制用户执行注销类,然后再关闭该类吗?还是应该在停用数据库 bundle 包时关闭所有连接。

  • 还可以理解其他建议来管理访问一个数据库的不同类。先感谢您。

    编辑:

    只要应用程序正在运行,数据库 bundle 包中的主类始终处于 Activity 状态。 bundle 包请求新类的实例(执行数据库操作)来去去去。而且由于它将被部署在嵌入式系统中,所以我只能使用占用空间小的应用程序。

    最佳答案

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

    换句话说:在停用消费包之前,请不要保持连接状态。

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

    @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)时,可以编写一个接受功能接口(interface)的简单组件。例如。:
    @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
    });
    

    使用事务

    如果要使用原子事务,建议您使用commons-dbcp中的org.apache.derby.jdbc.EmbeddedXADataSource和org.apache.commons.dbcp.managed.BasicManagedDataSource一起使用。之后,您可以通过JTA处理事务。

    很难直接使用JTA API。您应该选择一个有助于传播交易的库。

    基于声明式服务的小指南:
  • 将derby jar安装到OSGi容器
  • 也安装pax-derby bundle 包!这样,您将获得一个DataSourceFactory OSGi服务
  • 安装everit-dsf-bundle及其依赖项!您将看到两个新的DS组件。通过网络控制台为一个名为XADataSource的配置创建配置!所有配置选项都有说明。
  • 将JTA事务管理器安装到OSGi容器中!您有几种选择。我
  • 安装everit-commons-dbcp-component及其依赖项!您将看到两个新的DS组件。在Web控制台中配置托管服务器,并将先前创建的XADataSource设置为目标!如果您请求并关闭同一事务的范围内的连接,则事务池将负责提供相同的连接。
    通常使用嵌入Geronimo TM的Aries Transaction Manager。
  • everit-transaction-helper安装到您的OSGi容器中!您将看到带有TransactionHelper接口(interface)的新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 bundle 包
  • 的安装
  • 从代码
  • 中跳过TransactionHelper的使用

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

    更新

    您不必为每个SQL语句都获得连接。您应该获得一个连接,在“瞬间”内执行尽可能多的SQL语句,然后对连接进行调用。
  • 如果必须彼此直接运行三个SQL语句,则应请求一个连接,执行这三个SQL语句,然后在连接上调用close
  • 如果您在从池中请求的同一函数中关闭了所请求的连接,则可能做对了。您可能会调用将连接作为参数传递的其他函数,但是它们仅应使用它来运行SQL语句,而不要返回。
  • 您不应保持连接状态并等待其他用户操作。那就是连接池的工作。当您在池提供的连接上调用关闭时,该连接不会物理上关闭,而只会被检索到池中。
  • 您应该将连接对象保留在局部变量中。如果对连接对象使用成员变量,则应该怀疑代码有问题(唯一的异常(exception)是,如果将Connection传递给存在时间很短的对象,并且该对象将连接保存在成员中变量以使用更清晰的代码)。
  • 请注意,如果您使用Java 6或更早版本,则应在finally块中关闭连接,以避免未关闭的连接。

  • MiniConnectionPoolManager确实是“微型”的,因此对于嵌入式设备而言可能是一个很好的解决方案。唯一的问题是它没有实现DataSource接口(interface),因此您的业务代码应直接使用MiniCPM类。这样,如果发现错误或以后需要一个更复杂的池,将很难切换到其他连接池。

    如果决定使用MiniCPM,建议您编写一个实现DataSource并将getConnection()函数委托(delegate)给MiniCPM实例的组件。例如。:
    @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支持)之类的配置可能性来装饰该组件。如果使用此组件提供的服务,则可以在不更改业务代码的情况下切换连接池。此外,您的企业 bundle 包将不会直接连接到MiniCPM。

    关于java - OSGi中的嵌入式Derby,使用连接池创建多个连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27506647/

    相关文章:

    java - OSGI:声明性服务在捆绑启动后可用

    java - Executebatch 无法仅在数据库中插入最后一行

    java - uk.co.mmscomputing twain 扫描仪

    php mysql 数据库排序依据

    java - osgi 中的 Optaplanner

    java - 服务模型与扩展器模型?

    java - 在 sqlite 表中找到一个名称并返回 id?

    java - 用户界面 :repeat inside a ui:repeat and LazyInitException

    mysql - 如何在触发器中放置 IF 条件以计算列的值

    database - PostgreSQL 的连接被拒绝,无法从事件状态(已退出)重新启动