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..8e76ca7e --- /dev/null +++ b/src/main/java/mate/academy/ConnectionUtil.java @@ -0,0 +1,25 @@ +package mate.academy; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.Properties; + +public class ConnectionUtil { + private static final String DB_URL = "jdbc:mysql://localhost:3306/test?serverTimezone=UTC"; + private static final Properties DB_PROPERTIES = new Properties(); + + static { + DB_PROPERTIES.put("user", "root"); + DB_PROPERTIES.put("password", "Root1234"); + try { + Class.forName("com.mysql.cj.jdbc.Driver"); + } catch (ClassNotFoundException e) { + throw new RuntimeException("Can't load JDBC driver", e); + } + } + + public static Connection getConnection() throws SQLException { + return DriverManager.getConnection(DB_URL, DB_PROPERTIES); + } +} diff --git a/src/main/java/mate/academy/Main.java b/src/main/java/mate/academy/Main.java index 0058fbf9..6fd78b60 100644 --- a/src/main/java/mate/academy/Main.java +++ b/src/main/java/mate/academy/Main.java @@ -1,7 +1,46 @@ package mate.academy; +import java.math.BigDecimal; +import java.util.List; +import mate.academy.dao.BookDao; +import mate.academy.lib.Injector; +import mate.academy.model.Book; + public class Main { + private static final Injector INJECTOR = Injector.getInstance("mate.academy.dao"); + public static void main(String[] args) { + BookDao bookDao = (BookDao) INJECTOR.getInstance(BookDao.class); + final Book book1 = new Book(); + final Book book2 = new Book(); + final Book book3 = new Book(); + final Book book4 = new Book(); + // initialize field values using setters or constructor + book1.setTitle("QWERTY"); + book1.setPrice(BigDecimal.valueOf(123)); + bookDao.create(book1); + book2.setTitle("title"); + book2.setPrice(BigDecimal.valueOf(456)); + bookDao.create(book2); + book3.setTitle("World"); + book3.setPrice(BigDecimal.valueOf(789)); + bookDao.create(book3); + book4.setTitle("Cat"); + book4.setPrice(BigDecimal.valueOf(543)); + bookDao.create(book4); + // test other methods from BookDao + List bookList = bookDao.findAll(); + bookList.forEach(System.out::println); + + System.out.println(); + + Book updatedBook = new Book(); + updatedBook.setId(bookList.get(0).getId()); + updatedBook.setTitle("Updated"); + updatedBook.setPrice(BigDecimal.valueOf(999)); + bookDao.update(updatedBook); + bookList.forEach(System.out::println); + bookList.forEach(book -> bookDao.deleteById(book.getId())); } } 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..77d01020 --- /dev/null +++ b/src/main/java/mate/academy/dao/BookDao.java @@ -0,0 +1,17 @@ +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) throws DataProcessingException; + + boolean deleteById(Long id); +} 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..60e44f7b --- /dev/null +++ b/src/main/java/mate/academy/dao/BookDaoImpl.java @@ -0,0 +1,119 @@ +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.lib.Dao; +import mate.academy.model.Book; + +@Dao +public class BookDaoImpl implements BookDao { + + @Override + public Book create(Book book) { + String sql = "INSERT INTO books (title, price) VALUES (?, ?)"; + try (Connection connection = ConnectionUtil.getConnection(); + PreparedStatement preparedStatement = connection.prepareStatement(sql, + Statement.RETURN_GENERATED_KEYS)) { + preparedStatement.setString(1, book.getTitle()); + preparedStatement.setBigDecimal(2, book.getPrice()); + int affectedRows = preparedStatement.executeUpdate(); + if (affectedRows < 1) { + throw new DataProcessingException("Expected at least 1 row but found 0"); + } + ResultSet generatedKeys = preparedStatement.getGeneratedKeys(); + if (generatedKeys.next()) { + Long id = generatedKeys.getObject(1, Long.class); + book.setId(id); + } + } catch (SQLException e) { + throw new DataProcessingException("Can not create book", e); + } + return book; + } + + @Override + public Optional findById(Long id) { + String sql = "SELECT * FROM books WHERE id = ?"; + try (Connection connection = ConnectionUtil.getConnection(); + PreparedStatement preparedStatement = connection.prepareStatement(sql)) { + preparedStatement.setLong(1, id); + ResultSet resultSet = preparedStatement.executeQuery(); + if (resultSet.next()) { + return Optional.of(extractBookFromResultSet(resultSet)); + } + } catch (SQLException e) { + throw new DataProcessingException("Can not find book by id", e); + } + return Optional.empty(); + } + + @Override + public List findAll() { + String sql = "SELECT * FROM books"; + try (Connection connection = ConnectionUtil.getConnection(); + PreparedStatement preparedStatement = connection.prepareStatement(sql)) { + ResultSet resultSet = preparedStatement.executeQuery(); + List books = new ArrayList<>(); + while (resultSet.next()) { + books.add(extractBookFromResultSet(resultSet)); + } + return books; + } catch (SQLException e) { + throw new DataProcessingException("Can not find book by id", e); + } + } + + @Override + public Book update(Book book) { + String sql = "UPDATE books SET title = ?, price = ? WHERE id = ?"; + try (Connection connection = ConnectionUtil.getConnection(); + PreparedStatement preparedStatement = connection.prepareStatement(sql)) { + preparedStatement.setString(1, book.getTitle()); + preparedStatement.setBigDecimal(2, book.getPrice()); + preparedStatement.setLong(3, book.getId()); + int affectedRows = preparedStatement.executeUpdate(); + if (affectedRows < 1) { + throw new DataProcessingException("Expected at least 1 row but found 0"); + } + } catch (SQLException e) { + throw new DataProcessingException("Can not update book", e); + } + return book; + } + + @Override + public boolean deleteById(Long id) { + String sql = "DELETE FROM books WHERE id = ?"; + try (Connection connection = ConnectionUtil.getConnection(); + PreparedStatement preparedStatement = connection.prepareStatement(sql)) { + Optional book = findById(id); + if (book.isEmpty()) { + return false; + } + preparedStatement.setLong(1, book.get().getId()); + preparedStatement.executeUpdate(); + } catch (SQLException e) { + throw new DataProcessingException("Can not delete book", e); + } + return true; + } + + private Book extractBookFromResultSet(ResultSet resultSet) throws SQLException { + Long id = resultSet.getObject("id", Long.class); + String title = resultSet.getString("title"); + BigDecimal price = resultSet.getBigDecimal("price"); + Book book = new Book(); + book.setId(id); + book.setTitle(title); + book.setPrice(price); + return book; + } +} diff --git a/src/main/java/mate/academy/dao/DataProcessingException.java b/src/main/java/mate/academy/dao/DataProcessingException.java new file mode 100644 index 00000000..04c278e3 --- /dev/null +++ b/src/main/java/mate/academy/dao/DataProcessingException.java @@ -0,0 +1,13 @@ +package mate.academy.dao; + +import java.sql.SQLException; + +public class DataProcessingException extends RuntimeException { + public DataProcessingException(String message, SQLException e) { + super(message); + } + + public DataProcessingException(String message) { + super(message); + } +} 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..e2cb4289 --- /dev/null +++ b/src/main/java/mate/academy/model/Book.java @@ -0,0 +1,42 @@ +package mate.academy.model; + +import java.math.BigDecimal; + +public class Book { + private Long id; + private String title; + private BigDecimal 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/resources/init_db.sql b/src/main/resources/init_db.sql new file mode 100644 index 00000000..9a370bbf --- /dev/null +++ b/src/main/resources/init_db.sql @@ -0,0 +1,5 @@ +CREATE TABLE IF NOT EXISTS books ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + title VARCHAR(255) NOT NULL, + price DECIMAL(10, 2) NOT NULL + ); \ No newline at end of file