2014-02-09 3 views
3

Я выполняю операции CRUD с помощью Servlet и JSP. Следующий класс используется для извлечения соединения из пула соединений, поддерживаемого сервером (Tomcat).Выполнение операций CRUD с использованием Servlet/JSP

public final class DatabaseConnection { 

    private static final DataSource dataSource; 

    static { 
     try { 
      Context initContext = new InitialContext(); 
      Context context = (Context) initContext.lookup("java:/comp/env"); 
      dataSource = (DataSource) context.lookup("jdbc/assignment_db"); 
     } catch (NamingException e) { 
      Logger.getLogger(DatabaseConnection.class.getName()).log(Level.SEVERE, null, e); 
      throw new ExceptionInInitializerError("DataSource not initialized."); 
     } 
    } 

    public static Connection getConnection() throws SQLException { 
     return dataSource.getConnection(); 
    } 
} 

И методы в следующем классе (DAO) выполняют операции CRUD.

public final class CountryDao { 

    public Long getCurrentRow(Long id) throws SQLException { 
     Connection connection = null; 
     PreparedStatement preparedStatement = null; 
     ResultSet resultSet = null; 

     try { 
      connection = DatabaseConnection.getConnection(); 
      preparedStatement = connection.prepareStatement("select rownum from (select @rownum:[email protected]+1 as rownum, tbl.country_id from country_tbl tbl, (select @rownum:=0)t order by tbl.country_id desc)t where country_id=?"); 
      preparedStatement.setLong(1, id); 
      resultSet = preparedStatement.executeQuery(); 
      return resultSet.next() ? resultSet.getLong("rownum") : 1; 
     } finally { 
      if (connection != null) {connection.close();} 
      if (resultSet != null) {resultSet.close();} 
      if (preparedStatement != null) {preparedStatement.close();} 
     } 
    } 

    public Long rowCount() throws SQLException { 
     Connection connection = null; 
     PreparedStatement preparedStatement = null; 
     ResultSet resultSet = null; 

     try { 
      connection = DatabaseConnection.getConnection(); 
      preparedStatement = connection.prepareStatement("select count(*) as cnt from country_tbl"); 
      resultSet = preparedStatement.executeQuery(); 
      resultSet.next(); 
      return resultSet.getLong("cnt"); 
     } finally { 
      if (connection != null) {connection.close();} 
      if (resultSet != null) {resultSet.close();} 
      if (preparedStatement != null) {preparedStatement.close();} 
     } 
    } 

    public List<CountryBean> getData(Long currentPage, Long pageSize) throws SQLException { 
     Connection connection = null; 
     PreparedStatement preparedStatement = null; 
     ResultSet resultSet = null; 
     List<CountryBean> countryBeans = new ArrayList<CountryBean>(); 

     try { 
      connection = DatabaseConnection.getConnection(); 
      preparedStatement = connection.prepareStatement("select * from country_tbl order by country_id desc limit ?,?"); 

      //preparedStatement.setMaxRows(pageSize); 
      preparedStatement.setLong(1, currentPage); 
      preparedStatement.setLong(2, pageSize); 
      resultSet = preparedStatement.executeQuery(); 

      while (resultSet.next()) { 
       CountryBean countryBean = new CountryBean(); 
       countryBean.setCountryId(resultSet.getLong("country_id")); 
       countryBean.setCountryName(resultSet.getString("country_name")); 
       countryBean.setCountryCode(resultSet.getString("country_code")); 
       countryBeans.add(countryBean); 
      } 
     } finally { 
      if (connection != null) {connection.close();} 
      if (resultSet != null) {resultSet.close();} 
      if (preparedStatement != null) {preparedStatement.close();} 
     } 

     return countryBeans; 
    } 

    public boolean delete(Long id) throws SQLException { 
     boolean status = false; 
     Connection connection = null; 
     PreparedStatement preparedStatement = null; 

     try { 
      connection = DatabaseConnection.getConnection(); 
      preparedStatement = connection.prepareStatement("delete from country_tbl where country_id=?"); 
      preparedStatement.setLong(1, id); 

      if (preparedStatement.executeUpdate() == 1) { 
       status = true; 
      } 
     } finally { 
      if (connection != null) {connection.close();} 
      if (preparedStatement != null) {preparedStatement.close();} 
     } 
     return status; 
    } 

    public boolean delete(Long[] ids) throws SQLException { 
     boolean status = false; 
     Connection connection = null; 
     PreparedStatement preparedStatement = null; 

     try { 
      connection = DatabaseConnection.getConnection(); 
      connection.setAutoCommit(false); 
      preparedStatement = connection.prepareStatement("delete from country_tbl where country_id=?"); 
      int len = ids.length; 

      for (int i = 0; i < len; i++) { 
       preparedStatement.setLong(1, ids[i]); 
       preparedStatement.addBatch(); 
      } 

      preparedStatement.executeBatch(); 
      connection.commit(); 
      status = true; 
     } finally { 
      if (connection != null) {connection.close();} 
      if (preparedStatement != null) {preparedStatement.close();} 
     } 
     return status; 
    } 

