Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > database+web


Автор: DEMOVERSION 21.3.2006, 19:02
Добрый день.
скажите пожалуйста есть у кого-то клас/пример лучше живой код организации работы между базой даных и веб сервером(Tomcat,JSP,Struts).

Мой клас не подходит, вылетает на ошибке Too many connections to server(web server!!!)....
Data source rejected establishment of connection, message from server: "Too many connections"

Код

package edu.university.database;

import org.apache.commons.pool.ObjectPool;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.apache.commons.dbcp.ConnectionFactory;
import org.apache.commons.dbcp.PoolingDataSource;
import org.apache.commons.dbcp.PoolableConnectionFactory;
import org.apache.commons.dbcp.DriverManagerConnectionFactory;

import javax.sql.DataSource;
import javax.naming.InitialContext;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.SQLException;
import java.sql.ResultSet;

public class DataBase {

    private static DataBase db = null;
    private static String CANNOT_FIND_DRIVER = "Cannot find driver.";
    private static String CANNOT_CREATE_STATEMENT = "Cannont create the statement.";
    private static final String DRIVER_NAME = "com.mysql.jdbc.Driver";
    private static final String CONNECTION_STRING = "jdbc:mysql://ifdevserver:3307/kafedra";
    private DataSource ds;

    public void DataBase() {
    }

    public void init() throws Exception{
                 System.out.println("Loading DB driver...");
                 try {
                     Class.forName(DRIVER_NAME);
                 }
                 catch (ClassNotFoundException ex) {
                     System.out.println(CANNOT_FIND_DRIVER);
                     ex.printStackTrace();
                 }
                 System.out.println("Loading DB driver...DONE");
                 System.out.println("Setuping DataSource...");
                 ds = setupDataSource(CONNECTION_STRING);
                 System.out.println("Setuping DataSource...DONE");
                 db = this;
        }

        public DataSource setupDataSource(String connectURI) {
               ObjectPool connectionPool = new GenericObjectPool(null);
               ConnectionFactory connectionFactory = new DriverManagerConnectionFactory(connectURI,"root","");
               PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(connectionFactory,connectionPool,null,null,false,true);
               PoolingDataSource dataSource = new PoolingDataSource(connectionPool);
               return dataSource;
        }

        public static DataBase getInstance(){
            if (db == null) {
                System.gc();
                DataBase db_reserv = new DataBase();
                try {
                db_reserv.init();
                } catch (Exception ex) {
                    System.out.println("Can't initialize database connection.:" + ex.getMessage());
                }
                return db_reserv;
            }
            return db;
        }
        public Connection getConnection() {
            Connection conn = null;
            try {
                conn = ds.getConnection();
            } catch (SQLException ex) {
                     System.out.println("Can't get connection(1):" + ex.getMessage());
                     ds = null;
                     db = null;
                     System.gc();
                     try {
                     init();
                     Thread.sleep(100);
                     conn = ds.getConnection();
                     } catch (Exception exx) {
                         System.out.println("Can't get connection(2):" + ex.getMessage());
                     }
            }
            return conn;
    }
}




Пример использования
Код

package edu.university.database.utils;

import edu.university.database.DataBase;
import edu.university.objects.TypeShadow;
import edu.university.objects.LineInSchedule;
import edu.university.utils.constants.Constants;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Collection;
import java.util.ArrayList;
import java.util.List;


public class ScheduleManager {
    Connection connection = null;
    private static ScheduleManager scheduleManager = null;

     public static ScheduleManager getInstance() {
        if(scheduleManager == null) {
             scheduleManager = new ScheduleManager();
        }
            return scheduleManager;
     }

    public ScheduleManager() {
        connection = DataBase.getInstance().getConnection();
    }
    public void close() {
         try {
             connection.close();
             connection = null;
         }
         catch (SQLException sex) {
             System.out.println("Closing connection,statements error.:" + sex.getMessage());
         }
        scheduleManager = null;
        System.gc();
    }

    public List getSchedule(int groupId,int dayId){
        List result = new ArrayList();
        ResultSet resSet = null;
        try {
            Statement statement = connection.createStatement();
            // POSSIBLE UA, EN
            resSet = statement.executeQuery("select * from schedule where groupId=" + groupId +" and dayid="+dayId+ " order by n");
            int i = 0;
            while (resSet.next()) {
                LineInSchedule line = new LineInSchedule();
                line.setDayId(resSet.getInt("dayid"));
                line.setGroupId(resSet.getInt("groupId"));
                line.setSubjectIdTop(resSet.getInt("subjectTopId"));
                line.setRoomIdTop(resSet.getInt("roomTopId"));
                line.setTypeIdTop(resSet.getInt("kindTopId"));
                line.setSubjectIdDown(resSet.getInt("subjectDownId"));
                line.setRoomIdDown(resSet.getInt("roomDownId"));
                line.setTypeIdDown(resSet.getInt("kindDownId"));
                line.setN(resSet.getInt("n"));
                result.add(line);
                i++;
                if (i>Constants.LESSONS_NUMBER) {
                    System.out.println("======>>>> SOME ERROR <<<<=============");
                    break;
                }
            }
            resSet.close();
        } catch (SQLException sex) {
            System.out.println("Error while getting schedule of all days.:" +sex.getMessage());
        }
        return result;
    }

    public boolean updateSchedule(List schedule)  {
        boolean result = true;
        // schedule(groupId,dayid,subjectTopId,roomTopId,kindTopId,subjectDownId,roomDownId,kindDownId)
        Statement statement = null;
        try {
            statement = connection.createStatement();
            for(int i=0;i<schedule.size();i++) {
                LineInSchedule line = (LineInSchedule)schedule.get(i);
                String SQL = "UPDATE schedule SET " +
                     "subjectTopId="+line.getSubjectIdTop() + "," +
                     "roomTopId=" + line.getRoomIdTop() + "," +
                     "kindTopId=" + line.getTypeIdTop() + "," +
                     "subjectDownId="+line.getSubjectIdDown() + "," +
                     "roomDownId=" + line.getRoomIdDown() + "," +
                     "kindDownId=" + line.getTypeIdDown() + " WHERE n=" + line.getN();
                //ystem.out.println(SQL);
                result = result&(statement.executeUpdate(SQL)>0);
            }
            statement.close();
            statement = null;
        } catch (SQLException e) {
            result = false;
            System.out.println("Error updating schedule.");
            e.printStackTrace();
        }
        finally {
            if (statement!=null) {
                try {
                    statement.close();
                } catch (SQLException e) {
                    System.out.println("Error while closing statement");
                    e.printStackTrace();
                }
            }
        }
        return result;
    }
}


Автор: LSD 21.3.2006, 21:30
Уменьши у пула максимальное количество соединений, или наоборот у сервера увеличь его.

Автор: DEMOVERSION 22.3.2006, 12:50
а пример кода использования нормальный?
поможет System.gc(), может это очистит в все что неиспользуеться и просто висит?

Автор: LSD 22.3.2006, 13:19
Да вообщем, тоже нет. Смотри ты соединение из пула берешь (ScheduleManager:29), но не возвращаешь. А просто закрываешь его. Это не правильно.
Алгоритм работы такой: ты создаешь пул соединений, в этом пуле открываешь соединения (можешь вначале вообще ничего не открывать, а делать это по мере необходимости), когда приложению нужно соединение, оно обращается в пул за ним, работает с ним, закрывает все курсоры и statements, но не само соединение, а затем возвращает соединение в пул, пул при завершении работы сам закрывает все соединения.

Автор: tux 22.3.2006, 13:59
Цитата(LSD @ 22.3.2006, 18:19 Найти цитируемый пост)

Алгоритм работы такой: ты создаешь пул соединений, в этом пуле открываешь соединения (можешь вначале вообще ничего не открывать, а делать это по мере необходимости), когда приложению нужно соединение, оно обращается в пул за ним, работает с ним, закрывает все курсоры и statements, но не само соединение, а затем возвращает соединение в пул, пул при завершении работы сам закрывает все соединения.

В данном случае по-моему не так. Дело в том, что соединение берется у commons-dbcp. Эта самая DBCP возвращает не оригинальное соединение от драйвера, а обертку, которая при вызове connection.close() возвратит соединение в пул. Так что в коде, имхо, все правильно.

А параметры пула можно выставить, например, так:
Код

connectionPool.setMaxActive(2);
connectionPool.setMaxIdle(2);

Здесь setMaxActive() устанавливает максимальное количество активных соединений (выполняющих какие-то запросы), setMaxIdle() - максимальное количество открытых неактивных соединений. В javadoc к классу org.apache.commons.pool.impl.GenericObjectPool описания других параметров пула - http://jakarta.apache.org/commons/pool/apidocs/org/apache/commons/pool/impl/GenericObjectPool.html.

Автор: DEMOVERSION 22.3.2006, 17:48
Спасибо. Буду пробовать. Мне что-то не нравиться что ScheduleManager имеет static методы и поле. Нормально так оставить?

Автор: LSD 22.3.2006, 17:55
Цитата(DEMOVERSION @ 22.3.2006, 17:48 Найти цитируемый пост)
Мне что-то не нравиться что ScheduleManager имеет static методы и поле. Нормально так оставить?

Вообщем, это типичный синглетон. Подходит ли он по задаче или нет, тебе видней.
Тебе надо чтобы все операции с Schedule проходили через одиное место? Если да, то синглетон хорошо для этого подходит.

