目录
一、配置MySQL数据库驱动包
二、JDBC常规操作
1、创建数据源
2、建立连接
3、操作数据库,执行sql语句
4、关闭资源
三、JDBC实现图书管理系统
1、建表
2、连接数据库
3、创建实体类
a、Book类
b、BookShelf类
c、User类
d、Administrator类
e、RegularUser类
4、实现操作类
a、Operate接口
b、 添加图书方法
c、删除图书
d、显示图书
e、查找图书
f、借阅图书
g、归还图书
h、退出系统
5、Main
6、效果演示
一、配置MySQL数据库驱动包
进入maven的中央仓库https://mvnrepository.com/在搜索框中输入mysql,找到与自己电脑上MySQL版本相关的jar包进行下载,如MySQL为5.x版本,那jar包也选择5.x版本:
点击对应版本后,点击jar进行下载:
在idea中创建一个项目,并创建一个lib文件夹,将下载好的jar包放到文件夹lib下,然后双击lib选择Add as...完成配置。
二、JDBC常规操作
1、创建数据源
DataSource dataSource=new MysqlDataSource();
//设置数据库所在地址
((MysqlDataSource) dataSource).setURL("jdbc:mysql://127.0.0.1:3306/library?characterEncoding=utf8&useSSL=false");
//设置数据库用户名
((MysqlDataSource) dataSource).setUser("root");
//设置数据库的登录密码
((MysqlDataSource) dataSource).setPassword("1789");
url的格式为:jdbc:mysql://服务器地址:端口/数据库名?参数名=参数值
2、建立连接
Connection connection = (Connection) dataSource.getConnection();
3、操作数据库,执行sql语句
以删除数据为例:
String sql="delete from book where name=?";
PreparedStatement statement=connection.prepareStatement(sql);
statement.setString(1,name);
statement.executeUpdate()
在sql语句中有些数据是不确定的需要用户输入,就暂时用?替代,然后再使用statement.setxx()进行替换,最后对语句进行执行,对于插入、修改、删除操作利用 executeUpdate()执行,返回值为一个整数表示多少行受影响,而对于查询操作使用executeQuery()执行,返回的是一张表,需要使用ResultSet结果集接收,并利用其next()方法对得到的结果集进行遍历,例如:对于book表查找得到的内容进行输出:
String sql="select * from book";PreparedStatement statement=connection.prepareStatement(sql);ResultSet resultSet = statement.executeQuery();while(resultSet.next()){int id=resultSet.getInt("id");String name=resultSet.getString("name");String author=resultSet.getString("author");Double price=resultSet.getDouble("price");String theme=resultSet.getString("theme");boolean isBorrowed=resultSet.getBoolean("statue");Date borrowTime=resultSet.getDate("borrow_time");Date returnTime=resultSet.getDate("return_time");System.out.println("Book{" +"id=" + id +", name='" + name + '\'' +", author='" + author + '\'' +", price=" + price +", theme='" + theme + '\'' +", isBorrowed=" + isBorrowed +", borrowTime=" + borrowTime +", returnTime=" + returnTime +'}');}
4、关闭资源
对于JDBC中资源使用完毕后要进行关闭,对于先使用的资源后关闭,对于后使用的资源先关闭,以上述的查找操作为例:
resultSet.close();statement.close();connection.close();
三、JDBC实现图书管理系统
之前在JavaSE实现了图书管理系统,但是每次运行结束后数据也随之丢失,也不符合实际应用,那么使用JDBC连接MySQL数据库就可以实现。
1、建表
针对图书管理的需求,需要建立存放书的表、管理员表和普通用户表。
create table book(id int primary key,name varchar(50) not null,
price double(3,1) not null,theme varchar(20) not null,
statue boolean default false,borrow_time datetime,return_time datetime);
create table administrator(id int primary key auto_increment,name varchar(20),password varchar(20));
create table regularuser(id int primary key auto_increment,name varchar(20),password varchar(20));
三个表的结构分别为:
2、连接数据库
创建DBUtil类,其中定义了一个静态方法返回数据库的连接,在之后的操作数据库时进行使用。
import com.mysql.jdbc.Connection;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import javax.sql.DataSource;
import java.sql.SQLException;public class DBUtil {public static Connection getConnection() throws SQLException {//1.创建数据源DataSource dataSource =new MysqlDataSource();//设置数据库所在地址((MysqlDataSource) dataSource).setURL("jdbc:mysql://127.0.0.1:3306/library?characterEncoding=utf8&useSSL=false");//设置数据库用户名((MysqlDataSource) dataSource).setUser("root");//设置数据库的登录密码((MysqlDataSource) dataSource).setPassword("gsy20021014");//2.建立连接Connection connection = (Connection) dataSource.getConnection();return connection;}}
3、创建实体类
实体可以分为两类:书和用户,书包含书类和书架类,用户包含管理员类和普通用户类
为什么还要定义类?直接操作表不就行
当时这个问题也是困惑了我很久,但是在写代码时就会发现整个项目之间没有联系,没有封装性,比如在后面登录时选择身份时如果没有类就很难完成,有了类使整个项目联系密切,逻辑性强。
a、Book类
表示书类,相对于se版本的图书系统,增加了借书时间和还书时间两个属性,并且书类和创建的book表的内容几乎一致。 定义了两个构造方法,一个包含所有的属性,另一个没有包含是否借出、借书时间和还书时间。
import java.util.Date;
import java.util.Objects;public class Book {private int id;//图书编号private String name;//图书名称private String author;//图书作者private double price;//图书价格private String theme;//图书主题private boolean isBorrowed;//图书是否被借出private Date borrowTime;//借阅时间private Date returnTime;//归还时间public int getId() {return id;}public void setId(int id) {this.id = id;}public Date getBorrowTime() {return borrowTime;}public void setBorrowTime(Date borrowTime) {this.borrowTime = borrowTime;}public Date getReturnTime() {return returnTime;}public void setReturnTime(Date returnTime) {this.returnTime = returnTime;}public Book(int id,String name, String author, double price, String theme) {this.id=id;this.name = name;this.price=price;this.author = author;this.theme = theme;this.isBorrowed = false;//默认未借出}public Book(int id, String name, String author, double price, String theme, boolean isBorrowed, Date borrowTime, Date returnTime) {this.id = id;this.name = name;this.author = author;this.price = price;this.theme = theme;this.isBorrowed = isBorrowed;this.borrowTime = borrowTime;this.returnTime = returnTime;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getAuthor() {return author;}public void setAuthor(String author) {this.author = author;}public String getTheme() {return theme;}public void setTheme(String theme) {this.theme = theme;}public boolean isBorrowed() {return isBorrowed;}public void setBorrowed(boolean borrowed) {isBorrowed = borrowed;}public double getPrice() {return price;}public void setPrice(double price) {this.price = price;}@Overridepublic String toString() {return "Book{" +"id=" + id +", name='" + name + '\'' +", author='" + author + '\'' +", price=" + price +", theme='" + theme + '\'' +", isBorrowed=" + isBorrowed +", borrowTime=" + borrowTime +", returnTime=" + returnTime +'}';}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Book book = (Book) o;return isBorrowed == book.isBorrowed && Objects.equals(name, book.name) && Objects.equals(author, book.author) && Objects.equals(theme, book.theme);}
b、BookShelf类
仍然需要书架类,便于之后对book表的各种操作,但是构造方法发生了改变,之前的currentSize书架当前存放书本书目是固定的,并且默认是书架中存放了几本书,而现在需要统计Book表中存放了多少条数据,在此使用了全列查询,对得到的结果集遍历,将书存放到书架上,并且得到currentSize的大小。
import util.DBUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;public class Bookshelf {private Book[] books ;//书架类private int size;//书架当前存放图书的数目private int currentSize=0;public Bookshelf(int size) {books = new Book[size];this.size=size;}public Bookshelf() throws SQLException {books = new Book[10000];//默认能存放10000本书this.size=10000;Connection connection= DBUtil.getConnection();String sql="select * from book";PreparedStatement statement=connection.prepareStatement(sql);ResultSet resultSet = statement.executeQuery();int count=0;while(resultSet.next()) {int id = resultSet.getInt("id");String name = resultSet.getString("name");String author = resultSet.getString("author");Double price = resultSet.getDouble("price");String theme = resultSet.getString("theme");boolean isBorrowed = resultSet.getBoolean("statue");Date borrowTime = resultSet.getTime("borrow_time");Date returnTime = resultSet.getTime("return_time");books[count++] = new Book(id, name, author, price, theme, isBorrowed, borrowTime, returnTime);}this.currentSize=count;}public int getCurrentSize() {return this.currentSize;}public void setCurrentSize(int currentSize) {this.currentSize = currentSize;}public int getSize() {return size;}public void setSize(int size) {this.size = size;}/*** 获取指定位置的图书* @param pos* @return*/public Book getBook(int pos){if(pos>=size){System.out.println("已超出书架当前容量");}else{return books[pos];}return null;}public void addBook(Book book){books[currentSize]=book;}/*** 修改指定位置的图书* @param pos* @param book* @return*/public void modify(int pos,Book book){if(pos>=size){System.out.println("已超出书架当前容量");return ;}else{books[pos]=book;}}
}
c、User类
User类是管理员和普通用户的父类,因为在登录时登录时选择不同身份来对数据库进行操作,除了表中属性,还需要定义一个接口数组用于存放各种对书架的相关操作方法,需要一个展示菜单的方法并返回选项,然后再定义一个doWork()方法是依据选项来操作数据库。还需要定义一个身份验证的方法。
import book.Bookshelf;
import operate.Operate;
import java.sql.SQLException;public abstract class User {public int id;//用户编号public String name;//用户姓名public String password;//用户密码public Operate[] operates;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public User( String name, String password) {this.name = name;this.password = password;}public User() {}public abstract int menu();public void doWork(int option, Bookshelf books) throws SQLException {this.operates[option].work(books);}public abstract boolean authentication(String name, String pwd)throws SQLException;}
d、Administrator类
管理员的主要功能是对图书进行增加、删除、查看以及查找,管理员类继承User类,需要对父类定义的接口数组完善将自己特有的方法进行填充。对于重写身份验证方法,使用select name,password from administrator ,遍历结果集得到姓名和密码,若有对应的密码和密码则登录成功,否则登录失败。
import operate.*;
import util.DBUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Scanner;public class Administrator extends User{public Administrator(){}public Administrator(String name, String password) {super(name,password);this.operates=new Operate[]{new ExitOpe(),new AddBook(),new DelBook(),new DisplayBook(),new FindBook()};}@Overridepublic int menu() {System.out.println("*******************************************");System.out.println(" 1.添加图书 2.删除图书 ");System.out.println(" 3.显示图书 4.查找图书 ");System.out.println(" 0.退出系统 ");System.out.println("*******************************************");System.out.println("请输入您的操作:");Scanner sc = new Scanner(System.in);int option = sc.nextInt();return option;}@Overridepublic boolean authentication(String name,String pwd) throws SQLException {Connection connection= DBUtil.getConnection();String sql="select name,password from administrator where name=?";PreparedStatement statement=connection.prepareStatement(sql);statement.setString(1,name);ResultSet resultSet=statement.executeQuery();if(resultSet.next()){String na=resultSet.getString("name");String pw=resultSet.getString("password");if(pw.equals(pwd)&&na.equals(name)){return true;}}return false;}}
e、RegularUser类
普通用户类同样继承User类,内部实现与管理员类相似。
import operate.*;
import util.DBUtil;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Scanner;public class RegularUser extends User{public RegularUser(){}public RegularUser(String name, String password) {super(name,password);this.operates=new Operate[]{new ExitOpe(),new BorrowBook(),new ReturnBook(),new DisplayBook(),new FindBook(),};}@Overridepublic int menu() {System.out.println("*******************************************");System.out.println(" 1.借阅图书 2.归还图书 ");System.out.println(" 3.显示图书 4.查找图书 ");System.out.println(" 0.退出系统 ");System.out.println("*******************************************");System.out.println("请输入您的操作:");Scanner sc = new Scanner(System.in);int option = sc.nextInt();return option;}@Overridepublic boolean authentication(String name, String pwd) throws SQLException {Connection connection= DBUtil.getConnection();String sql="select name,password from regularuser where name=?";PreparedStatement statement=connection.prepareStatement(sql);statement.setString(1,name);ResultSet resultSet=statement.executeQuery();if(resultSet.next()){String na=resultSet.getString("name");String pw=resultSet.getString("password");if(pw.equals(pwd)&&na.equals(name)){return true;}}return false;}
}
4、实现操作类
a、Operate接口
创建一个接口,内部定义一个抽象的work方法,然后操作类都实现这个接口,并重写work方法。
import book.Bookshelf;
import java.sql.SQLException;public interface Operate {void work(Bookshelf books) throws SQLException;
}
b、 添加图书方法
由于书架当时的初始容量为10000,但还是进行了判断,如果容量已满则无法添加,再进一步输入要添加图书的信息,利用图书类中的equals()方法对添加的图书与已经存放的图书,若有重复则无法添加,否则使用insert插入语句进行添加,完成对数据库的更新,并且要将该图书添加到书架类的数组中。
public class AddBook implements Operate{@Overridepublic void work(Bookshelf books) throws SQLException {if(books.getCurrentSize()>= books.getSize()){System.out.println("书架已满,无法继续添加");}else{Scanner sc=new Scanner(System.in);System.out.println("请输入图书信息:");System.out.println("图书编号:");int id=sc.nextInt();System.out.println("图书名称:");String name=sc.next();System.out.println("图书作者:");String author = sc.next();System.out.println("图书价格:");int price = sc.nextInt();System.out.println("图书主题:");sc.nextLine();String theme= sc.nextLine();Book book = new Book(id,name, author, price, theme);for (int i = 0; i < books.getCurrentSize(); i++) {if(book.equals(books.getBook(i))){System.out.println("该图书已经存在,无法继续添加!");return;}}String sql="insert into book(id,name,author,price,theme) values(?,?,?,?,?)";Connection connection= DBUtil.getConnection();PreparedStatement statement=connection.prepareStatement(sql);statement.setInt(1,id);statement.setString(2,name);statement.setString(3,author);statement.setDouble(4,price);statement.setString(5,theme);books.addBook(book);books.setCurrentSize(books.getCurrentSize()+1);int ret=statement.executeUpdate();if(ret>0){System.out.println("添加成功!");}statement.close();connection.close();}}
}
c、删除图书
输入要删除的图书名称,利用书架类的数组遍历,此处不使用select语句进行查找是后面对书架进行删除时需要得到图书在书架的位置,找到后使用delete语句删除图书,然后再使用循环覆盖删除书架中的该图书。
public class DelBook implements Operate{@Overridepublic void work(Bookshelf books) throws SQLException {System.out.println("请输入要删除的图书名称");Scanner sc=new Scanner(System.in);String name=sc.nextLine();int pos=-1;for (int i = 0; i < books.getCurrentSize(); i++) {if(name.equals(books.getBook(i).getName())){pos=i;break;}}if(pos==-1){System.out.println("未找到您要删除的图书");}else{Connection connection= DBUtil.getConnection();String sql="delete from book where name=?";PreparedStatement statement=connection.prepareStatement(sql);statement.setString(1,name);int ret=statement.executeUpdate();if(ret>0){System.out.println("删除成功!");}for(int i= pos+1;i<books.getCurrentSize();i++){Book book=books.getBook(i);books.modify(i-1,book);}books.modify(books.getCurrentSize(),null);books.setCurrentSize(books.getCurrentSize()-1);statement.close();connection.close();}}
}
d、显示图书
显示所有的图书信息,此处使用select语句对book表进行全列查询,此处也可以遍历书架得到所有图书的信息。
public class DisplayBook implements Operate{@Overridepublic void work(Bookshelf books) throws SQLException {Connection connection= DBUtil.getConnection();String sql="select * from book";PreparedStatement statement=connection.prepareStatement(sql);ResultSet resultSet = statement.executeQuery();System.out.println("====================================================================================================================");while(resultSet.next()){int id=resultSet.getInt("id");String name=resultSet.getString("name");String author=resultSet.getString("author");Double price=resultSet.getDouble("price");String theme=resultSet.getString("theme");boolean isBorrowed=resultSet.getBoolean("statue");Date borrowTime=resultSet.getDate("borrow_time");Date returnTime=resultSet.getDate("return_time");System.out.println("Book{" +"id=" + id +", name='" + name + '\'' +", author='" + author + '\'' +", price=" + price +", theme='" + theme + '\'' +", isBorrowed=" + (isBorrowed?"已借出":"未借出") +", borrowTime=" + borrowTime +", returnTime=" + returnTime +'}');}System.out.println("====================================================================================================================");resultSet.close();statement.close();connection.close();}
}
e、查找图书
此处使用的是select语句对图书名称进行精确查询,也使用循环遍历书架更为方便。
public class FindBook implements Operate{@Overridepublic void work(Bookshelf books) throws SQLException {System.out.println("请输入要查找的图书名称");Scanner sc=new Scanner(System.in);String str=sc.nextLine();int pos=-1;Connection connection= DBUtil.getConnection();String sql="select * from book where name=?";PreparedStatement statement=connection.prepareStatement(sql);statement.setString(1,str);ResultSet resultSet = statement.executeQuery();if(resultSet==null){System.out.println("未找到您要找的书籍");return;}System.out.println("====================================================================================================================");while(resultSet.next()){int id=resultSet.getInt("id");String name=resultSet.getString("name");String author=resultSet.getString("author");Double price=resultSet.getDouble("price");String theme=resultSet.getString("theme");boolean isBorrowed=resultSet.getBoolean("statue");Date borrowTime=resultSet.getTime("borrow_time");Date returnTime=resultSet.getTime("return_time");System.out.println("Book{" +"id=" + id +", name='" + name + '\'' +", author='" + author + '\'' +", price=" + price +", theme='" + theme + '\'' +", isBorrowed=" + (isBorrowed?"已借出":"未借出") +", borrowTime=" + borrowTime +", returnTime=" + returnTime +'}');}System.out.println("====================================================================================================================");resultSet.close();statement.close();connection.close();}
}
f、借阅图书
在借阅图书时,首先对输入的图书进行查找,若有才能进行借阅,使用update语句对图书的是否借出还有借阅时间进行修改,在创建图书类的日期是使用的是util包的Date类,但是在book表中的datetime是sql包的Date类,需要进行转换,对数据库中的book表完成更新后,同时也要修改书架上的图书信息。
public class BorrowBook implements Operate{@Overridepublic void work(Bookshelf books) throws SQLException {System.out.println("请输入要借阅的图书名称");Scanner sc=new Scanner(System.in);String name=sc.nextLine();int pos=-1;for (int i = 0; i < books.getCurrentSize(); i++) {if(name.equals(books.getBook(i).getName())){pos=i;break;}}if(pos==-1){System.out.println("未找到您需要的图书");}else{if(books.getBook(pos).isBorrowed()==true){System.out.println("该图书已经借出");return;}Date date=new Date(System.currentTimeMillis());java.sql.Date sd=new java.sql.Date(date.getTime());Connection connection= DBUtil.getConnection();String sql1="update book set borrow_time=? where name=?";PreparedStatement statement1=connection.prepareStatement(sql1);statement1.setDate(1,sd);statement1.setString(2,name);String sql2="update book set statue=? where name=?";PreparedStatement statement2=connection.prepareStatement(sql2);Boolean flag=true;statement2.setBoolean(1,flag);statement2.setString(2,name);statement1.executeUpdate();statement1.close();statement2.executeUpdate();statement2.close();connection.close();books.getBook(pos).setBorrowed(true);books.getBook(pos).setBorrowTime(date);System.out.println("借阅成功!");}}
}
g、归还图书
在归还图书时,也要对图书的借阅状态和归还时间进行修改,操作与借阅图书类似。
public class ReturnBook implements Operate {@Overridepublic void work(Bookshelf books) throws SQLException {System.out.println("请输入要归还的图书名称");Scanner sc=new Scanner(System.in);String name=sc.nextLine();int pos=-1;for (int i = 0; i < books.getCurrentSize(); i++) {if(name.equals(books.getBook(i).getName())){pos=i;break;}}if(pos==-1){System.out.println("未找到您需要的图书");}else{Date date=new Date(System.currentTimeMillis());java.sql.Date sd=new java.sql.Date(date.getTime());Connection connection= DBUtil.getConnection();String sql1="update book set return_time=? where name=?";PreparedStatement statement1=connection.prepareStatement(sql1);statement1.setDate(1,sd);statement1.setString(2,name);String sql2="update book set statue=? where name=?";PreparedStatement statement2=connection.prepareStatement(sql2);Boolean flag=false;statement2.setBoolean(1,flag);statement2.setString(2,name);statement1.executeUpdate();statement1.close();statement2.executeUpdate();statement2.close();connection.close();books.getBook(pos).setBorrowed(false);books.getBook(pos).setReturnTime(date);System.out.println("归还成功!");}}
}
h、退出系统
使用System.exit(0)方法退出系统,虽然该方法没有任何异常,但因为重写了Operate中的work方法,work方法抛出了sql异常,那么该方法也需要抛出异常。
public class ExitOpe implements Operate{@Overridepublic void work(Bookshelf books) throws SQLException {System.out.println("退出成功,欢迎下次使用!");System.exit(0);}
}
5、Main
在测试类中需要实现登录函数,由于在登录时才知道用户身份,所以使用User类为返回值进行向上转型,在登录函数中首先选择身份,然后对身份进行验证,验证成功后,即登录成功。
public class Main {public static User login() throws SQLException {System.out.println("请选择登录身份:1)管理员 2)普通用户");Scanner sc=new Scanner(System.in);int option=sc.nextInt();System.out.println("请输入姓名:");String name=sc.next();System.out.println("请输入密码:");String pwd=sc.next();if(option==1){boolean flag=new Administrator().authentication(name,pwd);if(flag){System.out.println("登陆成功!");return new Administrator(name,pwd);}else{System.out.println("姓名或密码输入有误");}}else if(option==2){boolean flag=new RegularUser().authentication(name,pwd);if(flag){System.out.println("登陆成功!");return new RegularUser(name,pwd);}else{System.out.println("姓名或密码输入有误");}}else{System.out.println("输入有误");}return null;}public static void main(String[] args) throws SQLException {Bookshelf books=new Bookshelf();User user=login();while(true){int ret=user.menu();user.doWork(ret,books);}}
}
6、效果演示
管理员和普通用户表如下所示:
运行效果演示:
管理员:
普通用户: