Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java EE (J2EE) и Spring > объектная работа с Mysql в Servlet


Автор: initmax 27.10.2009, 17:56
Доброго, столкнулся с проблемой создания проинициализированного объекта внутри Servlet.

В Servlet осуществляю:
0) подключение к БД mySQL;
1) выполнение запроса по БД
3) формирование массива объектов с данными из БД

вот исходники

0) Класс подключения к БД
Код

/*
 * Class CreateBaseConnection provide connect to base MySQL
 * 
 */
package MySQL;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;


/**
 *
 * @author initmax
 */
public class MySQLConnect {

private String url = null;
private String name = null;
private String password = null;


//По умолчанию
    public MySQLConnect()
    {
      url = "jdbc:mysql://localhost:3030/initmax"+"?autoReconnect=true&useUnicode=true&characterEncoding=utf8"+
              "&SET NAMES utf8";
      name = "root";
      password = "pass";
    }


//Инициализирует поля значениями
    public MySQLConnect(String a_url, String a_name, String a_password){
        url = a_url;
        name = a_name;
        password = a_password;
    }


//***********************************************************************
private Connection CurrentConnect;


//***********************************************************************
//first need download driver, for work MySQL connect
    public void DownloadDriver()
    {
        try
        {
            Class.forName("com.mysql.jdbc.Driver");
//            System.out.println("Driver loading success!");
        }

        catch (ClassNotFoundException e)
        {
            e.printStackTrace();
        }
    }

//***********************************************************************
//Connected to MySQL Base use download driver
     public void Connected()
     {     
           
            try
            {
                CurrentConnect = DriverManager.getConnection(url, name, password);
//                System.out.println("Connected.");
            }

            catch (SQLException e)
            {
                    e.printStackTrace();
            }
     }      
    
//*********************************************************************
//disconnected base after finish work, get object connect
     public int DisConnected()
     {
         try
         {
          CurrentConnect.close();
          System.out.println("Disconnected.");
         }

         catch (SQLException e)
         {
                e.printStackTrace();
         }

         return 0;
      }

//*********************************************************************
//get current connection
      public Connection GetConnection()
      {
          return this.CurrentConnect;
      }
}


1) Класс отвечающий за запросы по БД

Код

package MySQL;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

import java.util.*;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

/**
 *
 * @author initmax
 */
public class MySQLQuery {

    private Connection CurrentConnect; //Объект типа подключение для работы с БД
    private Vector VectorPageObj = new Vector(); //создать объект типа вектор "динамическое" создание массива


public MySQLQuery() {}

//Конструктор принимает текущее установленное соединение с БД
public MySQLQuery(Connection CurrentConnectBase)
{
    CurrentConnect = CurrentConnectBase;
}

//*****************************************************************
//Метод принимает имя таблицы и возвращает полную по ней выборку
public Vector SelectAllField(String NameTable)
{
       try
       {
//Выполним запрос в БД по имени таблицы, переданой методу
         Statement st = CurrentConnect.createStatement();
         String query = ("select * from "+NameTable);
         ResultSet resultQuery = st.executeQuery(query);

//Пройдём в цикле по результату выполненого массива
//Создадим массив "Vector" объектов с данными страницы
         while (resultQuery.next())
         {
            GenPageMySQL PageObj = new GenPageMySQL();

            PageObj.setId(resultQuery.getInt("id"));
            PageObj.setTheme(resultQuery.getString("theme"));
            PageObj.setPage(resultQuery.getString("page"));
            
            VectorPageObj.add(PageObj); //добавим в конец массива заполненый объект
         }

       }
       catch (SQLException e) {
         e.printStackTrace();
      }

       return VectorPageObj;
}



    /**
    *@set the CurrentConnect
    */
    public void setConnection(Connection CurrentConnectBase) {
         CurrentConnect = CurrentConnectBase;
    }
 
}


2) Класс который инкапсулирет информацию выбраную из БД

package MySQL;

Код

/*
 * Класс объект содержащий все данные о странице выбраной из БД
 */


//import java.sql.Connection;
//import java.io.*;

/**
 *
 * @author initmax
 */
public class GenPageMySQL {

    private int id=0;
    private String theme=null;
    private String page=null;
    private String column=null;


    public GenPageMySQL(){

    }


    public GenPageMySQL(int a_id, String a_theme, String a_page){
        id = a_id;
        theme = a_theme;
        page = a_page;
    }


    /**
     * @return the id
     */
    public int getId() {
        return id;
    }

    /**
     * @param id the id to set
     */
    public void setId(int id) {
        this.id = id;
    }

    /**
     * @return the theme
     */
    public String getTheme() {
        return theme;
    }

    /**
     * @param theme the theme to set
     */
    public void setTheme(String theme) {
        this.theme = theme;
    }

    /**
     * @return the page
     */
    public String getPage() {
        return page;
    }

    /**
     * @param page the page to set
     */
    public void setPage(String page) {
        this.page = page;
    }

    /**
     * @return the column
     */
    public String getColumn() {
        return column;
    }

    /**
     * @param column the column to set
     */
    public void setColumn(String column) {
        this.column = column;
    }
  
}


3) И наконец сам Servlet который испоьзует вышеперечисленные классы

Код

import java.util.*;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import MySQL.*;

public class indexServlet extends HttpServlet {

    private String getpage;
 
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException, NullPointerException
            {
//получить параметр GET "выбор пользователя"
          getpage = request.getParameter("page");

//Подключиться к БД
          MySQLConnect MySQLConnectObj = new MySQLConnect();
          MySQLConnectObj.DownloadDriver();
          MySQLConnectObj.Connected();
//Принять текущее соединение для выполнения запросов по БД
//Из объекта MySQLConnectObj передаю текущее соединению объекту MySQLQueryObj
          MySQLQuery MySQLQueryObj = new MySQLQuery(MySQLConnectObj.GetConnection());
        

      Vector VectorPage = new Vector();
      VectorPage = MySQLQueryObj.SelectAllField("up_menu");

       MySQLConnectObj.DisConnected();
            
          return;
     }

  
}



Валится на этих вот строках 
      
Код

Vector VectorPage = new Vector();
      VectorPage = MySQLQueryObj.SelectAllField("up_menu");

       MySQLConnectObj.DisConnected();


ошибка такова:
Код

java.lang.NullPointerException
    MySQL.MySQLQuery.SelectAllField(MySQLQuery.java:39)
    indexServlet.doGet(indexServlet.java:34)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:717)

Что характерно, данные классы работают как обычный Java проект, если же данные классы вызывать из Servlet, получаю ошибку.


Автор: ivanovpv 28.10.2009, 09:12
Сразу видно PHP'ешника по полету smile

1) Если ближе к теме, то инициализацию драйвера JDBC надо выносить в метод init() сервлета, не дело при каждом запросе создавать новый коннект к БД, который как известно ресурс исчерпаемый и драгоценный. При запросе надо только проверять живо ли соединение или нет.
2) Далее после запроса положено закрывать ResultSet, а перед скроллированием записей в ResultSet неплохо бы убедиться, что он не пуст. ResultSet.next() при пустом запросе запросто может сгенерировать Exception.
3) Зачем вы создаете перед запросом Vector? Он же все равно создается внутри класса MySQLQuery?
4) Далее согласно стандартному стилю именований методов в Java если имя метода начинается с глагола, то его надо писать маленькими буквами. Например не SelectAllFields(), а selectAllFields()

Ну это все относится к стилю, а не к сути. По сути вы устанавливаете соединение с БД, но не проверяете живо оно или нет, просто выдаете printStackTrace() и идете дальше. Ну вот поэтому и получаете NullPointerException. А соединение с БД вы (как уже говорил выше) устанавливаете при каждом запросе и через несколько запросов ресурсы коннектов БД заканчиваются.

Автор: initmax 28.10.2009, 10:38
Цитата

Сразу видно PHP'ешника по полету 

Да Вы правы, вот переучиваюсь smile поразительно что так быстро раскусили, наверное сами на PHP когда-то кодили ;)

Цитата

1) Если ближе к теме, то инициализацию драйвера JDBC надо выносить в метод init() сервлета, не дело при каждом запросе создавать новый коннект к БД, который как известно ресурс исчерпаемый и драгоценный. При запросе надо только проверять живо ли соединение или нет.

Благодарю за критику smile
метод init() в сервлете это тот который вызывается автоматически?
сервлет должен выглдять так?
Код


import java.util.*;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import MySQL.*;

public class indexServlet extends HttpServlet {

    private String getpage;
    //Подключиться к БД
    private  MySQLConnect MySQLConnectObj = new MySQLConnect();
    private MySQLQuery MySQLQueryObj = new MySQLQuery();