Автор: DEMOVERSION 23.3.2006, 14:27
Я использую это в Struts Action's. Мне надо доставать расписание для груп. Тут подходит?

Автор: ALKS 23.3.2006, 14:56
Смотрю на это и тупо не понимаю.

1. Зачем городить свой конекшн пул? Ваш AppServer что не подерживает коннекшн пулы? Tomcat точно держит. http://www.javenue.info/post/10

2. Ну ладно а ваш JDBC драйвер тоже не имеет "родную" имплементацию?

3. Ну хорошо Бог с ним. а зачем сингл тон? статичным его сделайте и все дела...

зачем себе жизнь усложнять?

Автор: LSD 23.3.2006, 15:02
Честно говоря трудно оценить как ты его используешь. Если у тебя идет интенсивная работа, но время от времени, то лучше создать по экземпляру. Если обращения время от времени, то подойдет и синглетон.
Единственноее но, объект занимает одно соединение к базе (если вызовы происходят редко то лучше запрашивать соединение по мере необходимости). И плюс если будет несколько одновременных вызовов к методам, то будет конфликт из-за того, что они работают через одно соединение. Надо это как-то решить, или синхронизацией или запросом каждый раз нового соединения (второе предпочтительней).

Автор: tux 23.3.2006, 15:09
Цитата(ALKS @ 23.3.2006, 19:56 Найти цитируемый пост)
1. Зачем городить свой конекшн пул? Ваш AppServer что не подерживает коннекшн пулы? Tomcat точно держит. http://www.javenue.info/post/10

А, например, в Jetty это опциональная фича. А если я не хочу никаких опций, а хочу веб-контейнер в минимальной конфигурации. Не важно по какой причине. Кроме того, пулы соединений, как правило, поддерживают больше параметров пула чем серверы приложений. Хотя в общем случае я бы тоже предпочел пул от сервера приложений, но ведь не все случаи - общие.
Цитата(ALKS @ 23.3.2006, 19:56 Найти цитируемый пост)
2. Ну ладно а ваш JDBC драйвер тоже не имеет "родную" имплементацию?

Его к этому никто не обязывает. Например, у jdbc-драйвера PostgreSQL пул есть, но соединений он никогда не закрывает, то есть если у него стоит максимум 10 соединений, то он их создаст и будут они висеть пока приложение не закроется. Согласись, это не есть хорошо.
Цитата(ALKS @ 23.3.2006, 19:56 Найти цитируемый пост)
3. Ну хорошо Бог с ним. а зачем сингл тон? статичным его сделайте и все дела...

С обычным экземпляром все-таки попроще чем со статическими методами, а принципиальной разницы в общем-то нет.

Автор: LSD 23.3.2006, 15:28
Цитата(ALKS @ 23.3.2006, 14:56 Найти цитируемый пост)
3. Ну хорошо Бог с ним. а зачем сингл тон? статичным его сделайте и все дела...

Проблема в чем преимущества синглетона перед статическими методами, уже http://forum.vingrad.ru/index.php?showtopic=66616.

Автор: ALKS 23.3.2006, 15:52
LSD угу псомтрел диспут. да да. читал такие же обсуждения в разных местах на разных языках и в раное время. безспорно есть случаи когда без синглотонов не обойтись. есть случае когда они дают определнные выигрыш. но я ИМХО предпочитаю там где не нужно не использовать вот и всё.

tux, ну я слабо представляю себе динамическое вэб приложение без базы данных за спиной. все танцы с бубном вокруг коннекшн пула напоминают мне изобретательство велосипеда. Было время когда DataSource не был частью J2EE и тогда все крутились как могли. Но сейчас смасла в этом ноль. Зачем ставить AppServer и не пользоваться предоставляемыми им сервесами?

"Кроме того, пулы соединений, как правило, поддерживают больше параметров пула чем серверы приложений" это я, честно,совсем не понял. серверы приложений предоставляет вам импелменатцию J2EE DataSource. пользуйтесь. возможности этой имплементации даже у таких средненьких серверов как скажем JRun выше крыши. О каких таких загадочных пармерах реч?

Если JDBC драйвер заявляет что он соотвествует спецификации JDBC 3.0 (могу ошибаться в версии стандарта уж простите) то пул там быть должен. Другое дело что он может быть конечно корявым. да. в этом случае я бы скорее попытался найти альтенативный драйвер нежели чем писать пул самостоятельно....

Ребят поймите меня правильно... я когда-то вынужден был писать коннекшн пулл это та еще задача если делать серьезно там масса нюансов например обслуживание таймаутов и т.п. оно вам не надо, уверяю вас smile

