From 7430e7ff324df9f7900412f70b4a2992a257e6aa Mon Sep 17 00:00:00 2001 From: Yurii Soliar Date: Fri, 24 May 2024 14:14:14 +0300 Subject: [PATCH 1/4] resolve jdbc-intro --- pom.xml | 8 + .../java/mate/academy/ConnectionUtil.java | 27 ++++ src/main/java/mate/academy/Main.java | 55 +++++++ src/main/java/mate/academy/dao/BookDao.java | 19 +++ .../java/mate/academy/dao/BookDaoImpl.java | 141 ++++++++++++++++++ .../exception/DataProcessingException.java | 7 + src/main/java/mate/academy/model/Book.java | 54 +++++++ .../mate/academy/service/BookService.java | 19 +++ .../mate/academy/service/BookServiceImpl.java | 44 ++++++ src/main/resources/init_db.sql | 7 + 10 files changed, 381 insertions(+) create mode 100644 src/main/java/mate/academy/ConnectionUtil.java create mode 100644 src/main/java/mate/academy/dao/BookDao.java create mode 100644 src/main/java/mate/academy/dao/BookDaoImpl.java create mode 100644 src/main/java/mate/academy/exception/DataProcessingException.java create mode 100644 src/main/java/mate/academy/model/Book.java create mode 100644 src/main/java/mate/academy/service/BookService.java create mode 100644 src/main/java/mate/academy/service/BookServiceImpl.java create mode 100644 src/main/resources/init_db.sql diff --git a/pom.xml b/pom.xml index 683e84ec..f66e25ff 100644 --- a/pom.xml +++ b/pom.xml @@ -18,6 +18,14 @@ + + + com.mysql + mysql-connector-j + 8.3.0 + + + diff --git a/src/main/java/mate/academy/ConnectionUtil.java b/src/main/java/mate/academy/ConnectionUtil.java new file mode 100644 index 00000000..d17dc2c9 --- /dev/null +++ b/src/main/java/mate/academy/ConnectionUtil.java @@ -0,0 +1,27 @@ +package mate.academy; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.Properties; +import mate.academy.exception.DataProcessingException; + +public class ConnectionUtil { + private static final String URL = "jdbc:mysql://localhost:3306/book_db"; + private static final Properties PROPERTIES; + + static { + PROPERTIES = new Properties(); + PROPERTIES.put("user", "root"); + PROPERTIES.put("password", "rootroot"); + try { + Class.forName("com.mysql.cj.jdbc.Driver"); + } catch (ClassNotFoundException e) { + throw new DataProcessingException("Can not load JDBC driver", e); + } + } + + public static Connection getConnection() throws SQLException { + return DriverManager.getConnection(URL, PROPERTIES); + } +} diff --git a/src/main/java/mate/academy/Main.java b/src/main/java/mate/academy/Main.java index 0058fbf9..eabb0e95 100644 --- a/src/main/java/mate/academy/Main.java +++ b/src/main/java/mate/academy/Main.java @@ -1,7 +1,62 @@ package mate.academy; +import java.math.BigDecimal; +import mate.academy.dao.BookDao; +import mate.academy.lib.Injector; +import mate.academy.model.Book; +import mate.academy.service.BookService; +import mate.academy.service.BookServiceImpl; + public class Main { + private static final Injector injector = Injector.getInstance("mate.academy"); + private static BookService service; + public static void main(String[] args) { + BookDao bookDao = (BookDao) injector.getInstance(BookDao.class); + service = new BookServiceImpl(bookDao); + + testCreate(); + testFindAll(); + testFindById(); + testUpdate(); + testDelete(); + testFindAll(); + + service.deleteAll(); + } + + private static void testCreate() { + System.out.println("\nCREATE"); + Book bookHarry = new Book("Harry", new BigDecimal(1222)); + Book bookPotter = new Book("Potter", new BigDecimal(999)); + Book bookLol = new Book("Lol", new BigDecimal(69)); + Book bookKek = new Book("Kek", new BigDecimal(1488)); + service.createBook(bookHarry); + service.createBook(bookPotter); + service.createBook(bookLol); + service.createBook(bookKek); + } + + private static void testFindAll() { + System.out.println("\nFIND ALL"); + for (var book : service.findAllBooks()) { + System.out.println(book); + } + } + + private static void testFindById() { + System.out.println("\nFIND BY ID"); + System.out.println(service.findBookById(3L)); + } + + private static void testDelete() { + System.out.println("\nDELETE"); + service.deleteBookById(4L); + } + private static void testUpdate() { + System.out.println("\nUPDATE"); + Book bookForUpdate = new Book(3L, "Update", new BigDecimal(12345)); + service.updateBook(bookForUpdate); } } diff --git a/src/main/java/mate/academy/dao/BookDao.java b/src/main/java/mate/academy/dao/BookDao.java new file mode 100644 index 00000000..3be54f9e --- /dev/null +++ b/src/main/java/mate/academy/dao/BookDao.java @@ -0,0 +1,19 @@ +package mate.academy.dao; + +import java.util.List; +import java.util.Optional; +import mate.academy.model.Book; + +public interface BookDao { + Book create(Book book); + + Optional findById(Long id); + + List findAll(); + + Book update(Book book); + + boolean deleteById(Long id); + + boolean deleteAll(); +} diff --git a/src/main/java/mate/academy/dao/BookDaoImpl.java b/src/main/java/mate/academy/dao/BookDaoImpl.java new file mode 100644 index 00000000..acf9c8d8 --- /dev/null +++ b/src/main/java/mate/academy/dao/BookDaoImpl.java @@ -0,0 +1,141 @@ +package mate.academy.dao; + +import java.math.BigDecimal; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import mate.academy.ConnectionUtil; +import mate.academy.exception.DataProcessingException; +import mate.academy.lib.Dao; +import mate.academy.model.Book; + +@Dao +public class BookDaoImpl implements BookDao { + @Override + public Book create(Book book) { + String sql = "INSERT INTO book_db.books (title, price) VALUES (?, ?)"; + try (Connection connection = ConnectionUtil.getConnection(); + PreparedStatement statement = connection.prepareStatement(sql, + Statement.RETURN_GENERATED_KEYS)) { + + statement.setString(1, book.getTitle()); + statement.setBigDecimal(2, book.getPrice()); + + int affectedRows = statement.executeUpdate(); + if (affectedRows < 1) { + throw new DataProcessingException("expected insert at least 1 row, but was 0.", + new RuntimeException()); + } + + ResultSet generatedKeys = statement.getGeneratedKeys(); + if (generatedKeys.next()) { + Long id = generatedKeys.getObject(1, Long.class); + book.setId(id); + } + } catch (SQLException e) { + throw new DataProcessingException("can not add new book: " + book, e); + } + return book; + } + + @Override + public Optional findById(Long id) { + String sql = "SELECT * FROM book_db.books WHERE id = ?"; + try (Connection connection = ConnectionUtil.getConnection(); + PreparedStatement statement = connection.prepareStatement(sql)) { + + statement.setLong(1, id); + ResultSet resultSet = statement.executeQuery(); + + if (resultSet.next()) { + String title = resultSet.getString("title"); + BigDecimal price = resultSet.getBigDecimal("price"); + + Book book = new Book(id, title, price); + return Optional.of(book); + } + } catch (SQLException e) { + throw new DataProcessingException("can not find book by id : " + id, e); + } + return Optional.empty(); + } + + @Override + public List findAll() { + String sql = "SELECT * FROM book_db.books"; + try (Connection connection = ConnectionUtil.getConnection(); + PreparedStatement statement = connection.prepareStatement(sql)) { + ResultSet resultSet = statement.executeQuery(); + List books = new ArrayList<>(); + + while (resultSet.next()) { + Long id = resultSet.getObject("id", Long.class); + String title = resultSet.getString("title"); + BigDecimal price = resultSet.getObject("price", BigDecimal.class); + + Book book = new Book(id, title, price); + books.add(book); + } + + return books; + } catch (SQLException e) { + throw new DataProcessingException("Can not find all books", e); + } + } + + @Override + public Book update(Book book) { + String sql = "UPDATE book_db.books SET title = ?, price = ? WHERE id = ?"; + + try (Connection connection = ConnectionUtil.getConnection(); + PreparedStatement statement = connection.prepareStatement(sql)) { + + statement.setString(1, book.getTitle()); + statement.setBigDecimal(2, book.getPrice()); + statement.setLong(3, book.getId()); + + int rowsAffected = statement.executeUpdate(); + System.out.println("Rows updated: " + rowsAffected); + return book; + } catch (SQLException e) { + throw new DataProcessingException("Can not find all books", e); + } + } + + @Override + public boolean deleteById(Long id) { + String sql = "DELETE FROM book_db.books WHERE id = ?"; + + try (Connection connection = ConnectionUtil.getConnection(); + PreparedStatement statement = connection.prepareStatement(sql)) { + + statement.setLong(1, id); + + int rowsAffected = statement.executeUpdate(); + System.out.println("Rows deleted: " + rowsAffected); + return rowsAffected > 0; + } catch (SQLException e) { + throw new DataProcessingException("Can not find all books", e); + } + } + + @Override + public boolean deleteAll() { + String sql = "DELETE FROM book_db.books"; + + try (Connection connection = ConnectionUtil.getConnection(); + PreparedStatement statement = connection.prepareStatement(sql)) { + + int rowsAffected = statement.executeUpdate(); + System.out.println("Deleted " + rowsAffected + " rows from table books"); + return rowsAffected > 0; + } catch (SQLException e) { + throw new DataProcessingException("Can not delete all books", e); + } + } +} diff --git a/src/main/java/mate/academy/exception/DataProcessingException.java b/src/main/java/mate/academy/exception/DataProcessingException.java new file mode 100644 index 00000000..de9b45dc --- /dev/null +++ b/src/main/java/mate/academy/exception/DataProcessingException.java @@ -0,0 +1,7 @@ +package mate.academy.exception; + +public class DataProcessingException extends RuntimeException { + public DataProcessingException(String message, Throwable ex) { + super(message, ex); + } +} diff --git a/src/main/java/mate/academy/model/Book.java b/src/main/java/mate/academy/model/Book.java new file mode 100644 index 00000000..3dc033b5 --- /dev/null +++ b/src/main/java/mate/academy/model/Book.java @@ -0,0 +1,54 @@ +package mate.academy.model; + +import java.math.BigDecimal; + +public class Book { + private Long id; + private String title; + private BigDecimal price; + + public Book(Long id, String title, BigDecimal price) { + this.id = id; + this.title = title; + this.price = price; + } + + public Book(String title, BigDecimal price) { + this.title = title; + this.price = price; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public BigDecimal getPrice() { + return price; + } + + public void setPrice(BigDecimal price) { + this.price = price; + } + + @Override + public String toString() { + return "Book{" + + "id=" + id + + ", title='" + title + + ", price=" + price + + '}'; + } +} + diff --git a/src/main/java/mate/academy/service/BookService.java b/src/main/java/mate/academy/service/BookService.java new file mode 100644 index 00000000..b6950c1d --- /dev/null +++ b/src/main/java/mate/academy/service/BookService.java @@ -0,0 +1,19 @@ +package mate.academy.service; + +import java.util.List; +import java.util.Optional; +import mate.academy.model.Book; + +public interface BookService { + Book createBook(Book book); + + Optional findBookById(Long id); + + List findAllBooks(); + + Book updateBook(Book book); + + boolean deleteBookById(Long id); + + boolean deleteAll(); +} diff --git a/src/main/java/mate/academy/service/BookServiceImpl.java b/src/main/java/mate/academy/service/BookServiceImpl.java new file mode 100644 index 00000000..aa135a78 --- /dev/null +++ b/src/main/java/mate/academy/service/BookServiceImpl.java @@ -0,0 +1,44 @@ +package mate.academy.service; + +import java.util.List; +import java.util.Optional; +import mate.academy.dao.BookDao; +import mate.academy.model.Book; + +public class BookServiceImpl implements BookService { + private final BookDao bookDao; + + public BookServiceImpl(BookDao bookDao) { + this.bookDao = bookDao; + } + + @Override + public Book createBook(Book book) { + return bookDao.create(book); + } + + @Override + public Optional findBookById(Long id) { + return bookDao.findById(id); + } + + @Override + public List findAllBooks() { + return bookDao.findAll(); + } + + @Override + public Book updateBook(Book book) { + return bookDao.update(book); + } + + @Override + public boolean deleteBookById(Long id) { + return bookDao.deleteById(id); + } + + @Override + public boolean deleteAll() { + return bookDao.deleteAll(); + } +} diff --git a/src/main/resources/init_db.sql b/src/main/resources/init_db.sql new file mode 100644 index 00000000..114b3980 --- /dev/null +++ b/src/main/resources/init_db.sql @@ -0,0 +1,7 @@ +CREATE DATABASE book_db; +USE book_db; +CREATE TABLE books ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + title VARCHAR(50), + price BIGINT +); From 09d6d1dc86d32b1591b30109f585d07427c5a3ce Mon Sep 17 00:00:00 2001 From: Yurii Soliar Date: Sat, 25 May 2024 10:09:00 +0300 Subject: [PATCH 2/4] refactor duplicate code --- .../java/mate/academy/dao/BookDaoImpl.java | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/main/java/mate/academy/dao/BookDaoImpl.java b/src/main/java/mate/academy/dao/BookDaoImpl.java index acf9c8d8..260866ff 100644 --- a/src/main/java/mate/academy/dao/BookDaoImpl.java +++ b/src/main/java/mate/academy/dao/BookDaoImpl.java @@ -53,11 +53,7 @@ public Optional findById(Long id) { ResultSet resultSet = statement.executeQuery(); if (resultSet.next()) { - String title = resultSet.getString("title"); - BigDecimal price = resultSet.getBigDecimal("price"); - - Book book = new Book(id, title, price); - return Optional.of(book); + return Optional.of(mapToBook(resultSet)); } } catch (SQLException e) { throw new DataProcessingException("can not find book by id : " + id, e); @@ -74,12 +70,7 @@ public List findAll() { List books = new ArrayList<>(); while (resultSet.next()) { - Long id = resultSet.getObject("id", Long.class); - String title = resultSet.getString("title"); - BigDecimal price = resultSet.getObject("price", BigDecimal.class); - - Book book = new Book(id, title, price); - books.add(book); + books.add(mapToBook(resultSet)); } return books; @@ -138,4 +129,11 @@ public boolean deleteAll() { throw new DataProcessingException("Can not delete all books", e); } } + + private Book mapToBook(ResultSet resultSet) throws SQLException { + Long id = resultSet.getObject("id", Long.class); + String title = resultSet.getString("title"); + BigDecimal price = resultSet.getObject("price", BigDecimal.class); + return new Book(id, title, price); + } } From 86c305628cda4c03d15522eabae39269ca7c40e5 Mon Sep 17 00:00:00 2001 From: Yurii Soliar Date: Sat, 25 May 2024 13:18:20 +0300 Subject: [PATCH 3/4] rewrite exception messages, optimise return statements --- src/main/java/mate/academy/Main.java | 49 +++++-------------- .../java/mate/academy/dao/BookDaoImpl.java | 19 +++---- .../academy/{ => util}/ConnectionUtil.java | 2 +- 3 files changed, 20 insertions(+), 50 deletions(-) rename src/main/java/mate/academy/{ => util}/ConnectionUtil.java (96%) diff --git a/src/main/java/mate/academy/Main.java b/src/main/java/mate/academy/Main.java index eabb0e95..6574c84d 100644 --- a/src/main/java/mate/academy/Main.java +++ b/src/main/java/mate/academy/Main.java @@ -1,6 +1,8 @@ package mate.academy; import java.math.BigDecimal; +import java.util.List; +import java.util.stream.Collectors; import mate.academy.dao.BookDao; import mate.academy.lib.Injector; import mate.academy.model.Book; @@ -15,48 +17,23 @@ public static void main(String[] args) { BookDao bookDao = (BookDao) injector.getInstance(BookDao.class); service = new BookServiceImpl(bookDao); - testCreate(); - testFindAll(); - testFindById(); - testUpdate(); - testDelete(); - testFindAll(); + List books = List.of( + new Book("Harry", new BigDecimal(1222)), + new Book("Potter", new BigDecimal(999)), + new Book("Lol", new BigDecimal(69)), + new Book("Kek", new BigDecimal(1488))); - service.deleteAll(); - } + books.stream().map(book -> service.createBook((Book) book)).collect(Collectors.toList()); - private static void testCreate() { - System.out.println("\nCREATE"); - Book bookHarry = new Book("Harry", new BigDecimal(1222)); - Book bookPotter = new Book("Potter", new BigDecimal(999)); - Book bookLol = new Book("Lol", new BigDecimal(69)); - Book bookKek = new Book("Kek", new BigDecimal(1488)); - service.createBook(bookHarry); - service.createBook(bookPotter); - service.createBook(bookLol); - service.createBook(bookKek); - } + service.findAllBooks().forEach(System.out::println); - private static void testFindAll() { - System.out.println("\nFIND ALL"); - for (var book : service.findAllBooks()) { - System.out.println(book); - } - } - - private static void testFindById() { - System.out.println("\nFIND BY ID"); System.out.println(service.findBookById(3L)); - } - private static void testDelete() { - System.out.println("\nDELETE"); - service.deleteBookById(4L); - } - - private static void testUpdate() { - System.out.println("\nUPDATE"); Book bookForUpdate = new Book(3L, "Update", new BigDecimal(12345)); service.updateBook(bookForUpdate); + + service.deleteBookById(4L); + + service.deleteAll(); } } diff --git a/src/main/java/mate/academy/dao/BookDaoImpl.java b/src/main/java/mate/academy/dao/BookDaoImpl.java index 260866ff..ab751d4c 100644 --- a/src/main/java/mate/academy/dao/BookDaoImpl.java +++ b/src/main/java/mate/academy/dao/BookDaoImpl.java @@ -9,10 +9,10 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; -import mate.academy.ConnectionUtil; import mate.academy.exception.DataProcessingException; import mate.academy.lib.Dao; import mate.academy.model.Book; +import mate.academy.util.ConnectionUtil; @Dao public class BookDaoImpl implements BookDao { @@ -38,7 +38,7 @@ public Book create(Book book) { book.setId(id); } } catch (SQLException e) { - throw new DataProcessingException("can not add new book: " + book, e); + throw new DataProcessingException("can not create new book: " + book.toString(), e); } return book; } @@ -94,7 +94,7 @@ public Book update(Book book) { System.out.println("Rows updated: " + rowsAffected); return book; } catch (SQLException e) { - throw new DataProcessingException("Can not find all books", e); + throw new DataProcessingException("Can not update book " + book.toString(), e); } } @@ -104,14 +104,10 @@ public boolean deleteById(Long id) { try (Connection connection = ConnectionUtil.getConnection(); PreparedStatement statement = connection.prepareStatement(sql)) { - statement.setLong(1, id); - - int rowsAffected = statement.executeUpdate(); - System.out.println("Rows deleted: " + rowsAffected); - return rowsAffected > 0; + return statement.executeUpdate() > 0; } catch (SQLException e) { - throw new DataProcessingException("Can not find all books", e); + throw new DataProcessingException("Can not delete book with id " + id, e); } } @@ -121,10 +117,7 @@ public boolean deleteAll() { try (Connection connection = ConnectionUtil.getConnection(); PreparedStatement statement = connection.prepareStatement(sql)) { - - int rowsAffected = statement.executeUpdate(); - System.out.println("Deleted " + rowsAffected + " rows from table books"); - return rowsAffected > 0; + return statement.executeUpdate() > 0; } catch (SQLException e) { throw new DataProcessingException("Can not delete all books", e); } diff --git a/src/main/java/mate/academy/ConnectionUtil.java b/src/main/java/mate/academy/util/ConnectionUtil.java similarity index 96% rename from src/main/java/mate/academy/ConnectionUtil.java rename to src/main/java/mate/academy/util/ConnectionUtil.java index d17dc2c9..4a12f059 100644 --- a/src/main/java/mate/academy/ConnectionUtil.java +++ b/src/main/java/mate/academy/util/ConnectionUtil.java @@ -1,4 +1,4 @@ -package mate.academy; +package mate.academy.util; import java.sql.Connection; import java.sql.DriverManager; From 4413a8eab37783d71f6dfe315463180cf5975db4 Mon Sep 17 00:00:00 2001 From: Yurii Soliar Date: Sun, 26 May 2024 08:01:29 +0300 Subject: [PATCH 4/4] fix update method --- src/main/java/mate/academy/Main.java | 6 +++--- src/main/java/mate/academy/dao/BookDaoImpl.java | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/mate/academy/Main.java b/src/main/java/mate/academy/Main.java index 6574c84d..8efd54d9 100644 --- a/src/main/java/mate/academy/Main.java +++ b/src/main/java/mate/academy/Main.java @@ -27,12 +27,12 @@ public static void main(String[] args) { service.findAllBooks().forEach(System.out::println); - System.out.println(service.findBookById(3L)); + System.out.println(service.findBookById(49L)); - Book bookForUpdate = new Book(3L, "Update", new BigDecimal(12345)); + Book bookForUpdate = new Book(49L, "Update", new BigDecimal(12345)); service.updateBook(bookForUpdate); - service.deleteBookById(4L); + service.deleteBookById(48L); service.deleteAll(); } diff --git a/src/main/java/mate/academy/dao/BookDaoImpl.java b/src/main/java/mate/academy/dao/BookDaoImpl.java index ab751d4c..5ccff9a8 100644 --- a/src/main/java/mate/academy/dao/BookDaoImpl.java +++ b/src/main/java/mate/academy/dao/BookDaoImpl.java @@ -90,8 +90,10 @@ public Book update(Book book) { statement.setBigDecimal(2, book.getPrice()); statement.setLong(3, book.getId()); - int rowsAffected = statement.executeUpdate(); - System.out.println("Rows updated: " + rowsAffected); + if (statement.executeUpdate() < 1) { + throw new DataProcessingException("Book " + book.toString() + " was not updated", + new RuntimeException()); + } return book; } catch (SQLException e) { throw new DataProcessingException("Can not update book " + book.toString(), e);