    public boolean insert(String countryName, String countryCode) throws SQLException { 
     boolean status = false; 
     Connection connection = null; 
     PreparedStatement preparedStatement = null; 

     try { 
      connection = DatabaseConnection.getConnection(); 
      preparedStatement = connection.prepareStatement("insert into country_tbl(country_name, country_code)values(?,?)"); 
      preparedStatement.setString(1, countryName); 
      preparedStatement.setString(2, countryCode); 
      preparedStatement.executeUpdate(); 
      status = true; 
     } finally { 
      if (connection != null) {connection.close();} 
      if (preparedStatement != null) {preparedStatement.close();} 
     } 
     return status; 
    } 

    public boolean update(Long countryId, String countryName, String countryCode) throws SQLException { 
     boolean status = false; 
     Connection connection = null; 
     PreparedStatement preparedStatement = null; 

     try { 
      connection = DatabaseConnection.getConnection(); 
      preparedStatement = connection.prepareStatement("update country_tbl set country_name=?, country_code=? where country_id=?"); 
      preparedStatement.setString(1, countryName); 
      preparedStatement.setString(2, countryCode); 
      preparedStatement.setLong(3, countryId); 
      preparedStatement.executeUpdate(); 
      status = true; 
     } finally { 
      if (connection != null) {connection.close();} 
      if (preparedStatement != null) {preparedStatement.close();} 
     } 

     return status; 
    } 
} 

Эти методы называются надлежащим образом из сервлета после проверки. Сервлет, в свою очередь, взаимодействует с JSP (вместе с JSTL/EL).

Осталось только один вопрос. Керри, connection, preparedStatement и resultSet все локальные переменные к определенным методам.

Могу ли я объявить их только в одном месте в качестве членов класса (переменные экземпляра)? Может ли так поддерживать согласованное состояние?

Не нужно концентрироваться на основной логике. Пожалуйста, не просто скажите: Лучше использовать структуру MVC :)

+0

эй, я не понимаю вашу проблему ... просто попробуйте это, HTTP: // publib .boulder.ibm.com/infocenter/db2luw/v8/index.jsp? topic =/com.ibm.db2.udb.doc/ad/tjvpsxqu.htm, http://docs.oracle.com/javase/7/ docs/api/java/sql/PreparedStatement.html – jmail

+0

Я не знаю, как это узнать. Нет никаких проблем с приведенным кодом. – Tiny

ответ

3

Могу ли я объявить их только в одном месте в качестве членов класса (переменных экземпляра)?

Вы можете сделать это, но класс будет бесполезным. Вызывающий не может повторно использовать один и тот же экземпляр для нескольких потоков, не нарушая поведения каждого отдельного метода, вызванного несогласованным состоянием. В случае сервлета как вызывающего, таким образом, вы не можете создать экземпляр только один раз в файле сервлетов и повторно использовать его несколько раз в методах doXxx(). Вы были бы вынуждены повторно создать экземпляр в области threadlocal (так, внутри метода doXxx()). Это должно быть четко задокументировано в классе javadoc. Но, в конце концов, разработка класса downunsafe DAO не имеет смысла. Придерживайтесь текущего дизайна (или, если вы не просто хобби, переключитесь на JPA;)).


Может делать это поддерживать согласованное состояние точно?

Нет! Напротив, это было бы непоследовательно. Вы не можете разделить один и тот же оператор или набор результатов по нескольким запросам. Каждый запрос должен иметь свой собственный оператор и набор результатов. Каждый вызов метода в экземпляре изменил бы переменные экземпляра, в результате чего другие вызовы, выполняемые по-прежнему выполняются, будут работать в поврежденном состоянии.Совместное использование соединения возможно, но это задание обычно выполняется пулом соединений. Учитывая, что вы используете источник данных, у вас, скорее всего, уже есть один.


Тем не менее, если вы ненавидите повторный шаблонный код, но на самом деле хотите придерживаться хорошего «ола JDBC API, посмотрите на Execute Around pattern/idiom и/или Java 7's automatic resource management (ARM). При этом должно быть возможно создать вспомогательный DB-класс с кучей интерфейсов и в конечном итоге получить общий абстрактный класс DAO, методы которого принимают только SQL-запрос и значения параметров -if any.

+0

Только одно подтверждение. Безопасно ли иметь «соединение» в качестве переменной экземпляра (в «CountryDao» в образце кода)? Благодарю. – Tiny

+1

Нет. В качестве аргумента метода для этого случая вы должны иметь возможность вызывать несколько запросов в одной транзакции (так что, когда один запрос выдает исключение, все откатывается). – BalusC

1

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

например -

Если вы вызываете два метода этого класса на тот же объект. Один метод занимает две минуты для выполнения, а другой метод занимает 5 минут В этом случае первый метод закрывает соединение, а второй метод выдает исключение. Там есть много других причин ...

1

Конечно, вы можете использовать connection, statement и resultset в качестве переменной-члена, если вы не используете одни и те же объекты в двух или более разных потоках.

