Skip to content
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

hw is done, please check #420

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

Hero284
Copy link

@Hero284 Hero284 commented Sep 29, 2024

No description provided.

Copy link

@mateacademy-ai-mentor mateacademy-ai-mentor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like you've put in a solid effort on this project, and you're almost there! However, there are a few critical issues that need to be addressed before we can merge this Pull Request. The missing executeUpdate for the update operation and the incorrect use of RETURN_GENERATED_KEYS for SELECT queries are particularly important to fix, as they will affect the functionality of your application. Also, make sure to correct the exception messages to provide more accurate information, which is essential for debugging and maintenance. Keep up the good work, and with a few adjustments, your code will be ready to go! 👍💻

✨ Please rate this review in the Platform's notification center. I will be grateful for your feedback! ✨

import java.util.Properties;

public class ConnectionUtil {
private static final String DB_URL = "jdbc:mysql://localhost:3306/jdbc_intro";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The DB_URL string is not complete, it should contain the full JDBC URL, including the database server's IP, port, and the specific database name you want to connect to.

public class ConnectionUtil {
private static final String DB_URL = "jdbc:mysql://localhost:3306/jdbc_intro";
private static final String USERNAME = "root";
private static final String PASSWORD = "Nk102030!";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Storing passwords in source code is a security risk. Consider using environment variables or a configuration file for sensitive data.

public class BookDaoImpl implements BookDao {
@Override
public Book create(Book book) {
String sql = "INSERT INTO books (title, price) VALUES (?, ?)";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to the checklist, don't use schema's name in your queries. You should configure the schema while establishing a connection with the DB, so there is no need to specify it in the SQL query.

Comment on lines 30 to 32
if (affectedRows < 0) {
throw new DataProcessingException("Expected to insert at least one row,"
+ " but inserted 0 rows");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The executeUpdate method returns the number of rows affected by the query. It will return 0 if no rows were updated, not a negative number. You should check if affectedRows == 0 to determine if no rows were inserted.

Comment on lines 40 to 41
} catch (SQLException e) {
throw new DataProcessingException("Can' add a new book: " + book);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use more informative messages for exceptions. Include details like the book id when an exception occurs during insertion to help with debugging. For example: "Can't add a new book with id: " + book.getId().

statement.setString(1, book.getTitle());
statement.setBigDecimal(2, book.getPrice());
statement.setLong(3, book.getId());
return book;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're missing the statement.executeUpdate() call to actually perform the update operation on the database. Without it, the update will not be executed.

statement.setLong(3, book.getId());
return book;
} catch (SQLException e) {
throw new DataProcessingException("Can't update book: " + book);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a more informative exception message. Include the book id when an exception occurs during an update. For example: "Can't update the book with id: " + book.getId().

statement.setLong(1, id);
return statement.executeUpdate() > 0;
} catch (SQLException e) {
throw new DataProcessingException("Can't delete book");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a more informative exception message. Include the id of the book when an exception occurs during deletion. For example: "Can't delete the book with id: " + id.

Comment on lines 107 to 111
private Book getBookFromResultSet(ResultSet resultSet) throws SQLException {
Long id = resultSet.getLong("id");
String title = resultSet.getString("title");
BigDecimal price = resultSet.getBigDecimal("price");
return new Book(id, title, price);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's good practice to check if the values retrieved from the ResultSet are not null before using them to create a new object. Use resultSet.getObject for 'id' and check if it's not null before creating the Book object.

Comment on lines 34 to 37
public static Object getInstance(Class<?> certainInterface) {
Class<?> clazz = findClassExtendingInterface(certainInterface);
return createInstance(clazz);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method 'getInstance' is a bit misleading because it suggests that you can get an instance of any class, while it actually expects an interface that has an implementation marked with the @dao annotation. Consider renaming this method to reflect that it's specifically for getting Dao implementations, such as 'getDaoInstance'.

Copy link

@mateacademy-ai-mentor mateacademy-ai-mentor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there! It seems like we have a few areas to improve, especially with SQL style and exception handling. Let's make sure SQL keywords are in uppercase to follow the conventions, and work on catching specific exceptions rather than a generic one. Also, consider using PreparedStatement for all queries and refining the exception messages to be more informative. Keep up the good work, and with these changes, your code will be even better! 👍🛠️

✨ Please rate this review in the Platform's notification center. I will be grateful for your feedback! ✨

public class BookDaoImpl implements BookDao {
@Override
public Book create(Book book) {
String sql = "INSERT INTO books (title, price) VALUES (?, ?)";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use uppercase for SQL keywords to follow SQL style conventions. For example, use 'INSERT INTO books (title, price) VALUES (?, ?)'.

book.setId(id);
}
} catch (SQLException e) {
throw new DataProcessingException("Can' add a new book with id: " + book.getId());

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use informative messages for exceptions. Include the book object in the message to provide more context. For example, 'Can't add a new book: ' + book.


@Override
public Optional<Book> findById(Long id) {
String sql = "SELECT * FROM books WHERE id = ?";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use uppercase for SQL keywords to follow SQL style conventions. For example, use 'SELECT * FROM books WHERE id = ?'.

@Override
public List<Book> findAll() {
List<Book> listOfBooks = new ArrayList<>();
String sql = "SELECT * FROM books;";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use uppercase for SQL keywords to follow SQL style conventions. For example, use 'SELECT * FROM books'. Also, remove the semicolon at the end of the query string as it is not necessary in JDBC.

List<Book> listOfBooks = new ArrayList<>();
String sql = "SELECT * FROM books;";
try (Connection connection = ConnectionUtil.getConnection();
PreparedStatement statement = connection.prepareStatement(sql)) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.


@Override
public Book update(Book book) {
String sql = "UPDATE books SET title = ?, price = ? WHERE id = ?";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use uppercase for SQL keywords to follow SQL style conventions. For example, use 'UPDATE books SET title = ?, price = ? WHERE id = ?'.


@Override
public boolean deleteById(Long id) {
String sql = "DELETE FROM books WHERE id = ?";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use uppercase for SQL keywords to follow SQL style conventions. For example, use 'DELETE FROM books WHERE id = ?'.

Comment on lines 107 to 111
private Book getBookFromResultSet(ResultSet resultSet) throws SQLException {
Long id = resultSet.getLong("id");
String title = resultSet.getString("title");
BigDecimal price = resultSet.getBigDecimal("price");
return new Book(id, title, price);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid code duplication, move retrieving data from ResultSet into the Book entity object to a separate private method.

}

private Book getBookFromResultSet(ResultSet resultSet) throws SQLException {
Long id = resultSet.getLong("id");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use 'resultSet.getObject("id", Long.class)' instead of 'resultSet.getLong("id")' to handle null values correctly.

Copy link

@mateacademy-ai-mentor mateacademy-ai-mentor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job on demonstrating the CRUD operations in the Main class and adhering to Java conventions in your classes and interfaces! 👍 Remember to address the mentioned issues to ensure your code is robust and follows best practices. Keep up the good work, and make sure to review the comments to further enhance your code. It's important to continue refining your skills and learning from feedback. Happy coding! 🚀

✨ Please rate this review in the Platform's notification center. I will be grateful for your feedback! ✨


public class ConnectionUtil {
private static String password;
private static final String DB_URL = "jdbc:mysql://localhost:3306/jdbc_intro";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The DB_URL seems to be incomplete. Make sure to provide the full database URL including the database name, parameters, and avoid using schema names directly in the URL as per the checklist.

try (BufferedReader bufferedReader = Files.newBufferedReader(Paths.get(PASSWORD_PATH))) {
password = bufferedReader.readLine();
} catch (IOException e) {
throw new RuntimeException("Can't read file", e);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using a more informative message for the exception that includes the path to the file that couldn't be read.

try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
throw new RuntimeException("Can not load JDBC driver", e);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the exception message, include the name of the JDBC driver that could not be loaded to provide more context.

Book book = new Book();
book.setTitle("NewTitle");
book.setPrice(BigDecimal.valueOf(40));
Book bookUpdated = bookDao.create(book);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure that the 'create' method in 'BookDao' uses 'Statement.RETURN_GENERATED_KEYS' to retrieve and set the generated id for the book. This is crucial for the subsequent findById operation to work correctly.

Book bookUpdated = bookDao.create(book);
System.out.println("Created: " + bookUpdated);

Optional<Book> findById = bookDao.findById(book.getId());

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you retrieve a book using 'findById', it's good practice to check if the book is present before trying to use it. Use 'findById.isPresent()' to check if the book was found.

Comment on lines +47 to +60
public Optional<Book> findById(Long id) {
String sql = "SELECT * FROM books WHERE id = ?";
try (Connection connection = ConnectionUtil.getConnection();
PreparedStatement statement = connection.prepareStatement(sql)) {
statement.setLong(1, id);
ResultSet resultSet = statement.executeQuery();

if (resultSet.next()) {
return Optional.of(getBookFromResultSet(resultSet));
}
} catch (SQLException e) {
throw new DataProcessingException("Can't find a book with id: " + id);
}
return Optional.empty();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use resultSet.getObject() to retrieve the id from the ResultSet to handle null values correctly, as per the checklist.

@Override
public List<Book> findAll() {
List<Book> listOfBooks = new ArrayList<>();
String sql = "SELECT * FROM books;";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SQL keywords should be written in uppercase for consistency and readability, as per the checklist.

List<Book> listOfBooks = new ArrayList<>();
String sql = "SELECT * FROM books;";
try (Connection connection = ConnectionUtil.getConnection();
PreparedStatement statement = connection.prepareStatement(sql)) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even though the findAll method does not have parameters, it is still recommended to use PreparedStatement over Statement as per the checklist.

statement.executeUpdate();
return book;
} catch (SQLException e) {
throw new DataProcessingException("Can't update the book with id: " + book.getId());

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message in the DataProcessingException should be more informative. Include the book's details in the message to provide more context about the failure.

statement.setLong(1, id);
return statement.executeUpdate() > 0;
} catch (SQLException e) {
throw new DataProcessingException("Can't delete the book with id: " + id);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message in the DataProcessingException should be more informative. Include the id of the book in the message to provide more context about the failure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants