-
Notifications
You must be signed in to change notification settings - Fork 438
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
created UtilConnection; #398
base: main
Are you sure you want to change the base?
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,7 @@ | |
* Try to avoid code duplication. Especially, when you are working with ResultSet. | ||
Move retrieving data from ResultSet into Entity object to a separate private method. | ||
|
||
* Don't make `books.title` UNIQUE. This is not required in this task. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. revert file There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. title doesn`t unique There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please, revert changes in checklist file. If you have some questions please ask in chat |
||
* Don't make `book.title` UNIQUE. This is not required in this task. | ||
|
||
* When creating a table in MySQL, use `bigint` column type for storing id. | ||
|
||
|
@@ -12,11 +12,11 @@ | |
|
||
* Use `PreparedStatement` over `Statement`, even for a static query with no parameters in `findAll()` method. It's the best practice, and it's slightly faster. | ||
|
||
* Column naming (`books.` is a table name in these examples): | ||
* Column naming (`book.` is a table name in these examples): | ||
|
||
Wrong: `books.bookTitle`, `books.BOOK_TITLE` | ||
Wrong: `book.bookTitle`, `book.BOOK_TITLE` | ||
|
||
Good: `books.title` | ||
Good: `book.title` | ||
|
||
* Use `Statement.RETURN_GENERATED_KEYS` only in `create` statement, it's not needed in other methods. | ||
|
||
|
@@ -48,19 +48,19 @@ Good: `books.title` | |
|
||
- Bad practice: | ||
```sql | ||
insert into books (..) VALUES (..); | ||
insert into book (..) VALUES (..); | ||
``` | ||
- Good practice: | ||
```sql | ||
INSERT INTO books (..) VALUES (..); | ||
INSERT INTO book (..) VALUES (..); | ||
``` | ||
* Let's save each query in a separate variable. | ||
- Bad practice: | ||
```java | ||
public List<Book> findAll() { | ||
try (Connection connection = ConnectionUtil.getConnection() | ||
PreparedStatement preparedStatement = connection | ||
.prepareStatement("SELECT * FROM books")) { // it's bad | ||
.prepareStatement("SELECT * FROM book")) { // it's bad | ||
... | ||
} catch (SQLException ex) { | ||
... | ||
|
@@ -70,7 +70,7 @@ Good: `books.title` | |
- Good practice: | ||
```java | ||
public List<Book> findAll() { | ||
String query = "SELECT * FROM books"; // it's good | ||
String query = "SELECT * FROM book"; // it's good | ||
try (Connection connection = ConnectionUtil.getConnection(); | ||
PreparedStatement preparedStatement = connection.prepareStatement(query)) { | ||
... | ||
|
@@ -105,11 +105,11 @@ Good: `books.title` | |
|
||
- Bad practice: | ||
```sql | ||
SELECT * FROM schemaname.books WHERE id = 1; | ||
SELECT * FROM schemaname.book WHERE id = 1; | ||
``` | ||
- Good practice: | ||
```sql | ||
SELECT * FROM books WHERE id = 1; | ||
SELECT * FROM book WHERE id = 1; | ||
``` | ||
* When you convert `ResultSet` to `Book` better create an object using setters or constructor but not both of them, because it's not consistent to use both ways of initialization of object. | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,29 @@ | ||
package mate.academy; | ||
|
||
import java.math.BigDecimal; | ||
import java.util.List; | ||
import mate.academy.dao.BookDao; | ||
import mate.academy.entity.Book; | ||
import mate.academy.lib.Injector; | ||
|
||
public class Main { | ||
public static void main(String[] args) { | ||
private static final Injector injector = Injector.getInstance("mate.academy.dao"); | ||
|
||
public static void main(String[] args) { | ||
BookDao bookDao = (BookDao) injector.getInstance(BookDao.class); | ||
List<Book> books = List.of(new Book("First Book", BigDecimal.valueOf(45)), | ||
new Book("Second Book", BigDecimal.valueOf(12)), | ||
new Book("Third Book", BigDecimal.valueOf(26))); | ||
for (Book book : books) { | ||
bookDao.create(book); | ||
} | ||
bookDao.findById(1L); | ||
System.out.println(bookDao.findAll()); | ||
Book book = new Book(); | ||
book.setId(43L); | ||
book.setTitle("Update First Book"); | ||
book.setPrice(BigDecimal.valueOf(45)); | ||
bookDao.update(book); | ||
bookDao.deleteById(43L); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package mate.academy.dao; | ||
|
||
import java.util.List; | ||
import java.util.Optional; | ||
import mate.academy.entity.Book; | ||
|
||
public interface BookDao { | ||
Book create(Book book); | ||
|
||
Optional<Book> findById(Long id); | ||
|
||
List<Book> findAll(); | ||
|
||
Book update(Book book); | ||
|
||
boolean deleteById(Long id); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
package mate.academy.dao; | ||
|
||
import java.sql.Connection; | ||
import java.sql.PreparedStatement; | ||
import java.sql.ResultSet; | ||
import java.sql.SQLException; | ||
import java.sql.Statement; | ||
import java.sql.Types; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Optional; | ||
import mate.academy.entity.Book; | ||
import mate.academy.exception.DataProcessingException; | ||
import mate.academy.lib.Dao; | ||
import mate.academy.util.ConnectionUtil; | ||
|
||
@Dao | ||
public class BookDaoImpl implements BookDao { | ||
private static final String CREATE_SQL = "INSERT INTO book (title, price) VALUES (?, ?)"; | ||
private static final String FIND_BY_ID_SQL = "SELECT * FROM book WHERE id = ?"; | ||
private static final String FIND_ALL_SQL = "SELECT * FROM book"; | ||
private static final String UPDATE_BY_ID_SQL = "UPDATE book SET title = ?, " | ||
+ "price = ? WHERE id = ?"; | ||
private static final String DELETE_BY_ID_SQL = "DELETE FROM book WHERE id = ?"; | ||
|
||
@Override | ||
public Book create(Book book) { | ||
try (Connection connection = ConnectionUtil.getConnection(); | ||
PreparedStatement statement = connection | ||
.prepareStatement(CREATE_SQL, Statement.RETURN_GENERATED_KEYS)) { | ||
statement.setString(1, book.getTitle()); | ||
statement.setBigDecimal(2, book.getPrice()); | ||
int rowsAffected = statement.executeUpdate(); | ||
if (rowsAffected < 1) { | ||
throw new DataProcessingException("At least one row was expected to be affected, " | ||
+ "but 0 rows were affected"); | ||
} | ||
ResultSet generatedKeys = statement.getGeneratedKeys(); | ||
if (generatedKeys.next()) { | ||
book.setId(generatedKeys.getLong(1)); | ||
} | ||
} catch (SQLException e) { | ||
throw new DataProcessingException("An error occurred while creating the book", e); | ||
} | ||
return book; | ||
} | ||
|
||
@Override | ||
public Optional<Book> findById(Long id) { | ||
Book book = new Book(); | ||
try (Connection connection = ConnectionUtil.getConnection(); | ||
PreparedStatement statement = connection | ||
.prepareStatement(FIND_BY_ID_SQL)) { | ||
statement.setObject(1, id, Types.BIGINT); | ||
ResultSet resultSet = statement.executeQuery(); | ||
if (resultSet.next()) { | ||
book = mapResultSet(resultSet); | ||
} | ||
} catch (SQLException e) { | ||
throw new DataProcessingException("Could not find book with id: " + id, e); | ||
} | ||
return Optional.of(book); | ||
} | ||
|
||
@Override | ||
public List<Book> findAll() { | ||
try (Connection connection = ConnectionUtil.getConnection(); | ||
PreparedStatement statement = connection.prepareStatement(FIND_ALL_SQL)) { | ||
List<Book> books = new ArrayList<>(); | ||
ResultSet resultSet = statement.executeQuery(); | ||
while (resultSet.next()) { | ||
Book book = mapResultSet(resultSet); | ||
books.add(book); | ||
} | ||
return books; | ||
} catch (SQLException e) { | ||
throw new DataProcessingException("Could not find all book", e); | ||
} | ||
} | ||
|
||
@Override | ||
public Book update(Book book) { | ||
try (Connection connection = ConnectionUtil.getConnection(); | ||
PreparedStatement statement = connection.prepareStatement(UPDATE_BY_ID_SQL)) { | ||
statement.setObject(1, book.getTitle(), Types.VARCHAR); | ||
statement.setObject(2, book.getPrice(), Types.DECIMAL); | ||
statement.setObject(3, book.getId(), Types.BIGINT); | ||
|
||
int rowsAffected = statement.executeUpdate(); | ||
if (rowsAffected < 1) { | ||
throw new DataProcessingException("At least one row was expected to be affected, " | ||
+ "but 0 rows were affected"); | ||
} | ||
} catch (SQLException e) { | ||
throw new DataProcessingException("An error occurred while updating the book", e); | ||
} | ||
return book; | ||
} | ||
|
||
@Override | ||
public boolean deleteById(Long id) { | ||
try (Connection connection = ConnectionUtil.getConnection(); | ||
PreparedStatement statement = connection.prepareStatement(DELETE_BY_ID_SQL)) { | ||
statement.setObject(1, id, Types.BIGINT); | ||
return statement.executeUpdate() > 0; | ||
} catch (SQLException e) { | ||
throw new DataProcessingException("An error occurred while deleting the book", e); | ||
} | ||
} | ||
|
||
private Book mapResultSet(ResultSet resultSet) throws SQLException { | ||
Book book = new Book(); | ||
book.setId(resultSet.getLong("id")); | ||
book.setTitle(resultSet.getString("title")); | ||
book.setPrice(resultSet.getBigDecimal("price")); | ||
return book; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package mate.academy.entity; | ||
|
||
import java.math.BigDecimal; | ||
|
||
public class Book { | ||
private Long id; | ||
private String title; | ||
private BigDecimal price; | ||
|
||
public Book() { | ||
} | ||
|
||
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 | ||
+ '}'; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package mate.academy.exception; | ||
|
||
public class DataProcessingException extends RuntimeException { | ||
public DataProcessingException(String cause, Throwable e) { | ||
super(cause, e); | ||
} | ||
|
||
public DataProcessingException(String cause) { | ||
super(cause); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package mate.academy.util; | ||
|
||
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/books"; | ||
private static final Properties DB_PROPERTIES; | ||
|
||
static { | ||
DB_PROPERTIES = new Properties(); | ||
DB_PROPERTIES.put("user", "root"); | ||
DB_PROPERTIES.put("password", "6855"); | ||
|
||
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); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,5 @@ | ||||||
CREATE TABLE book ( | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
id BIGINT AUTO_INCREMENT PRIMARY KEY, | ||||||
title VARCHAR(255), | ||||||
price DECIMAL | ||||||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
revert
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but i have table dook with columns: id, title and price
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
according to the naming convention, table in DB should be plural