Показаны сообщения с ярлыком jdbc. Показать все сообщения
Показаны сообщения с ярлыком jdbc. Показать все сообщения

суббота, 19 сентября 2020 г.

Решение проблемы с зависанием веб-приложения

Пример анализа и, надеюсь, решения проблемы с зависаниями веб-приложения.

Началось все с нерегулярных обращений от пользователей о зависании веб-приложения, которое выражалось в том, что после ввода имени пользователя и пароля веб-страница зависала, а именно, переходила в режим "вечного ожидания ответа от веб-сервера".

Единственной полезной зацепкой была ошибка в "catalina.out" (лог-файл веб-сервера Apache Tomcat 9, при чем не сразу стало понятно, что указанная ниже информация записывается туда, при штатных настройках Apache Tomcat, только после остановки веб-сервера или после остановки проблемного веб-приложения, например, в "Tomcat Manager Application"):
19-Sep-2020 08:26:57.691 WARNING [http-nio-8080-exec-914] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [jenki##2.1.28] is still processing a request that has yet to finish. This is very likely to create a memory leak. You can control the time allowed for requests to finish by using the unloadDelay attribute of the standard Context implementation. Stack trace of request processing thread:[
sun.misc.Unsafe.park(Native Method)
java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
org.apache.tomcat.dbcp.pool2.impl.LinkedBlockingDeque.takeFirst(LinkedBlockingDeque.java:586)
org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:438)
org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:359)
org.apache.tomcat.dbcp.dbcp2.PoolingDataSource.getConnection(PoolingDataSource.java:134)
org.apache.tomcat.dbcp.dbcp2.BasicDataSource.getConnection(BasicDataSource.java:1543)
com.jenki.multicon.AppContextReader.<init>(AppContextReader.java:14)
com.jenki.LoginServlet.doPost(LoginServlet.java:46)
...
Последние две строки дали мне, как автору веб-приложения, понять, что проблема возникла, когда пользователь ввел пароль и началось ожидание подключения к БД для загрузки данных, которые пользователь ожидает на экране своего интернет-браузера. Таким образом, это дало уверенность в том, что на найденную ошибку можно спокойно опереться при дальнейшем анализе.

