
1. JDBC Connection & SQL Errors
My first roadblock wasn't even logic — it was just getting connected. I kept hitting:
com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure
**
What was going wrong:**
Wrong JDBC URL format (missing useSSL=false or timezone parameter caused issues on newer MySQL versions)
MySQL service not running
Driver JAR not added to the classpath correctly
How I fixed it:
java
String url = "jdbc:mysql://localhost:3306/voting_db?useSSL=false&serverTimezone=UTC";
Connection con = DriverManager.getConnection(url, "root", "password");
I also wrapped every connection attempt in a proper try-catch-finally block instead of letting exceptions crash the whole app silently:
java
*try *(Connection con = DriverManager.getConnection(url, user, pass)) {
// queries here
} catch (SQLException e) {
System.out.println("DB connection failed: " + e.getMessage());
}
Lesson: Using try-with-resources for Connection, PreparedStatement, and ResultSet saved me from a bunch of "leaked connection" bugs later.
**
- Preventing Duplicate Votes**
This was the trickiest logic problem. Nothing stops a user from just running the "vote" function twice unless you explicitly block it.
**
My approach:**
Added a has_voted boolean column to the voters table.
Before casting a vote, I check this flag. After a successful vote, I flip it immediately in the same transaction — not as an afterthought.
java
public boolean hasVoted(String voterId) throws SQLException {
String query = "SELECT has_voted FROM voters WHERE voter_id = ?";
try (PreparedStatement ps = con.prepareStatement(query)) {
ps.setString(1, voterId);
ResultSet rs = ps.executeQuery();
return rs.next() && rs.getBoolean("has_voted");
}
}
I also added a UNIQUE constraint at the database level as a backup — never trust application logic alone to enforce something this important. If the app logic has a bug, the database still refuses the duplicate insert.
**
- Designing the DAO Pattern Cleanly**
At first, my DB queries were scattered across the main class — messy and hard to test. Refactoring into a proper DAO layer took a few iterations to get right.
Final structure I settled on:
*VoterDAO * -> handles voter lookup & verification
*CandidateDAO * -> handles candidate data
*VoteDAO * -> handles casting + counting votes
*DBConnection * -> single utility class for getting connections
Each DAO interface has an implementation class, so if I ever swap MySQL for another database, only the implementation changes — not the code calling it.
java
public interface VoterDAO {
boolean verifyVoter(String voterId);
boolean hasVoted(String voterId);
}
**
Lesson:** Separating "what" (interface) from "how" (implementation) made my code far easier to debug and extend later.
4. Generating the Vote Result File
Once voting closes, I needed to tally results and write them to a file — but my first attempt kept producing incomplete or garbled output because I wasn't flushing/closing the file writer properly.
Fix:
java
try (BufferedWriter writer = new BufferedWriter(new FileWriter("vote_results.txt"))) {
for (Map.Entry entry : results.entrySet()) {
writer.write(entry.getKey() + " : " + entry.getValue() + " votes");
writer.newLine();
}
} catch (IOException e) {
System.out.println("Error writing results: " + e.getMessage());
}
Top comments (0)