Страницы

Поиск по вопросам

воскресенье, 8 марта 2020 г.

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

#java #mysql #jdbc #dao #preparedstatement


Как мне в этом коде, сделать так, чтобы я верно использовал 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 getAll() throws SQLException {
        String sql="SELECT * FROM student_db.student";
        List 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;
    }
}

    


Ответы

Ответ 1



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

Ответ 2



рекомендую модернизировать код таким образом 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 getAll() throws SQLException { init(); List 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(); } } }

Ответ 3



Верное использование PreparedStatement заключается в том, что необходимо подготовить запрос в СУБД, прежде, чем он будет отправлен. Его нужно подготовить, сохранить в поле, а потом использовать, таким образом достигается максимальная скорость обработки любых запросов в любом кол-ве. Вот код решения моего вопроса: (sql запрос сохранил в константу) /* Константа sql запроса */ private static final String SQL_SELECT_ALL_STUDENT = "SELECT id, first_name, second_name FROM student_db.student"; /* поле подключения */ private Connection connection = null; /* поле PS */ private PreparedStatement psSelectAllStudent = null; // использую Properties для чтения user,password,driver,url // подключаюсь к СУБД private Connection getConnection() throws DaoException { Properties property = new Properties(); InputStream inputStream = null; try { inputStream = this.getClass().getResourceAsStream("/config.properties"); property.load(inputStream); String url = property.getProperty("url"); String user = property.getProperty("user"); String password = property.getProperty("password"); String driver = property.getProperty("driver"); Class.forName(driver); if (connection == null) { connection = DriverManager.getConnection(url, user, password); } } catch (IOException ex) { DaoException er = new DaoException("ошибка загрузки файла ", ex); throw er; } catch (ClassNotFoundException ex) { DaoException er = new DaoException("ошибка Class.forName(driver) ", ex); throw er; } catch (SQLException ex) { DaoException er = new DaoException("ошибка соединения с СУБД ", ex); throw er; } return connection; } //подготавливаю PS в СУБД и сохраняю в поле private void selectAllStudentPs(String sql) throws DaoException { getConnection(); try { if (psSelectAllStudent == null) { psSelectAllStudent = connection.prepareStatement(sql); } } catch (SQLException er) { DaoException ex = new DaoException("ошибка подготовки запроса в selectStudentPs ", er); throw ex; } } //получаю список того, что было необходимо сделать в задании @Override public List selectAllStudent() throws DaoException { ResultSet resultSet=null; List list = new ArrayList<>(); try { selectAllStudentPs(SQL_SELECT_ALL_STUDENT); resultSet = psSelectAllStudent.executeQuery(); while (resultSet.next()) { Student ss = new Student(); ss.setId(resultSet.getInt("id")); ss.setFirstName(resultSet.getString("first_name")); ss.setSecondName(resultSet.getString("second_name")); list.add(ss); } } catch (SQLException ex) { DaoException er = new DaoException("ошибка выполения SQL_SELECT_ALL_STUDENT ", ex); throw er; }finally { if (resultSet != null) { try { resultSet.close(); } catch (SQLException ex) { DaoException er = new DaoException("ошибка закрытия resultSet в " + "selectStudent ", ex); throw er; } } } return list; } /* ---- */ Таким образов и получается именно ускорение PreparedStatement !

Комментариев нет:

Отправить комментарий