Поиск по остальным строкам стека ошибки привел к подобного рода обсуждениям: https://github.com/dotCMS/core/issues/7790 - тут описываются нюансы настройки подключений к БД через "context.xml" Томката (как раз, мой случай) с использованием параметров:
maxActive="60" maxIdle="10" maxWait="60000" removeAbandoned="true" removeAbandonedTimeout="60" logAbandoned="true" validationQuery="SELECT 1" testOnBorrow="true"
После попытки применения указанных на странице по ссылке параметров "maxActive", "maxWait" Томкат при запуске в своей консоли сообщает о том, что эти параметры для "фабрики пула соединений" устарели и вместо них нужно использовать актуальные, соответственно, "maxTotal" (по умолчанию "8" - Привет, зависания после 8 обновлений веб-страницы!), "maxWaitMillis" (по умолчанию "-1"). Там же Томкат сообщает наименование текущей фабрики подключений - "org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory" - оказывается, эта фабрика запускается Томкатом 9 автоматически, если администратор в context.xml в блоке настроек для подключения к БД не указывает другую фабрику с помощью тэга "factory" (описано в https://tomcat.apache.org/tomcat-9.0-doc/config/context.html#Resource_Definitions).

Поиск дополнительной информации на тему зависаний веб-приложения после 8 подключений к БД приводит к совету https://stackoverflow.com/questions/30879706/why-does-my-tomcat-only-open-8-jdbc-connections об использовании «factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"».

В итоге, блок настройки подключений к БД веб-приложения выглядит следующим образом:
    <Resource name="jdbc/jenki"
        auth="Container"
        driverClassName="oracle.jdbc.driver.OracleDriver"
        url="jdbc:oracle:thin:@myserver:1521:db"
        username="mySYSDBA"
        password="mypassw"
        type="javax.sql.DataSource"
        factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
        maxActive="100" maxIdle="30" maxWait="10000"
        removeAbandoned="true" removeAbandonedTimeout="40" logAbandoned="true" testOnBorrow="true" />

Теперь в логе Томката (catalina.out) видны лишь строки, символизирующие закрытие подключений (позднее будет проведена проверка кода приложения - возможно, подключения не всегда корректно закрываются, но пока с этим справляется "Tomcat JDBC Pool Cleaner"):
23-Sep-2020 12:27:26.355 WARNING [Tomcat JDBC Pool Cleaner[2129789493:1600853171352]] org.apache.tomcat.jdbc.pool.ConnectionPool.abandon Connection has been abandoned PooledConnection[oracle.jdbc.driver.T4CConnection@3af0c98d]:java.lang.Exception
...
23-Sep-2020 12:52:51.415 WARNING [Tomcat JDBC Pool Cleaner[2129789493:1600853171352]] org.apache.tomcat.jdbc.pool.ConnectionPool.abandon Connection has been abandoned PooledConnection[oracle.jdbc.driver.T4CConnection@6ea26def]:java.lang.Exception
...
23-Sep-2020 14:02:51.570 WARNING [Tomcat JDBC Pool Cleaner[2129789493:1600853171352]] org.apache.tomcat.jdbc.pool.ConnectionPool.abandon Connection has been abandoned PooledConnection[oracle.jdbc.driver.T4CConnection@41e58b1f]:java.lang.Exception
...
23-Sep-2020 14:04:26.574 WARNING [Tomcat JDBC Pool Cleaner[2129789493:1600853171352]] org.apache.tomcat.jdbc.pool.ConnectionPool.abandon Connection has been abandoned PooledConnection[oracle.jdbc.driver.T4CConnection@338e76fa]:java.lang.Exception
...
23-Sep-2020 14:52:16.686 WARNING [Tomcat JDBC Pool Cleaner[2129789493:1600853171352]] org.apache.tomcat.jdbc.pool.ConnectionPool.abandon Connection has been abandoned PooledConnection[oracle.jdbc.driver.T4CConnection@2165cd9c]:java.lang.Exception
===========================
Порядок действий для стабильного повторения:
1. Открываем несколько разных сессий к веб-приложению (можно даже под одним и тем же пользователем, главное, чтобы это были разные сессии), для этого нужно, к примеру, если тестируется на одном компьютере, то можно открыть 6 окон в 3-х разных браузерах (к примеру, Яндекс.Браузер, Firefox, Chrome): 3 окна в штатном режиме и 3 окна в приватном;
2. Несколько раз (около 6 в каждом окне по очереди) обновляем страницу;
3. Ждем около 20-30 минут (окна браузеров не закрываем);
4. Повторяем пункт 2.

Ожидаемый результат (до исправления):
обновление страницы будет выполнено штатно, пользователь увидит данные на обновленной странице.

Фактический результат (до исправления):
Примерно 4 из 6 окон перейдут в режим ожидания ответа от веб-сервера.

Результат тестирования после примененного исправления ...

четверг, 14 мая 2020 г.

Доступ к СУБД Firebird 3.0 через JSP под Tomcat

Пример доступа к БД Firebird 3.5 через JSP под Tomcat.

Чтобы научить Apache Tomcat 9 под Java 1.8 подключаться к базам Firebird 3.0, копируем из архива jaybird-4.0.0.java8.zip файлы jaybird-full-4.0.0.java8.jar, lib\antlr-runtime-4.7.2.jar, lib\connector-api-1.5.jar, lib\jna-5.5.0.jar в папку <tomcat>\lib.
Создаем web-приложение: JSP-страница, которая будет выводить содержимое таблицы "USER" из БД "c:/data/base.fdb" сервера "dbserver"
<tomcat>\webapps\test_app\index.jsp

Листинг index.jsp:
<%@page import="java.sql.*" %>
<%Class.forName("org.firebirdsql.jdbc.FBDriver"); %>
<HTML>
    <HEAD>
        <TITLE>Database access through JSP</TITLE>
    </HEAD>
    <BODY>
        <H1>Result of select query</H1>
        <%
            Connection connection = DriverManager.getConnection(
                "jdbc:firebirdsql:dbserver/3255:c:/data/base.fdb",
                "SYSDBA",
                "masterkey");
            Statement statement = connection.createStatement();
            ResultSet resultset = statement.executeQuery("select id, name from user order by id asc");
        %>
        <TABLE BORDER="1">
            <TR>
                <TH>id</TH>
                <TH>name</TH>
            </TR>
            <% while(resultset.next()){ %>
            <TR>
                <TD> <%= resultset.getString(1) %></TD>
                <TD> <%= resultset.getString(2) %></TD>
            </TR>
            <% } %>
        </TABLE>
    </BODY>
</HTML>

воскресенье, 4 марта 2018 г.

Firebird JDBC Encoding

При подключении к базе Firebird с помощью JDBC (jaybird-full-3.0.3.jar) появляется сообщение:
Фев 04, 2018 5:18:52 PM org.firebirdsql.logging.JulLogger warn
WARNING: WARNING: No connection character set specified (property lc_ctype, encoding, charSet or localEncoding), defaulting to character set NONE

Чтобы этого не происходило нужно:
- либо в строке подключения необходимо указывать кодировку "encoding=ISO/UTF/WIN...", например:
jdbc:firebirdsql:url:db?encoding=ISO8859_1
- либо:
Properties connInfo = new Properties();
connInfo.put("user", username);
connInfo.put("password", password);
connInfo.put("charSet", "Cp1251");
Connection db = DriverManager.getConnection(dataurl, connInfo);

вторник, 27 февраля 2018 г.

Java + SQL = JDBC

Select1.java:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class Select1 {

    private static final String url = "jdbc:oracle:thin:@172.21.10.56:1521:ora";
    private static final String user = "AZ_USER";
    private static final String password = "AZ_PSWD";

    private static Connection con;
    private static Statement stmt;
    private static ResultSet rs;

    public static void main(String args[]) {
        String query = "select count(*) from sysuser";
        try {
            con = DriverManager.getConnection(url, user, password);
            stmt = con.createStatement();
            rs = stmt.executeQuery(query);

            while (rs.next()) {
                int count = rs.getInt(1);
                System.out.println("Total number of users: " + count + ".");
            }

        } catch (SQLException sqlEx) {
            sqlEx.printStackTrace();
        } finally {
            try { con.close(); } catch(SQLException se) { /*can't do anything */ }
            try { stmt.close(); } catch(SQLException se) { /*can't do anything */ }
            try { rs.close(); } catch(SQLException se) { /*can't do anything */ }
        }
    }
}

Компиляция:
javac Select1.java
Если поместить "ojdbc6.jar" в папку .\lib\ тогда команда запуска будет выглядеть так:
java -cp .;.\lib\ojdbc6.jar Select1
или так:
java -cp .;.\lib\* Select1

четверг, 3 марта 2016 г.

Доступ к СУБД Oracle через JSP под Tomcat

Пример доступа к БД Oracle через JSP под Tomcat.

Чтобы научить tomcat подключаться к базам Oracle, копируем ojdbc6.jar в папку <tomcat>\lib.
Создаем web-приложение: JSP-страница, которая будет выводить содержимое таблицы "USER" из БД "c:/data/base.fdb" сервера "dbserver"
<tomcat>\webapps\test_app\index.jsp

Листинг index.jsp:
<%@page import="java.sql.*" %>
<%Class.forName("oracle.jdbc.driver.OracleDriver"); %>
<HTML>
    <HEAD>
        <TITLE>Database access through JSP</TITLE>
    </HEAD>
    <BODY>
        <H1>Result of select query</H1>
        <%
            Connection connection = DriverManager.getConnection(
                "jdbc:oracle:thin:@dbserver:1521:ORACLESID",
                "MY_ORA_SCHEMA",
                "password");
            Statement statement = connection.createStatement();
            ResultSet resultset = statement.executeQuery("select id, name from user order by id asc");
        %>
        <TABLE BORDER="1">
            <TR>
                <TH>id</TH>
                <TH>name</TH>
            </TR>
            <% while(resultset.next()){ %>
            <TR>
                <TD> <%= resultset.getString(1) %></TD>
                <TD> <%= resultset.getString(2) %></TD>
            </TR>
            <% } %>
        </TABLE>
    </BODY>
</HTML>

Полезные ссылки:
http://www.java2s.com/Tutorial/Java/0360__JSP/MakeDatabaseconnection.htm
http://jaybirdwiki.firebirdsql.org/jaybird/doku.php?id=config:driver_config

Проработать:
http://www.tutorialspoint.com/jsp/jsp_database_access.htm

Доступ к СУБД Firebird через JSP под Tomcat

Пример доступа к БД Firebird через JSP под Tomcat.

Чтобы научить tomcat подключаться к базам Firebird, копируем jaybird-full-2.2.9.jar в папку <tomcat>\lib.
Создаем web-приложение: JSP-страница, которая будет выводить содержимое таблицы "USER" из БД "c:/data/base.fdb" сервера "dbserver"
<tomcat>\webapps\test_app\index.jsp

Листинг index.jsp:
<%@page import="java.sql.*" %>
<%Class.forName("org.firebirdsql.jdbc.FBDriver"); %>
<HTML>
    <HEAD>
        <TITLE>Database access through JSP</TITLE>
    </HEAD>
    <BODY>
        <H1>Result of select query</H1>
        <%
            Connection connection = DriverManager.getConnection(
                "jdbc:firebirdsql:dbserver/3255:c:/data/base.fdb",
                "SYSDBA",
                "masterkey");
            Statement statement = connection.createStatement();
            ResultSet resultset = statement.executeQuery("select id, name from user order by id asc");
        %>
        <TABLE BORDER="1">
            <TR>
                <TH>id</TH>
                <TH>name</TH>
            </TR>
            <% while(resultset.next()){ %>
            <TR>
                <TD> <%= resultset.getString(1) %></TD>
                <TD> <%= resultset.getString(2) %></TD>
            </TR>
            <% } %>
        </TABLE>
    </BODY>
</HTML>

Полезные ссылки:
http://www.java2s.com/Tutorial/Java/0360__JSP/MakeDatabaseconnection.htm
http://jaybirdwiki.firebirdsql.org/jaybird/doku.php?id=config:driver_config

Проработать:
http://www.tutorialspoint.com/jsp/jsp_database_access.htm

Архив