JDNI数据源的模式



我使用Tomcat8中的JNDI资源连接到MS-SQL数据库(Azure)。我随机经历Connection closed异常,最终发生Connection peer reset事件。当这种情况发生时,服务已死(每个请求都运行到Connection closed),重新启动tomcat (redploying)是使其再次启动的唯一机会。

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

目前,我正在尝试更好地理解JNDI资源和连接池,我想知道实现注入到其他服务中的服务类的首选模式是什么。例如:

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

  2. 我如何验证数据源的几个选项的执行,例如testOnBorrowremoveAbandoned(参见下面的完整配置)是否正确执行?有一个选项logAbandoned,但我无法在我的日志中看到任何东西。这到底应该出现在哪里?我可以为池指定一个特定的日志级别吗?我只发现org.apache.tomcat.jdbc.pool,但这个类似乎只在创建池时被调用(至少这是日志出现的唯一时刻,即使在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"
        />

Thx, gapvision

Gapvision,您可以查看此链接-连接池的良好设计模式是什么?

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

我想问的是,要实现被注入到其他服务中的服务类,首选的模式是什么。

Try spring data。这对于组织资源访问数据非常有帮助。

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

没有spring(假设你为tomcat构建web应用程序),你可以添加到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(); }
}

或者你可以创建一个单例类并查找DataSource一次,在启动或惰性,像单例一样。

但最好还是试试春季数据

相关内容

最新更新