【问题标题】:Jboss datasource recovering after database re-start数据库重新启动后Jboss数据源恢复
【发布时间】:2011-01-08 10:46:44
【问题描述】:

已关闭的连接仍在连接池中 - 为什么?

servlet-

public class Index extends HttpServlet {

    TimeZoneService timeZoneService;

    public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException {
        WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
        timeZoneService = (TimeZoneService) ctx.getBean("timeZoneService");
        timeZoneService.loadAllTimeZones();
        System.out.println("Done");
    }
}

public interface TimeZoneService {
    void loadAllTimeZones();
}

public class TimeZoneServiceImpl implements TimeZoneService {

    private TimeZoneDao tzDao;
    private Map<Long, String> tzOid2JavaName = new HashMap<Long, String>();

    public void loadAllTimeZones() {
        List<TimeZone> timeZones = tzDao.findAllTimeZones();
        for (TimeZone tz : timeZones) {
            tzOid2JavaName.put(tz.getOid(), tz.getJavaName());
        }
    }

    public void setTzDao(TimeZoneDao tzDao) {
        this.tzDao = tzDao;
    }
}

public interface TimeZoneDao {
    List<TimeZone> findAllTimeZones() throws DataAccessException;  
}

public class TimeZoneDaoImpl extends JdbcDaoSupport implements TimeZoneDao {

    public List<TimeZone> findAllTimeZones() throws DataAccessException
    {
        StringBuffer sql = new StringBuffer();
        sql.append("SELECT TZ.OID, TZ.JAVA_NAME FROM TIME_ZONE TZ");
        List<TimeZone> timeZones = getJdbcTemplate().query(sql.toString(), new RowMapper() {
            public Object mapRow(ResultSet rs, int i) throws SQLException {
                TimeZone tz = new TimeZone();
                tz.setOid(rs.getLong("OID"));
                tz.setJavaName(rs.getString("JAVA_NAME"));
                return tz;
            }
        });

        return timeZones;
    }
}

public class TimeZone {
    private Long oid;
    private String javaName;

    public Long getOid() {
        return this.oid;
    }

    public void setOid(Long oid) {
        this.oid = oid;
    }

    public String getJavaName() {
        return this.javaName;
    }

    public void setJavaName(String javaName) {
        this.javaName = javaName;
    }
}

spring-config.xml

<beans>

    <jee:jndi-lookup id="dataSource" jndi-name="java:/OracleDS"/>

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <bean id="timeZoneDao" class="dao.impl.TimeZoneDaoImpl">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <bean id="timeZoneService" class="logic.impl.TimeZoneServiceImpl">
        <property name="tzDao" ref="timeZoneDao"/>
    </bean>

</beans>

web.xml

<web-app>

    <display-name>Spring</display-name>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            WEB-INF/spring-config.xml,classpath*:/META-INF/spring-config.xml</param-value>
    </context-param>

    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>

    <servlet>
        <servlet-name>index</servlet-name>
        <display-name>Index page</display-name>
        <description>Landing page</description>
        <servlet-class>servlet.Index</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>index</servlet-name>
        <url-pattern>/index</url-pattern>
    </servlet-mapping>

    <!-- Session Timeout (in minutes) -->
    <session-config>
        <session-timeout>60</session-timeout>
    </session-config>
</web-app>

mysql-ds.xml

<datasources> 
   <local-tx-datasource> 
      <jndi-name>OracleDS</jndi-name> 
      <connection-url>jdbc:mysql://localhost:3306/spring</connection-url> 
      <driver-class>com.mysql.jdbc.Driver</driver-class> 
      <user-name>spring_test</user-name> 
      <password>spring_test13</password> 
      <min-pool-size>1</min-pool-size> 
      <max-pool-size>5</max-pool-size> 
      <idle-timeout-minutes>2</idle-timeout-minutes> 
   </local-tx-datasource> 
</datasources>

【问题讨论】:

  • mysql-ds.xml OracleDSjdbc:mysql://localhost:3306/ springcom.mysql.jdbc.Driverspring_testspring_test131 52

标签: java jboss datasource


【解决方案1】:

好的。希望以下内容对某人有用:-)

有一个数据源配置设置-exception-sorter-class-name

根据 Jboss,这是用于a class that looks at vendor specific messages to determine whether sql errors are fatal and thus the connection should be destroyed. If none specified, no errors will be treated as fatal.

如果使用 Oracle 数据库,则此配置设置为 org.jboss.resource.adapter.jdbc.vendor.OracleExceptionSorter。这个类包含所有需要被视为致命的错误代码,因此需要销毁连接。

在 Jboss 4 中,不包括错误代码 17002(连接重置)&& 17008(连接关闭)。它们是在 Jboss 5 中添加的。因此,如果您正在使用 Jboss 4 并且想知道为什么连接没有被恢复,请尝试添加缺少的代码。

【讨论】:

    【解决方案2】:

    这是 jboss 7.1+ 的 oracle DB 的连接验证配置:

    <validation>
       <valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.vendor.OracleValidConnectionChecker"/>
       <check-valid-connection-sql>select 1 from dual</check-valid-connection-sql>
       <stale-connection-checker class-name="org.jboss.jca.adapters.jdbc.vendor.OracleStaleConnectionChecker"/>
       <exception-sorter class-name="org.jboss.jca.adapters.jdbc.extensions.oracle.OracleExceptionSorter"/>
    </validation>
    

    现在 Jboss 将验证您的每个连接。

    【讨论】:

      【解决方案3】:

      这是使用连接池时的常见问题。当应用程序从池中借用连接时,池本身应该“测试”连接,以确保它仍然有效,还是应该将其留给应用程序?

      如果池测试连接,这不可避免地涉及将连接发送到数据库服务器(通常是某种基本的 SELECT)。在高流量系统上,这是非常浪费的,并且会给数据库服务器增加相当大的压力。

      但是,在低流量站点上,您的数据库可以处理额外的负载,您可以配置数据源以使 JBoss 在将连接传递给您的应用程序之前对其进行验证。如果连接已死,JBoss 会将其从池中移除并获取一个新连接,以便在数据库重新启动后仍然存在。

      任何,将其添加到您的 mysql-ds.xml 文件中:

      <check-valid-connection-sql>select 1 from mytable</check-valid-connection-sql>
      

      您必须自己选择查询,确保它不是一个昂贵的查询,因为它将运行一个很多

      查看JBoss documentation wiki 了解如何修改这些数据源文件。

      【讨论】:

      • 是的。还有一个配置可以看到 Jboss 在返回连接之前做了一些事情。 valid-connection-checker-class-name 应该比发出 SQL 更好。既然你提到应用程序应该能够处理这种情况,我想知道 Hibernate/Spring 框架是否为我们做这件事?由于关闭连接异常带有所有数据库的标准代码。
      • 不,Spring 和 Hibernate 都无法更好地处理这个问题。如果您要重新启动数据库服务器,请使用连接检查器,或者也重新启动您的应用服务器。哦,valid-connection-checker-class-name 也发布 SQL,它只是在幕后进行。没有区别。
      • @skaffman 除了 org.jboss.resource.adapter.jdbc.vendor.OracleValidConnectionChecker使用 tns ping,正如您在此处提到的 stackoverflow.com/a/145889/274414
      猜你喜欢
      • 2012-07-03
      • 1970-01-01
      • 1970-01-01
      • 2011-01-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-13
      • 1970-01-01
      相关资源
      最近更新 更多