    public void init(){
          MySQLConnectObj.DownloadDriver(); //загрука драйвера
          MySQLConnectObj.Connected(); //подключение к MySQL
          //Передача утсновленного соединения с БД объекту "запросы"
          MySQLQueryObj.setConnection(MySQLConnectObj.GetConnection()); 
    }

 
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException, NullPointerException
            {
//получить параметр GET "выбор пользователя"
      getpage = request.getParameter("page");

//Проверка установки текущего соединения с БД
      if(MySQLConnectObj.GetConnection() != null){
           Vector VectorPage = new Vector(); //для массива объектов из БД
           VectorPage = MySQLQueryObj.SelectAllField("up_menu");//выборка по БД
      }

//При отсуствии соединения установить его
      else if(MySQLConnectObj.GetConnection() == null){
             init() ;
      }

     
//когда отключаться от БД? после каждой обработки запроса пользователем
//или после разрушения сессии?
//          MySQLConnectObj.DisConnected();
        
          
/*
//Разобрать вектор
          GenPageMySQL PageObj = new GenPageMySQL();
          for(int i=0; i<VectorUpMenuObj.size(); ++i)
          {           
//              PageObj = (PageObj)VectorUpMenuObj.elementAt(i);
                request.setAttribute("up_menu_theme",VectorUpMenuObj.elementAt(i));

                RequestDispatcher Dispatcher = getServletContext().getRequestDispatcher("/WEB-INF/jsp/index.jsp");
                Dispatcher.forward(request, response);
          }
*/
          return;
     }
  
}




Цитата

2) Далее после запроса положено закрывать ResultSet, а перед скроллированием записей в ResultSet неплохо бы убедиться, что он не пуст. ResultSet.next() при пустом запросе запросто может сгенерировать Exception.

Так в классе отвечающем за запросы MySQLQuery устанлена обработка исключительных ситуаций, или кроме всего прочего надобно делать проверку наличия выборки по БД?
if(resultQuery == null) { return VectorPageObj; }

package MySQL;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

Код

import java.util.*;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

/**
 *
 * @author initmax
 */
public class MySQLQuery {

    private Connection CurrentConnect; //Объект типа подключение для работы с БД
    private Vector VectorPageObj = new Vector(); //создать объект типа вектор "динамическое" создание массива


public MySQLQuery() {}

//Конструктор принимает текущее установленное соединение с БД
public MySQLQuery(Connection CurrentConnectBase)
{
    CurrentConnect = CurrentConnectBase;
}

//*****************************************************************
//Метод принимает имя таблицы и возвращает полную по ней выборку
public Vector SelectAllField(String NameTable)
{
       try
       {
//Выполним запрос в БД по имени таблицы, переданой методу
         Statement st = CurrentConnect.createStatement();
         String query = ("select * from "+NameTable);
         ResultSet resultQuery = null;
         resultQuery = st.executeQuery(query);

//проверим есть ли данные по запросу
         if(resultQuery == null) { return VectorPageObj; }

//Пройдём в цикле по результату выполненого массива
//Создадим массив "Vector" объектов с данными страницы
           while (resultQuery.next())
           {
              GenPageMySQL PageObj = new GenPageMySQL();

              PageObj.setId(resultQuery.getInt("id"));
              PageObj.setTheme(resultQuery.getString("theme"));
              PageObj.setPage(resultQuery.getString("page"));

              VectorPageObj.add(PageObj); //добавим в конец массива заполненый объект
           }


       }
       catch (SQLException e) {
         e.printStackTrace();
      }

          return VectorPageObj;
}



    /**
    *@set the CurrentConnect
    */
    public void setConnection(Connection CurrentConnectBase) {
         CurrentConnect = CurrentConnectBase;
    }
 
}


Так или я что-то не понял?


Цитата

3) Зачем вы создаете перед запросом Vector? Он же все равно создается внутри класса MySQLQuery?

Да он создаётся внутри класса,но объявлен как private, поэтому метод возвращает Vector
ссылка на который инициализируется в indexServlet
VectorPage = MySQLQueryObj.SelectAllField("up_menu");
или Вы полагаете более верным решением создать в классе MySQLQuery метод GetVector?


Цитата

4) Далее согласно стандартному стилю именований методов в Java если имя метода начинается с глагола, то его надо писать маленькими буквами. Например не SelectAllFields(), а selectAllFields()

Учту, Благодарю!

Цитата

Ну это все относится к стилю, а не к сути. По сути вы устанавливаете соединение с БД, но не проверяете живо оно или нет, просто выдаете printStackTrace() и идете дальше. Ну вот поэтому и получаете NullPointerException. А соединение с БД вы (как уже говорил выше) устанавливаете при каждом запросе и через несколько запросов ресурсы коннектов БД заканчиваются.


Делать так как указал выше в классе public class indexServlet?



Автор: ivanovpv 28.10.2009, 12:59
Цитата(initmax @  28.10.2009,  10:38 Найти цитируемый пост)
Да Вы правы, вот переучиваюсь smile поразительно что так быстро раскусили, наверное сами на PHP когда-то кодили ;)


Нет - не люблю я ваш PHP, просто приходилось разбираться в PHP кодах.

1) проверять живость соединения надо не только проверкой на null, но также и вызовом isClosed()
2) init() сервлета нельзя вызывать самому
3) по-поводу создания Vector все равно неправильно. Код конечно будет работать, но созданный объект Vector будет теряться.

А вообще по умному надо, чтобы соединение JDBC выдавал вам веб сервер через JNDI - надо настраивать сервер.

В общем вам учиться и учиться, дерзайте  smile 

Автор: initmax 28.10.2009, 13:01
Трагизм в том что аналогичные классы созданые как Java project с таким вот Main

Код

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package javatest;

import java.util.*;
import java.io.*;
import javatest.MySQL.*;


/**
 *
 * @author Admin
 */
public class Main {


    private static String getpage;
    //Подключиться к БД
    private static  MySQLConnect MySQLConnectObj = new MySQLConnect();
    private static MySQLQuery MySQLQueryObj = new MySQLQuery();


    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {


          MySQLConnectObj.DownloadDriver(); //загрука драйвера
          MySQLConnectObj.Connected(); //подключение к MySQL

          //Передача утсновленного соединения с БД объекту "запросы"
          MySQLQueryObj.setConnection(MySQLConnectObj.GetConnection());



            Vector VectorPage = new Vector(); //для массива объектов из БД
           VectorPage = MySQLQueryObj.SelectAllField("up_menu");//выборка по БД

          GenPageMySQL PageObj = new GenPageMySQL();
          for(int i=0; i<VectorPage.size(); ++i)
          {
             PageObj = (GenPageMySQL)VectorPage.elementAt(i);
             System.out.print(PageObj.getTheme());
          }


         MySQLConnectObj.DisConnected();

    }

}


Работает на УРА..

З.Ы.
лог сервера TOMCAT без ругани 

Автор: ivanovpv 28.10.2009, 15:22
Цитата(initmax @  28.10.2009,  13:01 Найти цитируемый пост)
Трагизм в том что аналогичные классы созданые как Java project с таким вот Main Работает на УРА..


Ага вот именно поэтому клиент-серверным программерам платят больше, а консольным копейки smile


Цитата(initmax @  28.10.2009,  13:01 Найти цитируемый пост)
лог сервера TOMCAT без ругани  

Чтобы он ругался, надо чтобы у вас был подключен логгер, почитайте например http://artamonov.ru/2007/04/06/vvedenie-v-log4j/

Автор: initmax 28.10.2009, 16:08
об авторе статейки 
Цитата


 я научился доступно объяснять разные сложные штуки, в том числе те которые сам не понимаю.


буду гуглить на предмет логирования веб-сервером выполнения сервлета smile))

Автор: initmax 28.10.2009, 16:51
28.10.2009 15:41:58 org.apache.catalina.core.AprLifecycleListener init
INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: C:\Program Files\Java\jdk1.5.0_06\bin;.;C:\WINDOWS\system32;C:\WINDOWS;C:\Program Files\PC Connectivity Solution\;C:\Java\jre6\bin;;;C:\Program Files\Java\jdk1.5.0_06\bin
28.10.2009 15:41:58 org.apache.coyote.http11.Http11Protocol init
INFO: Initializing Coyote HTTP/1.1 on http-8080
28.10.2009 15:41:58 org.apache.catalina.startup.Catalina load
INFO: Initialization processed in 899 ms
28.10.2009 15:41:58 org.apache.catalina.core.StandardService start
INFO: Starting service Catalina
28.10.2009 15:41:58 org.apache.catalina.core.StandardEngine start
INFO: Starting Servlet Engine: Apache Tomcat/6.0.20
28.10.2009 15:41:59 org.apache.catalina.core.StandardContext resourcesStart
SEVERE: Error starting static Resources
java.lang.IllegalArgumentException: Document base K:\NetBeans_project\FirstServlet\build\web does not exist or is not a readable directory
    at org.apache.naming.resources.FileDirContext.setDocBase(FileDirContext.java:142)
    at org.apache.catalina.core.StandardContext.resourcesStart(StandardContext.java:4048)
    at org.apache.catalina.core.StandardContext.start(StandardContext.java:4217)
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:791)
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:771)
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:526)
    at org.apache.catalina.startup.HostConfig.deployDescriptor(HostConfig.java:630)
    at org.apache.catalina.startup.HostConfig.deployDescriptors(HostConfig.java:556)
    at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:491)
    at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1206)
    at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:314)
    at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119)
    at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1053)
    at org.apache.catalina.core.StandardHost.start(StandardHost.java:722)
    at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
    at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
    at org.apache.catalina.core.StandardService.start(StandardService.java:516)
    at org.apache.catalina.core.StandardServer.start(StandardServer.java:710)
    at org.apache.catalina.startup.Catalina.start(Catalina.java:583)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:585)
    at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:288)
    at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:413)