Автор: tux 23.3.2006, 17:35
Цитата(ALKS @ 23.3.2006, 20:52 Найти цитируемый пост)
tux, ну я слабо представляю себе динамическое вэб приложение без базы данных за спиной. все танцы с бубном вокруг коннекшн пула напоминают мне изобретательство велосипеда. Было время когда DataSource не был частью J2EE и тогда все крутились как могли. Но сейчас смасла в этом ноль. Зачем ставить AppServer и не пользоваться предоставляемыми им сервесами?

Ну хотя бы затем, что сервер приложений при этом нужно настраивать, причем каждый сервер, на который нужно разворачивать приложение, приходится настраивать по-своему. И, опять-таки, повторюсь, не все веб-контейнеры предоставляют пулы соединений. Кстати, у Tomcat нет своей реализации пула соединений и по дефолту он использует все тот же commons-dbcp, который DEMOVERSION использует явно. Можно прикрутить и другие. И в где там танцы с бубном не пойму. Пять строчек кода и готов пул соединений, который к тому же не зависит от сервера приложений.

Что касается параметров пула соединений. У многих серверов все параметры ограничиваются максимальным и минимальным количеством соединений. У C3P0 таких параметров порядка 30. Не станешь же ты утверждать что 28 из них никогда не нужны.

Цитата(ALKS @ 23.3.2006, 20:52 Найти цитируемый пост)
Другое дело что он может быть конечно корявым. да. в этом случае я бы скорее попытался найти альтенативный драйвер нежели чем писать пул самостоятельно....

А я бы использовал какую-нибудь библиотеку пула соединений. Постоянно работаю с PostgreSQL и родной jdbc-драйвер - единственный бесплатный.

Цитата(ALKS @ 23.3.2006, 20:52 Найти цитируемый пост)
Ребят поймите меня правильно... я когда-то вынужден был писать коннекшн пулл это та еще задача если делать серьезно там масса нюансов например обслуживание таймаутов и т.п. оно вам не надо, уверяю вас smile

Я тоже писал простенький только для кжширования соединений. Зачем писать свой навороченный если готовых решений пруд пруди.

Автор: ALKS 23.3.2006, 18:35
"Ну хотя бы затем, что сервер приложений при этом нужно настраивать, причем каждый сервер, на который нужно разворачивать приложение, приходится настраивать по-своему."

tux, я искренне не понимаю. Cознательно не пользоваться иплементациями конкретного сервера преложений, чтобы их не настраивать и от них не зависеть? А зачем тогда сервер приложений вообще?
По-моему это порочный подход изначально...

Автор: tux 23.3.2006, 18:53
Код

tux, я искренне не понимаю. Cознательно не пользоваться иплементациями конкретного сервера преложений, чтобы их не настраивать и от них не зависеть?

Как это не пользовался? В Томкате ведь источник данных настраивал в server.xml примерно таким образом:
Код

<Resource name="jdbc/myoracle" auth="Container"
              type="javax.sql.DataSource"/> 

<ResourceParams name="jdbc/myoracle">
  <parameter>
    <name>factory</name>
    <value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
  </parameter>
  <parameter>
    <name>driverClassName</name>
    <value>oracle.jdbc.driver.OracleDriver</value>
  </parameter>
  <parameter>
    <name>url</name>
    <value>jdbc:oracle:thin:[email protected]:1521:mysid</value>
  </parameter>
  <parameter>
    <name>username</name>
    <value>scott</value>
  </parameter>
  <parameter>
    <name>password</name>
    <value>tiger</value>
  </parameter>
  <parameter>
    <name>maxActive</name>
    <value>20</value>
  </parameter>
  <parameter>
    <name>maxIdle</name>
    <value>10</value>
  </parameter>
  <parameter>
    <name>maxWait</name>
    <value>-1</value>
  </parameter>
</ResourceParams>

А в сервере приложений Orion источник данных настраивается вот так в файле data-sources.xml:
Код

<data-source
    class="com.evermind.sql.DriverManagerDataSource"
    name="PostgreSQL"
    location="jdbc/EntrantDS"
    xa-location="jdbc/xa/PostgresXADS"
    ejb-location="jdbc/PostgresDS"
    connection-driver="org.postgresql.Driver"
    username="postgres"
    password=""
    url="jdbc:postgresql://localhost/entrant"
    inactivity-timeout="30"
/>

В Томкате чтобы получить источник данных, нужно еще в web.xml веб-приложения описывать ссылку на ресурс (особенности сервиса JNDI таковы), в Orion можно обращаться по прямому имени в дереве JNDI. Как видишь между серверами значительная разница и убежать от этих различий не удастся. Согласен, если разрабатываешь для конкретного сервера приложений это совершенно не проблема, но если заранее не известно куда придется деплоить приложение, то придется предусматривать кой-какие особенности серверов.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)