diff --git a/pom.xml b/pom.xml
index 683e84ec..2af7ddfd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -17,6 +17,13 @@
https://raw.githubusercontent.com/mate-academy/style-guides/master/java/checkstyle.xml
+
+
+ com.mysql
+ mysql-connector-j
+ 8.3.0
+
+
diff --git a/src/main/java/mate/academy/Main.java b/src/main/java/mate/academy/Main.java
index 0058fbf9..44b6697a 100644
--- a/src/main/java/mate/academy/Main.java
+++ b/src/main/java/mate/academy/Main.java
@@ -1,7 +1,38 @@
package mate.academy;
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Optional;
+import mate.academy.bookdao.BookDao;
+import mate.academy.lib.Injector;
+import mate.academy.model.Book;
+
public class Main {
+ private static final Injector injector = Injector.getInstance("mate.academy");
+
public static void main(String[] args) {
+ BookDao bookDao = (BookDao) injector.getInstance(BookDao.class);
+ Book firstBook = Book.of("Effective Java", new BigDecimal(700));
+ Book secondBook = Book.of("Clean Code", new BigDecimal(900));
+ Book thirdBook = Book.of("Head of Java", new BigDecimal(600));
+
+ bookDao.create(firstBook);
+ bookDao.create(secondBook);
+ bookDao.create(thirdBook);
+
+ List booksFromDb = bookDao.findAll();
+ System.out.println(booksFromDb);
+
+ Optional bookById = bookDao.findById(3L);
+ bookById.ifPresent(System.out::println);
+
+ Book book = Book.of(3L, "Harry Potter", new BigDecimal(1000));
+ Book updated = bookDao.update(book);
+ System.out.println(updated);
+
+ bookDao.findById(3L).ifPresent(System.out::println);
+ boolean isBookDeleted = bookDao.deleteById(3L);
+ System.out.println(isBookDeleted);
}
}
diff --git a/src/main/java/mate/academy/bookdao/BookDao.java b/src/main/java/mate/academy/bookdao/BookDao.java
new file mode 100644
index 00000000..158e2c0d
--- /dev/null
+++ b/src/main/java/mate/academy/bookdao/BookDao.java
@@ -0,0 +1,18 @@
+package mate.academy.bookdao;
+
+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);
+}
diff --git a/src/main/java/mate/academy/bookdao/BookDaoImpl.java b/src/main/java/mate/academy/bookdao/BookDaoImpl.java
new file mode 100644
index 00000000..ca24eda2
--- /dev/null
+++ b/src/main/java/mate/academy/bookdao/BookDaoImpl.java
@@ -0,0 +1,122 @@
+package mate.academy.bookdao;
+
+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.dbconnection.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 books(title, price) VALUES(?, ?)";
+ try (Connection connection = ConnectionUtil.getConnection();
+ PreparedStatement preparedStatement = connection
+ .prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
+ if (storeBook(preparedStatement, book, false)) {
+ throw new RuntimeException("Book could not be created");
+ }
+ ResultSet generatedKeys = preparedStatement.getGeneratedKeys();
+ if (generatedKeys.next()) {
+ Long id = generatedKeys.getObject(1, Long.class);
+ book.setId(id);
+ }
+ } catch (SQLException e) {
+ throw new DataProcessingException("Can't add a book " + 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(mapToBook(resultSet));
+ }
+ } catch (SQLException e) {
+ throw new DataProcessingException("Can't get book by id " + id, e);
+ }
+ return Optional.empty();
+ }
+
+ @Override
+ public List findAll() {
+ String sql = "SELECT * FROM books";
+ List books = new ArrayList<>();
+ try (Connection connection = ConnectionUtil.getConnection();
+ Statement statement = connection.createStatement();
+ ResultSet resultSet = statement.executeQuery(sql)) {
+ while (resultSet.next()) {
+ books.add(mapToBook(resultSet));
+ }
+ } catch (SQLException e) {
+ throw new DataProcessingException("Can't get all books", e);
+ }
+ return books;
+ }
+
+ @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)) {
+ if (storeBook(preparedStatement, book, true)) {
+ throw new RuntimeException("Book not found");
+ }
+ } catch (SQLException e) {
+ throw new DataProcessingException("Can't update book " + book.getTitle(), e);
+ }
+ return book;
+ }
+
+ @Override
+ public boolean deleteById(Long id) {
+ String sql = "DELETE FROM books WHERE id = ?";
+ try (Connection connection = ConnectionUtil.getConnection();
+ PreparedStatement statement = connection.prepareStatement(sql)) {
+ statement.setLong(1, id);
+ int affectedRow = statement.executeUpdate();
+ if (affectedRow < 1) {
+ throw new RuntimeException("Book not found by id " + id);
+ }
+ } catch (SQLException e) {
+ throw new DataProcessingException("Can't delete book by " + id, e);
+ }
+ return true;
+ }
+
+ private Book mapToBook(ResultSet resultSet) throws SQLException {
+ Long id = resultSet.getLong("id");
+ String title = resultSet.getString("title");
+ BigDecimal price = resultSet.getBigDecimal("price");
+ return Book.of(id, title, price);
+ }
+
+ private boolean storeBook(PreparedStatement preparedStatement,
+ Book book, boolean idPresent) throws SQLException {
+ if (idPresent) {
+ preparedStatement.setString(1, book.getTitle());
+ preparedStatement.setBigDecimal(2, book.getPrice());
+ preparedStatement.setLong(3, book.getId());
+ return preparedStatement.executeUpdate() < 1;
+ }
+ preparedStatement.setString(1, book.getTitle());
+ preparedStatement.setBigDecimal(2, book.getPrice());
+ return preparedStatement.executeUpdate() < 1;
+ }
+}
diff --git a/src/main/java/mate/academy/dbconnection/ConnectionUtil.java b/src/main/java/mate/academy/dbconnection/ConnectionUtil.java
new file mode 100644
index 00000000..ebea8c28
--- /dev/null
+++ b/src/main/java/mate/academy/dbconnection/ConnectionUtil.java
@@ -0,0 +1,27 @@
+package mate.academy.dbconnection;
+
+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";
+ private static final Properties DB_PROPERTIES;
+
+ static {
+ DB_PROPERTIES = new Properties();
+ DB_PROPERTIES.put("user", "root");
+ DB_PROPERTIES.put("password", "databasepractice1!");
+
+ try {
+ Class.forName("com.mysql.cj.jdbc.Driver");
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException("Can't load a JDBC driver!", e);
+ }
+ }
+
+ public static Connection getConnection() throws SQLException {
+ return DriverManager.getConnection(DB_URL, DB_PROPERTIES);
+ }
+}
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..63b937dc
--- /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 cause) {
+ super(message, cause);
+ }
+}
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..f3380f0f
--- /dev/null
+++ b/src/main/java/mate/academy/model/Book.java
@@ -0,0 +1,65 @@
+package mate.academy.model;
+
+import java.math.BigDecimal;
+
+public class Book {
+ private Long id;
+ private String title;
+ private BigDecimal price;
+
+ private Book(Long id, String title, BigDecimal price) {
+ this.id = id;
+ this.title = title;
+ this.price = price;
+ }
+
+ private Book(String title, BigDecimal price) {
+ this.title = title;
+ this.price = price;
+ }
+
+ public static Book of(Long id, String title, BigDecimal price) {
+ return new Book(id, title, price);
+ }
+
+ public static Book of(String title, BigDecimal price) {
+ return new Book(title, price);
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public void setPrice(BigDecimal price) {
+ this.price = price;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public BigDecimal getPrice() {
+ return 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..adf7fe11
--- /dev/null
+++ b/src/main/resources/init_db.sql
@@ -0,0 +1,6 @@
+CREATE TABLE books
+(
+ id BIGINT PRIMARY KEY AUTO_INCREMENT,
+ title VARCHAR(100) NOT NULL,
+ price DECIMAL NOT NULL
+);
\ No newline at end of file