我正在用Java开发一个小项目,并且我有DatabaseController类,该类包含许多可以从数据库中插入/选择/删除的方法。
我的问题是有关建立最佳软件工程实践方面的联系。
我了解两者都可能有缺点也有优点。.但我想知道哪种方法最适合小型和大型项目?
答案 0 :(得分:1)
DataSource
首先,最好将对数据库的访问放在DataSource
界面后面。这使您能够更改获取数据库连接的策略,而无需更改代码中使用这些数据库连接的所有位置。参见Oracle Tutorial。
您的JDBC driver应该提供DataSource
的实现。例如,考虑来自https://jdbc.postgresql.org的Postgres JDBC驱动程序。该驱动程序supplies two implementations:一个用于直接连接到数据库,另一个用于pooling connections。通过使用DataSource
作为外观,您可以在代码中的一个位置之间切换,甚至可以使用第三方连接池解决方案,而无需更改调用DataSource::getConnection()
的位置。
您可能要替代的第三种实现方式是distributed transactions。
在接口后面交换具体类的另一个示例:也许您决定切换JDBC驱动程序。也许对于您的Postgres数据库,您决定从jdbc.postgresql.org driver切换到pgjdbc-ng driver。您希望能够在一处更改此配置,而又不破坏所有现有的应用程序代码。
这里是在DataSource
接口后面使用具体实现的示例。
public javax.sql.DataSource obtainDataSource() {
org.postgresql.ds.PGSimpleDataSource dataSource = new PGSimpleDataSource() ;
dataSource("AcmeInvoices database data source") ;
source.setServerName( "localhost" ) ;
source.setDatabaseName( "invoicing" ) ;
source.setUser( "Scott" ) ;
source.setPassword( "tiger" ) ;
return dataSource ; // Returning a reference to the object of this concrete class `PGSimpleDataSource` as an object of the interface `DataSource`.
}
您在上述代码段中看到的调用方法将因数据库和JDBC driver的功能而异。例如,如果您使用到数据库的加密连接,则将有其他方法可调用以配置加密密钥。
您可能会在应用启动时尽早设置此DataSource
对象。保持参考的地方。或保留几个:对于应用程序的不同部分,您可能具有不同的连接类型(不同的用户名和密码),需要不同的安全性或不同的用户角色。
将代码库中的DataSource
对象传递给许多用于插入/选择/删除数据库的方法。在每种方法中,它们都调用myDataSource.getConnection()
,然后继续执行其SQL。该方法完成工作后,应通过调用Connection::close
关闭连接。更好的是,使用try-with-resources自动关闭连接。
如果连接来自连接池,则该连接并没有真正关闭。而是,连接返回到池中。这是使用界面(此处为Connection
)的强大功能的另一个示例。接口后面的具体类可以选择如何响应调用close
的方法-并且可以稍后换出具体类而不会破坏调用代码。
我应该在DatabaseController构造函数中建立数据库连接,以便将其打开一次并保持打开状态
不,保持连接打开而不进行进一步工作通常不是一个好主意。
基本上,您将创建自己的连接池。连接池并不是一件容易的事。池中要考虑各种问题,而您不太可能认为它们没有能力解决这些问题。我见过的所有连接池工具都有各自的bug,问题和局限性。因此,不要自己承担这项任务。如果您确实选择使用池,请找到一个可靠的,陈旧的现有实现。并仔细研究其文档,以确保您了解如何正确配置和使用该池。
坦白说,我自己停止使用连接池。在我看来,对于用户/连接次数较少,频率较低的系统,各种风险和复杂性都不值得。例如,查看各种池解决方案中的默认超时设置,其中在一段时间不使用后关闭池连接。如果您在池中的活动大多低于该超时时间,那么您实际上将不会从池中受益。另外,我发现,关于以昂贵的价格打开与数据库的连接的大多数主张都被夸大了,尤其是对于同一台机器上的本地数据库。
我应该在插入/删除/选择方法之前放置一种方法来连接数据库
下面是一些示例场景,这些场景显示了如何在与特定的数据库任务相同的位置使用数据库连接。
在登录屏幕上,您可以通过查找数据库中存储的用户和组来对用户进行身份验证,当用户单击Login
按钮时,您的代码应检索对DataSource
对象的引用,调用getConnection
,进行用户和组查询,然后立即关闭连接。
当用户继续查找过期发票时,请执行相同的操作。检索DataSource
,调用getConnection
,运行SQL以查找任何过期的发票,将该发票数据作为缓存加载到内存中,调用Connection::close
以关闭与数据库的连接,然后继续构建您的GUI以显示缓存的发票数据。
当用户单击按钮以对其中一张发票执行某些操作时,请执行相同的过程。检索DataSource
,调用getConnection
,运行SQL来获取所需主键值的特定发票行,检索其他发票字段和相关行(如发票项),调用Connection::close
以关闭与数据库的连接,然后继续执行操作,例如生成包含缓存的发票明细及其发票项目行的电子邮件。请注意,您如何在此操作方法中多次使用连接,首先单击发票表,然后再次单击发票项目表。最终所有即将完成的即时工作完成后,关闭连接。
请记住,在这几次连接中,如果已合并,则每次都关闭连接:
该池可能会在某个时候关闭该连接,并可能在某个时候用一个新的连接替换它。但这对所有用户身份验证代码和发票查询代码都是透明的。