28.10.2009 15:41:59 org.apache.catalina.core.StandardContext start
SEVERE: Error in resourceStart()
28.10.2009 15:41:59 org.apache.catalina.core.StandardContext start
SEVERE: Error getConfigured
28.10.2009 15:41:59 org.apache.catalina.core.StandardContext start
SEVERE: Context [/FirstServlet] startup failed due to previous errors
28.10.2009 15:41:59 org.apache.catalina.core.StandardContext stop
INFO: Container org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/FirstServlet] has not been started
28.10.2009 15:42:01 org.apache.coyote.http11.Http11Protocol start
INFO: Starting Coyote HTTP/1.1 on http-8080
28.10.2009 15:42:01 org.apache.jk.common.ChannelSocket init
INFO: JK: ajp13 listening on /0.0.0.0:8009
28.10.2009 15:42:01 org.apache.jk.server.JkMain start
INFO: Jk running ID=0 time=0/156  config=null
28.10.2009 15:42:01 org.apache.catalina.startup.Catalina start
INFO: Server startup in 2502 ms
28.10.2009 15:42:02 org.apache.catalina.startup.HostConfig checkResources
INFO: Undeploying context [/initmax]
28.10.2009 15:42:02 org.apache.catalina.core.StandardContext start
INFO: Container org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/initmax] has already been started

Судя по всему контейнер сервлет не может стартовать, а почему?

Автор: ivanovpv 28.10.2009, 21:12
Цитата(initmax @  28.10.2009,  16:51 Найти цитируемый пост)
java.lang.IllegalArgumentException: Document base K:\NetBeans_project\FirstServlet\build\web does not exist or is not a readable directory


Тут же все написано...

Автор: ShurikA 28.10.2009, 22:12
initmax, 
У меня один вопрос: а зечем изобретать колесо? Можно же пользоваться уже давно разработанными и оттестированными инструментами.

Автор: initmax 29.10.2009, 09:39
Цитата

У меня один вопрос: а зечем изобретать колесо? Можно же пользоваться уже давно разработанными и оттестированными инструментами.

Hibernate ?

Автор: ShurikA 29.10.2009, 22:20
Цитата(initmax @  29.10.2009,  08:39 Найти цитируемый пост)
Hibernate ? 

да, на пример.
Или любой другой JPA.

Автор: Samotnik 30.10.2009, 11:01
initmax,  smile   мдяяя...  вам точно заняться нечем ... 

Автор: initmax 30.10.2009, 11:49
Цитата

да, на пример.
Или любой другой JPA.


Для начала я разбираюсь в технологических аспектах, потом фреймворк.
Переход на jdk 1.6, проблему решил. 
всем Спасибо.

Автор: ivanovpv 30.10.2009, 12:37
Цитата(initmax @  30.10.2009,  11:49 Найти цитируемый пост)
Для начала я разбираюсь в технологических аспектах, потом фреймворк.

Вот это правильно! А то уже сталкивался, что народ за фреймворком не видит (и что самое страшное не понимает) как все работает. Hibernate еще успеете поковыряться, там тоже своих тараканов хватает  smile 

Автор: Samotnik 30.10.2009, 13:53
ivanovpv, ну так ведь никто не спорит ! 
Разбираться конечно надо. Но зачем изобраетать то, что уже есть ?  Качай, подключай и пользуйся ! 
Напиши простейшее приложение на хибернете и продеббаж его.  smile Чтобы быть в курсе как оно работает. Да к тому же доков куча на оф сайте - читать не перечитать. 
Но если времени свободного у человека вагон, то пусть занимается этим smile 
У меня к примеру, нет времени писать аналоги существующим фреймворкам. 

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