我想创建一个类的实例,该类可以访问底层的嵌入式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();
但是文档并没有涵盖很多东西,而且我是初学者使用数据库。我的问题是:
当我创建一个新类时,需要数据库连接来执行insert,update&其他行为。我应该传递'poolMgr'并从新创建的类中调用poolMgr.getConnection()吗?
我应该何时关闭此连接?我不知道bundle(用户)将使用新类多长时间,所以我应该将新创建的连接保存在私有全局变量中并强制用户执行unregister类,然后我可以关闭连接?或者,当我的数据库包被停用时,我应该关闭所有连接。
还可以理解其他建议来管理访问一个数据库的不同类。提前谢谢。
编辑:
只要应用程序正在运行,我的数据库包中的主类始终处于活动状态。它是请求进出的新类(执行数据库操作)实例的bundle。而且由于它将部署在嵌入式系统中,我只能使用占地面积小的应用程序。
答案 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。您应该选择一个可以帮助您传播事务的库。
基于声明服务的小指南:
现在你有了编写代码的所有内容。您的组件类似于以下内容:
@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语句获取连接。你应该得到一个连接,在一个&#34;时刻执行尽可能多的SQL语句。而不是在连接上打电话。
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。