Медленная работа с БД через PreparedStatement

468
07 февраля 2017, 19:40

Как мне в этом коде, сделать так, чтобы я верно использовал PrepareStatement? Я уже всю реализацию ДАО не скидываю, так как очень много кода. В моем коде PrepareStatement замедляет работу, а нужно чтобы ускорял. Я его использую не верно. Я так понимаю, мне его как то открыть надо один раз, потом использовать везде как-то, и потом закрыть? Буду рад любой помощи.

public class MySqlDaoStudent implements DaoStudent {
    private PreparedStatement stm=null;
    private final Connection connection;
    private ResultSet rs=null;
    public MySqlDaoStudent(Connection connection) {
        this.connection = connection;
    }
    @Override
    public Student read(int key) throws SQLException {
        String sql="SELECT * FROM student_db.student where id = ?;";
        Student student = new Student();
        try {
            stm = connection.prepareStatement(sql);
            stm.setInt(1, key);
            rs = stm.executeQuery();
            rs.next();
            student.setId(rs.getInt("ID"));
            student.setFirst_name(rs.getString("FIRST_NAME"));
            student.setSecond_name(rs.getString("SECOND_NAME"));
         } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if(rs!=null){
                rs.close();
            } 
            if(connection!=null){
                connection.close();
            }
            if (stm!=null){
                stm.close();
            }
        }
        return student;
    }
    @Override
    public List<Student> getAll() throws SQLException {
        String sql="SELECT * FROM student_db.student";
        List<Student> list=new ArrayList<>();
        Student student=new Student();
        try{
            stm=connection.prepareStatement(sql);
            rs=stm.executeQuery();
            while(rs.next()){
                student.setId(rs.getInt("ID"));
                student.setFirst_name(rs.getString("FIRST_NAME"));
                student.setSecond_name(rs.getString("SECOND_NAME"));
                list.add(student);
            }
        } catch (SQLException e){
            e.printStackTrace();
        } finally {
            if(rs!=null){
                rs.close();
            }
            if(connection!=null){
                connection.close();
            }
            if (stm!=null){
                stm.close();
            }
        }
        return list;
    }
}
Answer 1

рекомендую модернизировать код таким образом

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
 * Created by TS on 07.02.2017.
 */
public class MySqlDaoStudent implements DaoStudent {
    private static final String ALL_STUDENTS = "SELECT * FROM student_db.student";
    private PreparedStatement stm = null;
    private PreparedStatement allPreparedStatement = null;
    private final Connection connection;
    public MySqlDaoStudent(Connection connection) {
        this.connection = connection;
    }
    private void init() throws SQLException {
        if (allPreparedStatement == null)
            allPreparedStatement = connection.prepareStatement(ALL_STUDENTS);
    }
    public Student read(int key) throws SQLException {
        // у нас каждый раз новый key, и так как у нас 1 параметр, запрос легче сформировать так
        String sql = String.format("SELECT * FROM student_db.student where id = %s;", key);
        Student student = new Student();
        try (ResultSet rs = stm.executeQuery(sql)) { // такая конструкция позволяет закрывать rs (вместо finally) 
            rs.next();
            student.setId(rs.getInt("ID"));
            student.setFirst_name(rs.getString("FIRST_NAME"));
            student.setSecond_name(rs.getString("SECOND_NAME"));
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return student;
    }
    public List<Student> getAll() throws SQLException {
        init();
        List<Student> list = new ArrayList<>();
        Student student = new Student();
        try (ResultSet rs = allPreparedStatement.executeQuery()) {
            while (rs.next()) {
                student.setId(rs.getInt("ID"));
                student.setFirst_name(rs.getString("FIRST_NAME"));
                student.setSecond_name(rs.getString("SECOND_NAME"));
                list.add(student);
            }
        } catch (SQLException e) {
            e.printStackTrace();
            throw e;
        }
        return list;
    }
    public void closeConnection() throws SQLException {
        if (connection != null) {
            connection.close();
        }
    }
}
Answer 2

Смысл PreparedStatement в том, чтобы скомпилировать запрос один раз и использовать все время меняя только параметры запроса. Фактически, компиляция запроса происходит при вызове PrepareStatement() - ваша проблема в том, что вы при каждом выполнении запроса заново компилируете запрос.

Отделите мух от котлет, а именно: разделите этап компиляции запроса и этап выполнения прекомпилированного запроса.

Ну и на закуску: поскольку PreparedStatement привязан к Connection, то при закрытии соединения естественно вы теряете свой прекомплированный запрос (на что вам и указывают в комментариях)

Answer 3

вот мой код..верно ли я все сделал?

package com.mysql;
import com.classes.StudentSubject;
import com.interfaces.DaoStudentSubject;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class MySqlDaoDaoStudentSubject implements DaoStudentSubject {
public static final String SELECT=" SELECT * FROM student_db.student ";
private PreparedStatement stm=null;
private PreparedStatement AllPreparedStatement=null;
private final Connection connection;
private ResultSet rs=null;
private void init() throws SQLException{
    if(AllPreparedStatement==null){
        AllPreparedStatement=connection.prepareStatement(SELECT);
    }
}
public MySqlDaoDaoStudentSubject(Connection connection) {
    this.connection = connection;
}
//Прочитать всех студентов
    @Override
    public void getAllStudent (StudentSubject ss) throws SQLException {
    init();
    try ( ResultSet rs=AllPreparedStatement.executeQuery(SELECT)){
        while (rs.next()) {
            System.out.println(rs.getInt("id")+" "+rs.getString("first_name")+" "+rs.getString("second_name"));
        }
    }
    catch (Exception e){
        e.printStackTrace();
    }
    }
Answer 4

Получить все предметы одного студента вместе с их оценками

    public static final String SELECT="select n.first_name," +
    "n.second_name, s.subject, s.mark" +
            " from " +
            "   subjects s inner join " +
            " names n on s.names_id=n.id " +
            "where s.names_id=1";

запрос для меня как будет выглядеть ?

не могу составить так сказать общий запрос.

 public static final String SELECT="select (first_name," +
    "second_name, subject, mark") +
            " from " +
            "   subjects inner join " +
            " names VALUES (?,?,?,?,?) ";
READ ALSO
Как правильно конвертировать int в binary?

Как правильно конвертировать int в binary?

Есть несколько способов получить бинарное значение с int

500
не отрабатывает шрифт в браузерах

не отрабатывает шрифт в браузерах

Написан вот такой код, использую бутстрап

471
Нужна помощь/совет в адаптивной верстке + owlcarousel

Нужна помощь/совет в адаптивной верстке + owlcarousel

Есть примерно такая структура сайта, поведение блоков примерно соответствует нужному результату, кроме последнего

492
Не работает slider [требует правки]

Не работает slider [требует правки]

codepenio скопировал исходники этого слайдшоу и не работает помогите разобраться

457