使用 Vaadin 和获取数据库是正交的问题,彼此之间没有真正的关系。
DataSource接口
通常最好为您的特定数据库定义一个DataSource 对象。
以H2 Database Engine 及其DataSource implementation 为例。
// Setup the data source.
JdbcDataSource ds = new JdbcDataSource();
ds.setURL("jdbc:h2:˜/test");
ds.setUser("sa");
ds.setPassword("sa");
return ds ; // Return as a `DataSource` object rather than concrete class.
研究您的特定JDBC driver 以找到DataSource 的可能实现。例如,JDBC driver for Postgres by postgresql.org provides org.postgresql.ds.PGConnectionPoolDataSource(池化)和 org.postgresql.ds.PGSimpleDataSource(非池化)。
然后,当您需要与数据库通信时,请求该对象建立数据库连接。完成该数据库操作后,关闭连接。
Connection conn = myDataSource.getConnection() ;
您可以使用 Java try-with-resources 语法简单地做到这一点。
try (
Connection conn = myDataSource.getConnection() ;
)
{
…
// Use `conn` object to work with database.
// When going out of scope here, the connection's `close` method is automatically called.
}
有些人强烈推荐使用connection pooling。我确实不推荐连接池,除非是为了解决一个已证实的问题。连接池很难正确处理,有几个臭名昭著的失败项目,还有一些项目甚至不推荐自己用于生产环境。即使实施得当,连接池也总是会带来额外的问题,例如连接返回池的情况不佳,例如事务挂起。每次从新连接开始是最安全的路线。有些人谴责获得新数据库连接的费用。但是,无论是我自己的经验还是其他人通过正式测试客观地提出的证据,我都没有看到过这种费用的证据。
如果您仍然决定使用池,您的 DataSource 实现可以在后台处理池。因此,此答案中讨论的代码和概念适用于池化和非池化数据源对象。这就是DataSource 接口的意义所在,用于掩盖诸如池化与非池化之类的差异。见Oracle Tutorial。
ServletContext 和“属性”
然后问题就变成了在哪里存储您的 DataSource 对象。这就是 Vaadin 出现的地方。
Vaadin 基于Jakarta Servlet(以前称为 Java Servlet)技术。实际上,Vaadin 是一个大 servlet。您的 Vaadin Web 在能够托管 servlet 的服务器上运行。该服务器需要支持Jakarta Servlet specification。该规范需要支持代表整个正在运行的 Web 应用程序的 javax.servlet.ServletContext 对象。一个“上下文”有零个、一个或多个当前运行您的网络应用程序的“会话”对象,每个用户每个网络浏览器一个会话。
我们感兴趣的地方在于ServletContext 为您可能希望保留的任何对象提供缓存,以供您应用程序的所有会话(用户)使用。这个缓存被称为“属性”,一个键值集合,其中键是String。您可以在此处存储您的DataSource,并使用"javax.sql.DataSource" 作为密钥。
那么如何访问代表我们网络应用的ServletContext 对象呢?请参阅 this Question 了解解释和可能的更好方法。
ServletContext servletContext =
VaadinServletService // com.vaadin.flow.server.VaadinServletService
.getCurrentServletRequest() // Returns a javax.servlet.http.HttpServletRequest
.getServletContext() // Returns a `javax.servlet.ServletContext`.
;
现在我们可以存储我们的DataSource 实现对象。我们可以使用任何String,只要它在键值集合中是不同的。提示:使用您自己的域名为您的密钥字符串添加前缀以确保唯一性。
servletContext.setAttribute( "com.example-javax.sql.DataSource" , dataSource ) ;
并通过任何需要访问数据库的代码进行检索。键值集合将值存储为Object,因此我们必须进行强制转换。
DataSource dataSource = (DataSource) servletContext.getAttribute( "com.example-javax.sql.DataSource" ) ;
提示:您可能应该测试 NULL 结果。
您的积分
我不希望在每个会话中建立连接。
不,您不希望为每个会话创建一个数据库连接,通常不会。维护打开的数据库连接会占用客户端和服务器上的资源(内存、CPU、端口等)。
当您需要进行数据库工作时,请向您的DataSource 对象询问Connection。完成数据库后,调用 Connection::close 或让 try-with-resources 语法自动执行此操作。
不过,据我所知,vaadin 在会话级别工作。
Vaadin 只是一个 Jakarta Servlet。 servlet 只是将大部分 HTTP 和 Web 工作委托给 Web 容器(例如 Tomcat、Jetty 或 Glassfish 等)的 Web 应用程序。
尽管 HTTP 的无状态请求-响应架构,但常见 Web 工作的一部分是创建有状态连接的假象。 Cookie 或其他技巧用于在多个请求之间跟踪单个用户。基于 Servlet 的 Web 容器代表我们作为 Web 应用程序程序员处理此问题,创建对象以将每个用户作为“会话”进行跟踪。 Vaadin 在这方面并没有什么特别之处。
是否可以创建一个无论会话都将持续存在的类,然后,vaadin 会话将查询它以获取数据库连接?
Vaadin 和数据库连接是两个彼此不直接相关的主题。
我建议您进行更多研究,以真正了解基本的 Web 技术,以了解 HTTP 请求/响应的工作原理,以及会话如何产生有状态连接的错觉。这适用于所有网络工作,而不仅仅是 Vaadin。 Vaadin 建立在此基础之上,因此要了解 Vaadin,您需要了解 Web 的基础知识。