我想创建一个类的实例,该类可以访问基础的嵌入式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();
但是文档不涉及很多内容,而且我是使用数据库的初学者。我的问题是:
还可以理解其他建议来管理访问一个数据库的不同类。先感谢您。
编辑:
只要应用程序正在运行,数据库 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。您应该选择一个有助于传播交易的库。
基于声明式服务的小指南:
通常使用嵌入Geronimo TM的Aries Transaction Manager。
现在,您已经拥有编写代码的一切。您的组件将类似于以下内容:
@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
}
}
}
}
如果不需要事务处理,可以:
http://cookbook.everit.org/persistence/index.html上提供了更复杂的指南(该指南还负责模式创建并使用基于OO的查询)。
更新
您不必为每个SQL语句都获得连接。您应该获得一个连接,在“瞬间”内执行尽可能多的SQL语句,然后对连接进行调用。
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/