Как и в сервлете, вы создадите объект dao, поэтому каждый раз, когда сервлет попадает в новый поток, начинается, и этот новый поток собирается создать новый объект dao для выполнения какого-либо метода.

Существует только случай, когда он может выйти из строя, в сервлет, который вы создаете объект dao, и передаете этот же объект двум различным потокам, созданным вручную, чтобы выполнить два метода. в таком случае возможно, что один поток будет считывать все записи из набора результатов, но в то же время другой поток выполняет запрос get и пытается сбросить набор результатов, что приведет к исключению.

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

Однако, если вы намереваетесь просто удалить шаблонный код, то у вас есть несколько других путей. Вы можете создать класс с именем шаблонной как этот

class Boilerplate{ 
    private Connection con; 
    private PreparedStatement ps; 

    public Boilerplate(String query){ 
    //initialize connection, ps and resultset 
    con=DatabaseConnection.getConnection(); 
    ps=connection.prepareStatement(query); 
    } 

    destroy void Boilerplate(){ 
    if(con!=null) 
     con.close() 
    if(ps!=null) 
     ps.close(); 
    } 
} 

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

1

Выполнение операций CRUD с использованием Servlet/JSP

шаг за шагом создавая операции CRUD в JSP/сервлет

Follow this link ...

1

Общие вещи:

Как Зная терминологию важно. Переменные экземпляра и переменные класса являются переменными-членами. Они оба являются переменными-членами, поскольку оба они связаны с определенным классом. Но существуют различия между переменными экземпляра и переменными класса.

Переменные экземпляра

Переменные экземпляра принадлежат к экземпляру класса. Другой способ сказать, что это instance variables, принадлежит к объекту, поскольку объект является экземпляром класса. У каждого объекта есть своя копия переменных экземпляра.Вот что декларация переменного экземпляра будет выглядеть следующим образом:

экземпляр переменной

class Taxes 
    { 
     int count; 
     /*...*/ 
    } 

классом переменных

class Taxes 
    { 
     static int count; 
     /*...*/ 
    } 
0
res.setContentType("text/html"); 

// Ask for a 16K byte response buffer; do not set the content length 
res.setBufferSize(16 * 1024); 

PrintWriter out = res.getWriter(); 
out.println("<HTML>"); 
out.println("<HEAD><TITLE>Hello World</TITLE></HEAD>"); 
out.println("<BODY>"); 
out.println("<BIG>Less than 16K of response body</BIG>"); 
out.println("</BODY></HTML>"); 
+0

Пожалуйста, объясните, как это связано с вопросом. – Tiny

0

Я использую свой пример и хочу создать связь. Но он показывает мне NoInitialContextException, когда я использую junit для его проверки. Как это сделать, чтобы исправить это? Вот мой код ниже.

public final class DataSourceUtil {      
    private static Context initCtx; 
    private static Context envCtx; 
    private static DataSource dataSource;     

    static { 
    try {            
     // Initial a datasource for pooled connections.  
     initCtx = new InitialContext();     
     envCtx = (Context) initCtx.lookup("java:/comp/env");  
     dataSource = (DataSource) envCtx.lookup("jdbc/ServletDB");             
    } catch (NamingException e) {      
     Logger.getLogger(DataSourceUtil.class.getName()).log(Level.SEVERE, null, e);        
     throw new ExceptionInInitializerError("DataSource not initialized."); 
    }             
}           

    public static Connection getConnection() throws SQLException { 
    return dataSource.getConnection(); 
    } 
} 

И код Test

public class ConnectionTest() { 
    @Test 
    public void connectionTest2() { 
    try { 

    Connection connection = DataSourceUtil.getConnection(); 

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

и сообщение об ошибке:

Dec 23, 2015 9:06:46 PM com.wxz.server.dao.DataSourceUtil <clinit> 
SEVERE: null 
javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial 
+0

Это другой вопрос. Скорее всего, вам поможет лучше, если вы откроете новую тему вместо того, чтобы спрашивать людей, а именно, только меня, где, если необходимо, вы можете указать ссылку на этот вопрос. Единичное тестирование с использованием JUnit/Mockito - это совершенно другая вещь, чем реальная среда разработки, где вам может потребоваться выполнить поиск JNDI по-разному, о котором я совершенно не подозреваю. – Tiny

+0

Хорошо, я постараюсь создать новую тему и еще один вопрос. Использует ли ваш пример код для вас? Я имею в виду в статической области, он не может инициализировать экземпляр контекста в моем коде. Но в конструкторе класса работает. Спасибо вам за помощь. :) – Sam

+0

Да, он работал нормально в то время, когда задавался этот вопрос. Инициализация 'DataSouce' с помощью JNDI-поиска внутри инициализатора' static', возможно, придется что-то сделать с использованием инструмента тестирования, используемого, например, JUnit, который может быть отмечен только людьми, имеющими опыт работы с этим инструментом, и активно занимается разработкой тестовых примеров. – Tiny

Смежные вопросы