
Это 5 статья из цикла статей: «Простой сайт на Java» и сегодня мы поговорим о работе с базой данных в Java. На повестке дня:
- создание записи;
- выбор всех записей;
- изменение, удаление записей;
- выбор по определенному параметру.
Перез началом, настоятельно рекомендую почитать теорию об SQL.
Для создания запроса создается объект PreparedStatement. Его удобнее использовать для отправки операторов SQL в базу данных. Этот особый тип инструкции выводится из более общего класса, Statement.
PreparedStatement создается не как обычный новый объект. Он берется как результат метода prepareStatement объекта Connection. Общий вид записи будет выглядеть так:
- Connection con = ConnectionPool.getInstance().getConnection(); - получение соединения с базой данных
Чтобы выполнить запрос нужно вызвать метод executeUpdate() для создания, редактирования, удаления записи или executeQuery() для извлечения записи. Метод executeQuery() возвращает ResultSet объект из которого уже можно получить данные и использовать их для наших целей. Чтобы долго не расписывать теорию предлагаю сразу перейти к примерам.
В прошлой статье мы уже создали базу данных и создали пул соединений. Теперь пришло время поработать с базой.
В этой статье будет показано пример работы с таблицей Article. Работу с остальными доменными классами можно будет посмотреть в видео или скачать готовый код, который будет в конце статьи.
Для начала нужно извлечь все данные с таблицы article:
- public List<Article> getAllArticles() {
- List<Article> articles = new ArrayList<Article>();//создаем список статей. пока пустой
- Article article = null;
- try {//PreparedStatement выбрасывает SQLException. Поэтому, нужно всегда следить за тем, чтобы код был обработан обработчиком try-catch
- PreparedStatement pr = con.prepareStatement("select id, title, body, category_id, users_id from article");
- while (rs.next()){//пока у ResultSet есть данные
- article = new Article();
- article.setId(rs.getInt(1));//вынимаем данные в том порядке, в котором мы указали в запросе. Можно выбирать не по
- //цифре, а по имени поля в таблице базы например можно было бы указать rs.getInt("id")
- article.setTitle(rs.getString(2));
- article.setBody(rs.getString(3));
- Category category = new Category();//не забываем о вложенных объектах
- category.setId(rs.getInt(4));
- article.setCategory(category);
- Users user = new Users();
- user.setId(rs.getInt(5));
- article.setUsers(user);
- articles.add(article);
- }
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- try {
- con.close();//после выполнения запроса нужно закрыть соединение
- //метод close тоже выбрасывает исключение. Для избежания громоздких записей лучше обработать исключение один раз в отдельном методе например closeConnection
- //и потом вызывать только его
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return articles;
- }
Такой же механизм и в выборе данных по определенному критерию:
- public Article getArticleById(int id) {
- Article article = null;
- try {
- + "category_id, users_id from article where id=?");
- pr.setInt(1, id);//то, что нужно вставить вместо первого знака вопроса
- //можно было бы написать "select id, title, body, " + "category_id, users_id from article where id="+id в запросе
- //но в целях безопасности советую подставлять значение через метод сет.
- if (rs.next()){
- article = new Article();
- article.setId(rs.getInt(1));
- article.setTitle(rs.getString(2));
- article.setBody(rs.getString(3));
- Category category = new Category();
- category.setId(rs.getInt(4));
- article.setCategory(category);
- Users user = new Users();
- user.setId(rs.getInt(5));
- article.setUsers(user);
- }
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- try {
- connection.close();
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return article;
- }
Для создания записи нужно только заменить pr.executeQuery(); на pr.executeUpdate();
- public int createArticle(Article article) {
- try {
- + "article(title, body, category_id, users_id) values(?,?,?,?)");
- pr.setString(1, article.getTitle());
- pr.setString(2, article.getBody());
- pr.setInt(3, article.getCategory().getId());
- pr.setInt(4, 1);
- pr.executeUpdate();
- // TODO Auto-generated catch block
- e.printStackTrace();
- try {
- con.close();
- // TODO Auto-generated catch block
- e1.printStackTrace();
- }
- return 0;
- }
- try {
- con.close();
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return 1;//чтобы контролировать выполнение запроса можно выводить переменную в зависимости от успешность или неудачи выполнения запроса.
- //можно также выводить айди объекта, который был добавлен в базу.
- }
Ну и бонусом скину код для обновления и удаления записи:
- public int editArticle(Article article) {
- int result = 0;
- try {
- + "title=?, body=?, category_id=?");
- pr.setString(1, article.getTitle());
- pr.setString(2, article.getBody());
- pr.setInt(3, article.getCategory().getId());
- result = pr.executeUpdate();
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- try {
- con.close();
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return result;
- }
- public void deleteArticle(int id) {
- try {
- pr.setInt(1, id);
- pr.executeUpdate();
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- try {
- con.close();
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
Как видите, работать с базой через стандартный jdbc просто но неудобно: записи получаются громоздкие, нужно постоянно обрабатывать возможные ошибки, ошибиться в коде очень легко, пропустил символ в строке выбора и код не работает. И это у нас еще небольшая база. Понятно, что легче всего пользоваться фреймоворками типа Hibernate, Spring JPA. Эти инструменты очень облегчают жизнь.
Наш случай — научиться и понять, как все работает на начальных уровнях. Ведь все фреймворки строятся на этом.
Код на гитхаб: https://github.com/caligula95/simplewebapp-part5
Видео на ютуб: