JDNI 数据源的模式

Pattern for JDNI datasource

我在 Tomcat8 中使用 JNDI 资源连接到 MS-SQL 数据库 (Azure)。我随机遇到 Connection closed 异常,最终发生 Connection peer reset 事件。发生这种情况时,服务已停止(每个请求的 运行 变为 Connection closed)并且重新启动 tomcat(redploying)是唯一重新启动它的机会。

在我尝试解决这个问题的过程中,我双重(三次)检查了每个未关闭连接的方法,我确保每个连接都以 try-with-ressource.

打开

目前我正试图更好地了解 JNDI 资源和连接池,我想问的是实现注入到其他服务的服务 class 的首选模式是什么。例如。问题是

  1. 调用ctx.lookup()应该把DataSource分配到哪里?在方法级别或 class 范围?例如。使用 hk2 @Service 注释时,服务似乎只实例化一次,而不是按请求实例化。当前 ctx.lookup() 被调用一次(在构造函数中)并且 DataSource 存储在 class 字段中,稍后由使用 this.dataSource 的方法访问。这有意义吗?或者应该在每次请求(=方法调用)时检索 DataSource

  2. 如何验证数据源的几个选项的执行情况,例如testOnBorrowremoveAbandoned(请参阅下面的完整配置)是否正确执行?有一个选项 logAbandoned 但我在日志中看不到任何内容。无论如何,这应该出现在哪里?我能以某种方式为池指定特定的日志级别吗?我只找到了 org.apache.tomcat.jdbc.pool,但是这个 class 似乎只在创建池时被调用(至少这是日志出现的唯一时刻,即使在 FINEST 级别)。

  3. 有没有我不知道的一般模式?

这是我当前的配置:

<Resource name="jdbc/mssql"
          auth="Container"
          type="javax.sql.XADataSource"
          driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
          username="***"
          password="***"
          url="jdbc:sqlserver://***.database.windows.net:1433;database=***;encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;loginTimeout=30;"
          factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
          removeAbandonedOnBorrow="true"
          removeAbandonedTimeout="55"
          removeAbandonedOnMaintenance="true"
          timeBetweenEvictionRunsMillis="34000"
          minEvictableIdleTimeMillis="55000"
          logAbandoned="true"
          validationQuery="SELECT 1"
          validationInterval="34000"
        />

谢谢,gapvision

I'm asking what is the preferred pattern to implement a service class which is injected into other services.

尝试spring数据。对组织资源访问数据很有帮助。

没有spring,没有tomcat内置功能,你确实需要创建自己的单例来分配DataSource或ConnectionPool。

没有 spring(假设您为 tomcat 构建网络应用程序),您可以添加到 web.xml:

<resource-ref>
<description>H2DB</description>
<res-ref-name>jdbc/project1</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>

并且在 tomcat 的 context.xml 中:

<Resource name="jdbc/project1" auth="Container" type="javax.sql.DataSource" driverClassName="org.h2.Driver"  url="jdbc:h2:tcp://localhost/~/project1"   username="sa" password="" maxActive="20" maxIdle="10" maxWait="-1"/>

然后你可以在每个请求中查找数据源:

Context ctx = new InitialContext();
Context envContext = (Context) ctx.lookup("java:comp/env");
DataSource ds = (DataSource) envContext.lookup("jdbc/project1");
Connection conn = null;
try {
conn = ds.getConnection();
PreparedStatement ps = conn.prepareStatement("INSERT INTO USERS (NAME) VALUES (?)");
ps.setString(1,name);
ps.executeUpdate();
response.getWriter().write("added user "+name);
response.getWriter().write("\n");
} finally {
if (conn!=null) { conn.close(); }
}

或者您可以创建一个单例 class 并像单例一样在启动或延迟时查找一次数据源。

但最好尝试 spring 数据。

Gapvision,你可以看看这个link - What is the good design pattern for connection pooling?

您可能希望使用对象池模式。 希望这有帮助!!