CSDN话题挑战赛第2期
参赛话题:学习笔记
(点击进入专栏)
【1】idea添加mysql-jar包
【2】使用IDEA连接数据库,执行增删改操作。
【3】IDEA连接数据库,执行查询操作,返回结果集并输出。
【4】JDBC实战 水果库存系统 [设计阶段]
【5】水果库存系统 [功能实现](接口实现类FruitDAOImpl)
【7】 水果库存系统 [代码优化]
【8】连接数据库,执行批处理操作。
【9】数据库连接池:德鲁伊druid的使用
上一篇文章中,我们对水果库存系统的需求进行了介绍,同时对系统需要的结构进行了设计,接下来,就到了实际上手,实现功能的阶段了。
在这篇文章中,我们将对实现类FruitDAOImpl
中的单精度方法进行代码实现。
回顾一下实现类FruitDAOImpl
中设计的单精度方法吧:
查询库存列表
:
新增库存
:
修改库存
:
删除库存
:
查询指定库存
:
这是新增库存
的方法,根据字面意思来简单理解一下,就是使用JDBC连接数据库,对数据库数据进行增添操作
,增添的数据来自传入的Fruit
对象。
依旧是常规的步骤:
…
加载驱动
:
//加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
…
使用数据库管理器,连接数据库
:
需要准备:
连接数据库的地址URL;
数据库账户USER;
账户密码PSW(password);
String URL = "jdbc:mysql://localhost:3306/fruitdb?useSSL=false&useUnicode=true&CharacterEncoding=utf-8";
String USER = "root" ;
String PSW = "" ;
//数据库管理器,连接数据库
Connection connection = DriverManager.getConnection(URL, USER, PSW);
…
编写SQL语句
:
因为第一个属性fid(水果编号)是自增列,所以填入0即可。
剩下的四个属性,使用占位符 ?代替,以便后续的填充。
String sql = "insert into t_fruit values(0,?,?,?,?)";
…
创建预处理对象
:
将编写的SQL语句传入;
PreparedStatement pstm = connection.prepareStatement(sql);
…
填充占位符 ?参数
:
这里面的参数需要从传入的Fruit对象中获取,也就是:
pstm.setString(1, fruit.getFname());
pstm.setInt(2,fruit.getPrice());
pstm.setInt(3,fruit.getFcount());
pstm.setString(4,fruit.getRemark());
…
执行更新,返回影响行数
:
int count = pstm.executeUpdate()
因为boolean addFruit(Fruit fruit);
方法的返回值是布尔类型(boolean),所以当返回的影响行数大于零时,我们就返回true
,否则返回false
return count > 0;
…
关闭资源
:
很重要的一步:
psmt.close();
connection.close();
…
完成这一系列的操作,我们得到了:
满屏的报错,对了,我们还需要异常处理:try-catch-finally
@Override
public boolean addFruit(Fruit fruit){
try {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/fruitdb?useSSL=false&useUnicode=true&characterEncoding=gbk",
"root", "");
String sql = "insert into t_fruit values(8,?,?,?,?)";
PreparedStatement psmt = connection.prepareStatement(sql);
pstm.setString(1, fruit.getFname());
pstm.setInt(2,fruit.getPrice());
pstm.setInt(3,fruit.getFcount());
pstm.setString(4,fruit.getRemark());
int count = psmt.executeUpdate();
return count > 0;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally{
try {
if(psmt != null)
psmt.close();
if(connection != null)
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return false;
}
但是,依旧爆红
:
这是因为我们经过异常处理之后,创建的对象
,都被try{}
代码块给囊括起来了,而出了代码块之后也就失去了效用,所以在finally{}
中的对象会出问题…
为了解决这个问题,我们就需要将对象都设置成全局变量
,这样的话,无论在那个代码块中,都能被识别出来。
同时,还可以将一些比较冗长,常常用到的属性也设置成全局变量
,方便使用。
final String DRIVER = "com.mysql.cj.jdbc.Driver";
final String URL = "jdbc:mysql://localhost:3306/fruitdb?useSSL=false&useUnicode=true&CharacterEncoding=utf-8";
final String USER = "root" ;
final String PSW = "" ;
Connection connection;
PreparedStatement pstm;
ResultSet rs;
List<Fruit> list;
这样子,问题基本就解决啦:
@Override
public boolean addFruit(Fruit fruit){
try {
Class.forName(DRIVER);
connection = DriverManager.getConnection(URL, USER, PSW);
String sql = "insert into t_fruit values(0,?,?,?,?)";
pstm = connection.prepareStatement(sql);
pstm.setString(1, fruit.getFname());
pstm.setInt(2,fruit.getPrice());
pstm.setInt(3,fruit.getFcount());
pstm.setString(4,fruit.getRemark());
return pstm.executeUpdate() > 0;
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}finally{
try {
if(pstm != null)
pstm.close();
if(connection != null)
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return false;
}
上文介绍的功能实现,步骤已经十分齐全,而且在接下来的更新操作相关方法中,除了SQL语句,基本上都大同小异了。
在更新水果库存方法中,我们只需要更新指定水果的库存数量即可,所以需要填充的参数有两个,都是从传入的Fruit对象(已修改库存)中获取:
功能实现代码
:
@Override
public boolean UpdateFruit(Fruit fruit) {
try {
//加载驱动
Class.forName(DRIVER);
//数据库管理器,连接数据库
connection = DriverManager.getConnection(URL, USER, PSW);
//sql语句
String sql = "update t_fruit set fcount = ? where fname like ?";
//预处理对象
pstm = connection.prepareStatement(sql);
pstm.setInt(1,fruit.getFcount());
pstm.setString(2, fruit.getFname());
return pstm.executeUpdate() > 0;
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}finally{
try {
if(pstm != null)
pstm.close();
if(connection != null)
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return false;
}
删除库存的方法里,只需要根据传入的水果名称
,删除数据库中相应的数据即可:
功能实现的代码
:
@Override
public boolean DelFruit(String fname) {
try {
//加载驱动
Class.forName(DRIVER);
//数据库管理器,连接数据库
connection = DriverManager.getConnection(URL, USER, PSW);
//sql语句
String sql = "delete from t_fruit where fname like ?";
//预处理对象
pstm = connection.prepareStatement(sql);
pstm.setString(1,fname);
return pstm.executeUpdate() > 0;
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}finally{
try {
if(pstm != null)
pstm.close();
if(connection != null)
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return false;
}
执行查询
操作与执行更新
操作之间有一定的差异
:
查询操作通常调用的是预处理对象的executeQuery()
方法
更新操作通常调用的是预处理对象的executeUpdate()
方法
executeUpdate()
方法返回的是更新操作后的影响行数;
而executeQuery()
方法返回的是一个 ResultSet
对象,里面存储的是记录了数据库每行信息的数据。
我们需要使用循环来将数据库每行信息记录下来,存储进数组中返回。
集合在上文已经设置成了全局变量:
ResultSet rs; //rs对象
List<Fruit> list; //集合
查询水果信息的实现代码
:
@Override
public List<Fruit> getFruitList() {
try {
//加载驱动
Class.forName(DRIVER);
//数据库管理器,连接数据库
connection = DriverManager.getConnection(URL, USER, PSW);
//sql语句
String sql = "select * from t_fruit";
//预处理对象
pstm = connection.prepareStatement(sql);
//执行查询,返回结果集
rs = pstm.executeQuery();
list = new ArrayList<Fruit>();
while(rs.next()){
int Fid = rs.getInt("fid");
String Fname = rs.getString("fname");
int Price = rs.getInt("price");
int Fcount = rs.getInt("fcount");
String Remark = rs.getString("remark");
Fruit fruitTable = new Fruit(Fid,Fname,Price,Fcount,Remark);
list.add(fruitTable);
}
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally{
try {
if(rs != null)
rs.close();
if(pstm != null)
pstm.close();
if(connection != null)
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return list;
}
查询指定水果的信息,在这个方法中,我们依靠传入的水果姓名-fname
来确定需要查询信息的水果。
返回的是Fruit对象,此对象的属性便是指定水果的信息。
@Override
public Fruit getFruitByFname(String fname) {
try {
//加载驱动
Class.forName(DRIVER);
//数据库管理器,连接数据库
connection = DriverManager.getConnection(URL, USER, PSW);
//sql语句
String sql = "select * from t_fruit where fname = ? ";
//预处理对象
pstm = connection.prepareStatement(sql);
pstm.setString(1,fname);
//执行查询,返回结果集
rs = pstm.executeQuery();
while(rs.next()){
int fid = rs.getInt("fid");
int price = rs.getInt("price");
int fcount = rs.getInt("fcount");
String remark = rs.getString("remark");
Fruit fruit = new Fruit(fid,fname,price,fcount,remark);
return fruit;
}
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally{
try {
if(rs != null)
rs.close();
if(pstm != null)
pstm.close();
if(connection != null)
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return null;
}
接口实现类FruitDAOImpl中出现的方法,全都是单精度方法
,代表方法的颗粒密度已经不能再划分了。
简单点来说,方法的功能还过于单一
,操作过于简易
,而不足以满足水果库存系统的功能需求。
也正因如此,我们还需要菜单类Menu
中的方法,里面的方法调用了接口实现类FruitDAOImpl
这里的单精度方法,同时将拥有更加丰富的功能。
接口实现类FruitDAOImpl的功能实现
:
import com.haojin.fruit.dao.FruitDAO;
import com.haojin.fruit.pojo.Fruit;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
/**
* @author .29.
* @create 2022-09-23 17:56
*/
public class FruitDAOImpl implements FruitDAO {
final String DRIVER = "com.mysql.cj.jdbc.Driver";
final String URL = "jdbc:mysql://localhost:3306/fruitdb?useSSL=false&useUnicode=true&CharacterEncoding=utf-8";
final String USER = "root" ;
final String PSW = "" ;
Connection connection;
PreparedStatement pstm;
ResultSet rs;
List<Fruit> list;
@Override
public List<Fruit> getFruitList() {
try {
//加载驱动
Class.forName(DRIVER);
//数据库管理器,连接数据库
connection = DriverManager.getConnection(URL, USER, PSW);
//sql语句
String sql = "select * from t_fruit";
//预处理对象
pstm = connection.prepareStatement(sql);
//执行查询,返回结果集
rs = pstm.executeQuery();
list = new ArrayList<Fruit>();
while(rs.next()){
int Fid = rs.getInt("fid");
String Fname = rs.getString("fname");
int Price = rs.getInt("price");
int Fcount = rs.getInt("fcount");
String Remark = rs.getString("remark");
Fruit fruitTable = new Fruit(Fid,Fname,Price,Fcount,Remark);
list.add(fruitTable);
}
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally{
try {
if(rs != null)
rs.close();
if(pstm != null)
pstm.close();
if(connection != null)
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return list;
}
@Override
public boolean addFruit(Fruit fruit){
try {
Class.forName(DRIVER);
connection = DriverManager.getConnection(URL, USER, PSW);
String sql = "insert into t_fruit values(0,?,?,?,?)";
pstm = connection.prepareStatement(sql);
pstm.setString(1, fruit.getFname());
pstm.setInt(2,fruit.getPrice());
pstm.setInt(3,fruit.getFcount());
pstm.setString(4,fruit.getRemark());
return pstm.executeUpdate() > 0;
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}finally{
try {
if(pstm != null)
pstm.close();
if(connection != null)
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return false;
}
@Override
public boolean UpdateFruit(Fruit fruit) {
try {
//加载驱动
Class.forName(DRIVER);
//数据库管理器,连接数据库
connection = DriverManager.getConnection(URL, USER, PSW);
//sql语句
String sql = "update t_fruit set fcount = ? where fname like ?";
//预处理对象
pstm = connection.prepareStatement(sql);
pstm.setInt(1,fruit.getFcount());
pstm.setString(2, fruit.getFname());
return pstm.executeUpdate() > 0;
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}finally{
try {
if(pstm != null)
pstm.close();
if(connection != null)
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return false;
}
@Override
public boolean DelFruit(String fname) {
try {
//加载驱动
Class.forName(DRIVER);
//数据库管理器,连接数据库
connection = DriverManager.getConnection(URL, USER, PSW);
//sql语句
String sql = "delete from t_fruit where fname like ?";
//预处理对象
pstm = connection.prepareStatement(sql);
pstm.setString(1,fname);
return pstm.executeUpdate() > 0;
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}finally{
try {
if(pstm != null)
pstm.close();
if(connection != null)
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return false;
}
@Override
public Fruit getFruitByFname(String fname) {
try {
//加载驱动
Class.forName(DRIVER);
//数据库管理器,连接数据库
connection = DriverManager.getConnection(URL, USER, PSW);
//sql语句
String sql = "select * from t_fruit where fname = ? ";
//预处理对象
pstm = connection.prepareStatement(sql);
pstm.setString(1,fname);
//执行查询,返回结果集
rs = pstm.executeQuery();
while(rs.next()){
int fid = rs.getInt("fid");
int price = rs.getInt("price");
int fcount = rs.getInt("fcount");
String remark = rs.getString("remark");
Fruit fruit = new Fruit(fid,fname,price,fcount,remark);
return fruit;
}
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally{
try {
if(rs != null)
rs.close();
if(pstm != null)
pstm.close();
if(connection != null)
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return null;
}
}
到这里,接口实现类FruitDAOImpl
的功能实现就完成啦…
接下来就是对菜单类Menu
的功能实现,再完成菜单类的功能代码,我们的水果库存系统功能就可以说是完成了。之后就可以进入代码优化阶段…