Java Movie Database Tutorial: CRUD App with JDBC and Swing
This tutorial walks through building a simple desktop CRUD (Create, Read, Update, Delete) movie database using Java, JDBC for database access, and Swing for the GUI. It assumes Java 11+ and a relational database (SQLite for simplicity). You’ll get a working app with a movies table, forms to add/edit movies, and a list view with delete functionality.
What you’ll build
- SQLite database with a movies table
- Data Access Object (DAO) using JDBC
- Swing GUI: list of movies, add/edit form, delete action
- Basic validation and exception handling
Project setup
-
Create a Maven project (or plain Java project). Example Maven coordinates:
- GroupId: com.example
- ArtifactId: java-movie-db
- Java version: 11+
-
Add dependency for SQLite (if using Maven):
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.42.0.0</version>
</dependency>
Database schema (SQLite)
Create a file movies.db in the project root or let the app create it. SQL schema:
CREATE TABLE IF NOT EXISTS movies (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
director TEXT,
year INTEGER,
genre TEXT,
rating REAL
);
Data model
Create a simple Movie class.
public class Movie {
private int id;
private String title;
private String director;
private Integer year;
private String genre;
private Double rating;
// constructors, getters, setters, toString
}
JDBC DAO
Create MovieDao with methods: initialize(), listAll(), findById(id), insert(movie), update(movie), delete(id). Example key methods:
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class MovieDao {
private final String url = “jdbc:sqlite:movies.db”;
public MovieDao() throws SQLException {
initialize();
}
public void initialize() throws SQLException {
try (Connection conn = DriverManager.getConnection(url);
Statement stmt = conn.createStatement()) {
String sql = “CREATE TABLE IF NOT EXISTS movies (” +
“id INTEGER PRIMARY KEY AUTOINCREMENT,” +
“title TEXT NOT NULL,” +
“director TEXT,” +
“year INTEGER,” +
“genre TEXT,” +
“rating REAL)”;
stmt.execute(sql);
}
}
public List<Movie> listAll() throws SQLException {
List<Movie> list = new ArrayList<>();
String sql = “SELECT id, title, director, year, genre, rating FROM movies ORDER BY title”;
try (Connection conn = DriverManager.getConnection(url);
PreparedStatement ps = conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
Movie m = new Movie();
m.setId(rs.getInt(“id”));
m.setTitle(rs.getString(“title”));
m.setDirector(rs.getString(“director”));
int y = rs.getInt(“year”);
m.setYear(rs.wasNull() ? null : y);
m.setGenre(rs.getString(“genre”));
double r = rs.getDouble(“rating”);
m.setRating(rs.wasNull() ? null : r);
list.add(m);
}
}
return list;
}
public Movie findById(int id) throws SQLException {
String sql = “SELECT id, title, director, year, genre, rating FROM movies WHERE>;
try (Connection conn = DriverManager.getConnection(url);
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setInt(1, id);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
Movie m = new Movie();
m.setId(rs.getInt(“id”));
m.setTitle(rs.getString(“title”));
m.setDirector(rs.getString(“director”));
int y = rs.getInt(“year”);
m.setYear(rs.wasNull() ? null : y);
m.setGenre(rs.getString(“genre”));
double r = rs.getDouble(“rating”);
m.setRating(rs.wasNull() ? null : r);
return m;
}
}
}
return null;
}
public void insert(Movie m) throws SQLException {
String sql = “INSERT INTO movies(title,director,year,genre,rating) VALUES(?,?,?,?,?)”;
try (Connection conn = DriverManager.getConnection(url);
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, m.getTitle());
ps.setString(2, m.getDirector());
if (m.getYear() == null) ps.setNull(3, Types.INTEGER); else ps.setInt(3, m.getYear());
ps.setString(4, m.getGenre());
if (m.getRating() == null) ps.setNull(5, Types.REAL); else ps.setDouble(5, m.getRating());
ps.executeUpdate();
}
}
public void update(Movie m) throws SQLException {
String sql = “UPDATE movies SET title=?, director=?, year=?, genre=?, rating=? WHERE>;
try (Connection conn = DriverManager.getConnection(url);
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, m.getTitle());
ps.setString(2, m.getDirector());
if (m.getYear() == null) ps.setNull(3, Types.INTEGER); else ps.setInt(3, m.getYear());
ps.setString(4, m.getGenre());
if (m.getRating() == null) ps.setNull(5, Types.REAL); else ps.setDouble(5, m.getRating());
ps.setInt(6, m.getId());
ps.executeUpdate();
}
}
public void delete(int id) throws SQLException {
String sql = “DELETE FROM movies WHERE>;
try (Connection conn = DriverManager.getConnection(url);
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setInt(1, id);
ps.executeUpdate();
}
}
}
Swing GUI
Create a main frame with:
- JTable to list movies (backed by AbstractTableModel)
- Buttons: Add, Edit, Delete, Refresh
- Modal dialog for Add/Edit with input fields: title, director, year, genre, rating
Key parts:
- MovieTableModel extending AbstractTableModel to wrap List.
- MainFrame: loads list via MovieDao.listAll(), sets table model, wires button actions.
- Add/Edit Dialog: validates title required, year numeric (optional), rating between 0–10 (optional).
Example MovieTableModel skeleton:
public class MovieTableModel extends AbstractTableModel {
private final List<Movie> movies;
private final String[] cols = {“ID”,“Title”,“Director”,“Year”,“Genre”,“Rating”};
public MovieTableModel(List<Movie> movies) { this.movies = movies; }
public int getRowCount() { return movies.size(); }
public int getColumnCount() { return cols.length; }
public String getColumnName(int c) { return cols[c]; }
public Object getValueAt(int r, int c) {
Movie m = movies.get(r);
switch(c) {
case 0: return m.getId();
case 1: return m.getTitle();
case 2: return m.getDirector();
case 3: return m.getYear();
case 4: return m.getGenre();
case 5: return m.getRating();
default: return null;
}
}
public Movie getMovieAt(int row) { return movies.get(row); }
}
MainFrame action examples:
- Add: open dialog, on OK call dao.insert(movie), refresh table.
- Edit: get selected row, open dialog populated, on OK call dao.update(movie), refresh.
- Delete: confirm, dao.delete(id), refresh.
- Refresh: reload list from dao and update model.
Simple Add/Edit dialog example
Use JDialog with JTextFields and JButtons. On OK parse and validate inputs, construct Movie, close and return.
Validation rules
- Title required (non-empty)
- Year optional; if provided must be integer between 1888 and current year (2026)
- Rating optional; if provided must be number 0.0–10.0
Error handling
- Show JOptionPane dialogs for SQL errors or validation failures.
- Use try-with-resources for JDBC.
- Keep UI responsive: for longer ops consider SwingWorker.
How to run
- Build with Maven: mvn package
- Run: java -cp target/java-movie-db.jar;path/to/sqlite-jdbc.jar com.example.MainFrame (Adjust classpath for your environment.)
Next steps / enhancements
- Use H2 or PostgreSQL for production.
- Add search/filtering, sorting, pagination.
- Replace Swing with JavaFX or convert to a REST API + web frontend.
- Add unit tests for DAO.
This provides the essentials to implement a CRUD Java Movie Database with JDBC and Swing. Use the provided DAO and table model patterns to complete the UI and behavior.