JDNI 数据源的模式
Pattern for JDNI datasource
我在 Tomcat8 中使用 JNDI 资源连接到 MS-SQL 数据库 (Azure)。我随机遇到 Connection closed
异常,最终发生 Connection peer reset
事件。发生这种情况时,服务已停止(每个请求的 运行 变为 Connection closed
)并且重新启动 tomcat(redploying)是唯一重新启动它的机会。
在我尝试解决这个问题的过程中,我双重(三次)检查了每个未关闭连接的方法,我确保每个连接都以 try-with-ressource
.
打开
目前我正试图更好地了解 JNDI 资源和连接池,我想问的是实现注入到其他服务的服务 class 的首选模式是什么。例如。问题是
调用ctx.lookup()
应该把DataSource
分配到哪里?在方法级别或 class 范围?例如。使用 hk2 @Service
注释时,服务似乎只实例化一次,而不是按请求实例化。当前 ctx.lookup()
被调用一次(在构造函数中)并且 DataSource
存储在 class 字段中,稍后由使用 this.dataSource
的方法访问。这有意义吗?或者应该在每次请求(=方法调用)时检索 DataSource
如何验证数据源的几个选项的执行情况,例如testOnBorrow
和 removeAbandoned
(请参阅下面的完整配置)是否正确执行?有一个选项 logAbandoned
但我在日志中看不到任何内容。无论如何,这应该出现在哪里?我能以某种方式为池指定特定的日志级别吗?我只找到了 org.apache.tomcat.jdbc.pool
,但是这个 class 似乎只在创建池时被调用(至少这是日志出现的唯一时刻,即使在 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"
/>
谢谢,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?
您可能希望使用对象池模式。
希望这有帮助!!
我在 Tomcat8 中使用 JNDI 资源连接到 MS-SQL 数据库 (Azure)。我随机遇到 Connection closed
异常,最终发生 Connection peer reset
事件。发生这种情况时,服务已停止(每个请求的 运行 变为 Connection closed
)并且重新启动 tomcat(redploying)是唯一重新启动它的机会。
在我尝试解决这个问题的过程中,我双重(三次)检查了每个未关闭连接的方法,我确保每个连接都以 try-with-ressource
.
目前我正试图更好地了解 JNDI 资源和连接池,我想问的是实现注入到其他服务的服务 class 的首选模式是什么。例如。问题是
调用
ctx.lookup()
应该把DataSource
分配到哪里?在方法级别或 class 范围?例如。使用 hk2@Service
注释时,服务似乎只实例化一次,而不是按请求实例化。当前ctx.lookup()
被调用一次(在构造函数中)并且DataSource
存储在 class 字段中,稍后由使用this.dataSource
的方法访问。这有意义吗?或者应该在每次请求(=方法调用)时检索DataSource
如何验证数据源的几个选项的执行情况,例如
testOnBorrow
和removeAbandoned
(请参阅下面的完整配置)是否正确执行?有一个选项logAbandoned
但我在日志中看不到任何内容。无论如何,这应该出现在哪里?我能以某种方式为池指定特定的日志级别吗?我只找到了org.apache.tomcat.jdbc.pool
,但是这个 class 似乎只在创建池时被调用(至少这是日志出现的唯一时刻,即使在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"
/>
谢谢,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?
您可能希望使用对象池模式。 希望这有帮助!!