我在Tomcat8中使用JNDI资源来连接到MS-SQL数据库(Azure)。随机我遇到Connection closed
异常,最后是Connection peer reset
个事件。发生这种情况时,服务已经死亡(每个请求都运行Connection closed
)并重新启动tomcat(redploying)是唯一一次再次启动它。
在试图解决这个问题的过程中,我对未闭合连接的每个方法进行了双重(三次)检查,我保证每个连接都以try-with-ressource
打开。
目前我正在努力更好地了解JNDI资源和连接池,我问的是实现一个注入其他服务的服务类的首选模式。例如。问题是
通过致电DataSource
,应该在哪里分配ctx.lookup()
?在方法级别或类范围?例如。当使用hk2 @Service
注释时,似乎服务仅实例化一次而不是每个请求。当前ctx.lookup()
被调用一次(在构造函数中),DataSource
存储在类字段中,稍后由方法使用this.dataSource
访问。这有意义吗?或者应该在每个请求(=方法调用)
DataSource
如何验证DataSource的多个选项的执行,例如testOnBorrow
和removeAbandoned
(请参阅下面的完整配置)是否正确执行?有一个选项logAbandoned
但我在日志中看不到任何内容。无论如何这应该出现在哪里?我可以以某种方式指定池的某个日志级别吗?我只找到org.apache.tomcat.jdbc.pool
,但这个类似乎只在创建池时被调用(至少这是日志出现的唯一时刻,即使在级别FINEST
上)。
是否有一些我不知道的一般模式?
这是我目前的配置:
<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
答案 0 :(得分:1)
Gapvision,您可以查看此链接 - What is the good design pattern for connection pooling?
您可能希望使用对象池模式。 希望这会有所帮助!!
答案 1 :(得分:0)
我问的是实现一个注入其他服务的服务类的首选模式。
尝试弹簧数据。它在组织资源以访问数据方面非常有用。
没有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。
但更好的尝试弹簧数据。