目录
1、需求
2、工程目录
2.1、工程目录说明
2.2、src文件
3、准备工作
3.1、⭐开启MySQL
3.2、数据初始化
3.3、导入驱动包
3.4、驱动包介绍
3.5、回顾JDBC代码步骤
3.5.1、原先步骤
3.5.2、改进步骤
4、代码实现
4.1、druid.properties
4.2、com.sql
4.2.1、information
4.2.2、sqlInitialForMySQL
4.3、com.operation
4.3.1、encapsulationTool
4.3.2、operations完整源码
4.3.3、⭐selectAll()
4.3.4、insert()
4.3.5、update()
4.3.6、delete()
5、注意事项
5.1、空指针
5.2、包名格式异常
5.3、junit异常
5.4、图解IDEA中配置MySQL
5.5、SQL语句警告
本文介绍JDBC的实践案例,是对JDBC的综合操作讲解(文中附有详细代码)
了解并熟悉JDBC,请看我的另一篇文章:
JDBC->Java操作MySQL数据库_︶ㄣ释然的博客-CSDN博客JDBC->超一万字文章带你详细了解Java操作MySQL数据库的各种步骤,后续会更新一篇关于JDBC综合实践案例说明文章,敬请期待。https://blog.csdn.net/qq_60735796/article/details/128843095
需求:完成商品品牌数据的增删改查操作(增删改查)
①查询:查询所有数据
②添加:添加品牌
③修改:根据id修改
④删除:根据id删除
最终完成后的工程目录如下:
该工程下的JDBC模块存放此次实践案例的相关文件。
模块下创建了两个文件:lib和src。
lib放的是需要的驱动jar包
src放的是主要实现代码和Druid框架的配置文件druid.properties。
src下有两个二级包,分别为com.operation和com.sql。
①operation包下有两个类:分别是encapsulationTool封装工具类和operations操作类。
encapsulationTool的内容是把表单信息添加进实体类,后续有详细说明
operations是本次的主体,里面包含了所有本次需求的实现代码
②sql包下有两个类:分别是information表单信息类和sqlInitialForMySQL初始化类
information是MySQL中的commodity数据库中的information表的实体类
sqlInitialForMySQL是将JDBC的八个步骤中一些相同的步骤提取出来单独成类来实现,
以达到简化代码量的效果
本次的实践案例连接的是本地的MySQL数据库,所以要记得开启本地的MySQL服务。
如果不开启服务,所有的操作一律报错。
操作:
win+R,cmd,按住Ctrl+Shift+Enter,以管理员模式打开终端。
命令->开启:net start mysql
关闭:net stop mysql
接下来要先创建一个commodity商品类型的数据库,在该数据库中创建一个information表单来存储信息,在information表单中创建具体的表存储信息。如下:
information表中依次存放六种信息:
id:唯一标识,使用主键约束(primary key),设置自动增长(auto_increment);
brand:品牌名称
company:公司名称
sort:排序字段 (注:在本次实践案例中暂时没用上)
description:描述信息
status:状态信息,只有0和1两种,分别代表禁用、启用。 (注:在本次实践案例中暂时没用上)
本次案例实践的驱动包一共有四个:
druid-1.1.12.jar
hamcrest-core-1.3.jar
junit-4.13.1.jar
mysql-connector-java-5.1.48.jar
将上述四个驱动包导入到lib文件夹,并添加到项目依赖中。
Druid和MySQL驱动包的解释,详细查看我的另一篇文章中的 "5、数据库连接池" :
JDBC->Java操作MySQL数据库_︶ㄣ释然的博客-CSDN博客JDBC->超一万字文章带你详细了解Java操作MySQL数据库的各种步骤,后续会更新一篇关于JDBC综合实践案例说明文章,敬请期待。https://blog.csdn.net/qq_60735796/article/details/128843095
junit驱动主要是用来编写单元测试类,代替实践案例中所需要的main方法。
如果不导入hamcrest驱动,使用junit的测试注解会出现问题:
说明:
在原来的JDBC八个步骤中,第一步导入jar包的操作,在一开始已经完成了;
第二部注册驱动,在MySQL 5开始的驱动包中不需要手动注册,会自动扫描驱动
第三步获取连接,原来的获取方式有造成资源浪费的明显缺点,所以由连接池代替
第五步获取执行对象,存在SQL注入漏洞,所以由获取预编译执行对象代替
所以,改进完成之后的JDBC操作为十个步骤:
关于这个配置文件的书写,详细查看我另一篇文章中的 "5.3.2、定义配置文件":
编写src下的com.sql.information实体类,该实体类为一个标准JavaBeen格式。
总共六个参数,分别对应数据库中information表中六列数据。
package com.sql;
public class information {
private int id;
private String brand;
private String company;
private int sort;
private String description;
private int status;
public information() { }
public information(int id, String brand, String company, int sort, String description, int status) {
this.id = id;
this.brand = brand;
this.company = company;
this.sort = sort;
this.description = description;
this.status = status;
}
@Override
public String toString() {
return "information{" +
"id=" + id +
", brand='" + brand + '\'' +
", company='" + company + '\'' +
", sort=" + sort +
", description='" + description + '\'' +
", status=" + status +
'}';
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
public int getSort() {
return sort;
}
public void setSort(int sort) {
this.sort = sort;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
}
sqlInitialForMySQL即是在本文目录中的2.2部分提到过的,将JDBC的实现步骤中一些相同的步骤提取出来单独成类来实现,以达到简化代码量的效果。
sqlInitialForMySQL类实现的是,在本文目录中3.5.2部分提到的"改进后的JDBC步骤"中的第三步到第五步-->加载配置文件、获取连接池对象、获取连接:
package com.sql;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.util.Properties;
public class sqlInitialForMySQL {
public Connection InitialOfOperation() throws Exception {
//注册驱动
//MySQL 5之后的驱动包,可以省略注册驱动的步骤,
//自动加载jar包中META-INF/services/java.sql.Driver文件中的驱动类
//获取Connection,加载配置文件(MySQL的url,username,password均在其中)
Properties properties = new Properties();
properties.load(new FileInputStream("src/druid.properties"));
//获取连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
//获取数据库连接
Connection connection;
connection = dataSource.getConnection();
return connection;
}
}
最终这个类返回的是Connection对象,方便接着调用或者作参传入。
此工具类主要作用是将传进来的六种参数封装成一个information实例对象,方便添加进list集合,使用于selectAll()方法中。
package com.operation;
import com.sql.information;
public class encapsulationTool {
public information tool(information ifm, int id,String brand,
String company, int sort, String description,int status){
ifm.setId(id);
ifm.setBrand(brand);
ifm.setCompany(company);
ifm.setSort(sort);
ifm.setDescription(description);
ifm.setStatus(status);
return ifm;
}
}
operations操作类中是实现了本次需求的增删改查操作。
在这个类里边使用到了com.sql.sqlInitialForMySQL和com.sql.information两个自己编写的类。
下面是operations的全部实现代码。
package com.operation;
import com.sql.sqlInitialForMySQL;
import com.sql.information;
import org.junit.Test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
/**
* JDBC各种操作
*/
public class operations {
public static Connection connection;
/**
* 重点
*/
public encapsulationTool TOOL = new encapsulationTool();
static {//导入写好的类
try {
connection = new sqlInitialForMySQL().InitialOfOperation();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 查询所有
* 1. SQL:select * from information;
* 2. 参数:不需要
* 3. 结果:List
*/
@Test
public void selectAll() throws Exception {
//定义SQL
String sql = "select * from information";
//获取preparedStatement
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//执行SQL
ResultSet resultSet = preparedStatement.executeQuery();
//处理结果
information information = new information();
List list = new ArrayList<>();
while (resultSet.next()) {
int id = resultSet.getInt("id");
String brand = resultSet.getString("brand");
String company = resultSet.getString("company");
int sort = resultSet.getInt("sort");
String description = resultSet.getString("description");
int status = resultSet.getInt("status");
//封装information对象
information = TOOL.tool(information, id, brand, company, sort, description, status);
list.add(information);
System.out.println(list);
}
resultSet.close();
preparedStatement.close();
connection.close();
}
/**
* 添加数据
* 1. SQL:insert into information(brand_name,company_name,
* ordered, description, status) values(?,?,?,?,?);
* 2. 参数:需要,除了id之外的所有参数信息
* 3. 结果:boolean
*/
@Test
public void insert() throws Exception {
String brand = "香飘飘";
String company = "香飘飘公司";
int sort = 1;
String description = "香飘飘是香飘飘食品股份有限公司旗下杯装奶茶品牌,成立于2005年";
int status = 1;
String sql = "insert into information(brand,company,sort,description,status) " +
"values (?,?,?,?,?)";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
try (preparedStatement) {
preparedStatement.setString(1, brand);
preparedStatement.setString(2, company);
preparedStatement.setInt(3, sort);
preparedStatement.setString(4, description);
preparedStatement.setInt(5, status);
connection.setAutoCommit(false);
preparedStatement.executeUpdate();
connection.commit();
selectAll();
} catch (Exception e) {
connection.rollback();
e.printStackTrace();
} finally {
connection.close();
}
}
/**
* 修改数据
* 1. SQL:update information set
* brand_name = ?,company_name= ?,
* ordered = ?,description = ?,status = ?
* where id = ?
* 2. 参数:需要,所有数据
* 3. 结果:boolean
*/
@Test
public void update() throws Exception {
int id = 4;
String brand = "香飘飘";
String company = "香飘飘";//作出修改
int sort = 1000;//做出修改
String description = "绕地球三圈";
int status = 1;
String sql = "update information set brand=?,company=?,sort=?,description=?,status=?" +
" where id=? ";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
try (preparedStatement) {
preparedStatement.setString(1, brand);
preparedStatement.setString(2, company);
preparedStatement.setInt(3, sort);
preparedStatement.setString(4, description);
preparedStatement.setInt(5, status);
preparedStatement.setInt(6, id);
connection.setAutoCommit(false);
preparedStatement.executeUpdate();
connection.commit();
selectAll();
} catch (Exception e) {
connection.rollback();
e.printStackTrace();
} finally {
connection.close();
}
}
/**
* 删除数据
* 1. SQL:delete from information where id = ?
* 2. 参数:需要,id
* 3. 结果:boolean
*/
@Test
public void delete() throws Exception {
//删除第四条数据"香飘飘"
int id = 4;
String sql = "delete from information where id = ?";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
try (preparedStatement) {
preparedStatement.setInt(1, id);
connection.setAutoCommit(false);
preparedStatement.executeUpdate();
connection.commit();
selectAll();
} catch (Exception e) {
connection.rollback();
e.printStackTrace();
} finally {
connection.close();
}
}
}
在operations中的各个方法,使用了事务管理机制。使用try-with-resource,自动释放资源,在try中设置事务管理,在catch中设置事务回滚,在finally中设置资源释放,避免出现死锁占用资源
在operations类中的开头部分,使用静态代码块加载connection连接,跟随本类一起加载,自始至终只有一个对象,节约了性能
该方法是获取commodity数据库中information表中的信息。
/**
* 查询所有
* 1. SQL:select * from information;
* 2. 参数:不需要
* 3. 结果:List
*/
@Test
public void selectAll() throws Exception {
//定义SQL
String sql = "select * from information";
//获取preparedStatement
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//执行SQL
ResultSet resultSet = preparedStatement.executeQuery();
//处理结果
information information = new information();
List list = new ArrayList<>();
while (resultSet.next()) {
int id = resultSet.getInt("id");
String brand = resultSet.getString("brand");
String company = resultSet.getString("company");
int sort = resultSet.getInt("sort");
String description = resultSet.getString("description");
int status = resultSet.getInt("status");
//封装information对象
information = TOOL.tool(information, id, brand, company, sort, description, status);
list.add(information);
System.out.println(list);
}
resultSet.close();
preparedStatement.close();
connection.close();
}
该方法是往commodity数据库中information表中添加信息,可批量添加也可依次添加。
/**
* 添加数据
* 1. SQL:insert into information(brand_name,company_name,
* ordered, description, status) values(?,?,?,?,?);
* 2. 参数:需要,除了id之外的所有参数信息
* 3. 结果:boolean
*/
@Test
public void insert() throws Exception {
String brand = "香飘飘";
String company = "香飘飘公司";
int sort = 1;
String description = "香飘飘是香飘飘食品股份有限公司旗下杯装奶茶品牌,成立于2005年";
int status = 1;
String sql = "insert into information(brand,company,sort,description,status) " +
"values (?,?,?,?,?)";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
try (preparedStatement) {
preparedStatement.setString(1, brand);
preparedStatement.setString(2, company);
preparedStatement.setInt(3, sort);
preparedStatement.setString(4, description);
preparedStatement.setInt(5, status);
connection.setAutoCommit(false);
preparedStatement.executeUpdate();
connection.commit();
selectAll();
} catch (Exception e) {
connection.rollback();
e.printStackTrace();
} finally {
connection.close();
}
}
该方法是修改commodity数据库中information表中的信息,以唯一标识id号为限制条件
/**
* 修改数据
* 1. SQL:update information set
* brand_name = ?,company_name= ?,
* ordered = ?,description = ?,status = ?
* where id = ?
* 2. 参数:需要,所有数据
* 3. 结果:boolean
*/
@Test
public void update() throws Exception {
int id = 4;
String brand = "香飘飘";
String company = "香飘飘";//作出修改
int sort = 1000;//做出修改
String description = "绕地球三圈";
int status = 1;
String sql = "update information set brand=?,company=?,sort=?,description=?,status=?" +
" where id=? ";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
try (preparedStatement) {
preparedStatement.setString(1, brand);
preparedStatement.setString(2, company);
preparedStatement.setInt(3, sort);
preparedStatement.setString(4, description);
preparedStatement.setInt(5, status);
preparedStatement.setInt(6, id);
connection.setAutoCommit(false);
preparedStatement.executeUpdate();
connection.commit();
selectAll();
} catch (Exception e) {
connection.rollback();
e.printStackTrace();
} finally {
connection.close();
}
}
该方法是删除commodity数据库中information表中的信息,以唯一标识id号为限制条件
/**
* 删除数据
* 1. SQL:delete from information where id = ?
* 2. 参数:需要,id
* 3. 结果:boolean
*/
@Test
public void delete() throws Exception {
//删除第四条数据"香飘飘"
int id = 4;
String sql = "delete from information where id = ?";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
try (preparedStatement) {
preparedStatement.setInt(1, id);
connection.setAutoCommit(false);
preparedStatement.executeUpdate();
connection.commit();
selectAll();
} catch (Exception e) {
connection.rollback();
e.printStackTrace();
} finally {
connection.close();
}
}
关于自己编写的封装工具类TOOL的使用,一开始写的是:
public encapsulationTool TOOL;
即只声明了对象,但是没有初始化,此时调用Tool.tool会报空指针异常,初始化Tool对象后则解决:
在创建包的时候,出现了如下的现象:
即:com.operation.selectAll本来应该创建的是一个在二级包下的Java类selectAll,但是这个地方却出现了三级包名,并未创建Java类。
解决方法:
将此处的Compact Middle Packages取消勾选,即可解决。
在使用junit时,要同时导入hamcrest驱动包,否则报异常。