目录
1、在src里面创建一个文件,命名为:database.properties
2、定义实体类:实体类的表名与数据库的表名一致,表中大每一列为实体类的属性
4、由不同数据库的实现类分别实现接口;实现类实现接口并继承数据库工具类
5、将通用的操作(如打开、关闭连接等)封装到工具类数据库工具类
在编写JDBC时存在一些问题:
1、可读性差
2、不利于后期维护和修改
3、不利于代码复用
采用面向接口编程,可以降低代码间的耦合性
JDBC封装:
1、隔离业务逻辑代码和数据访问代码
2、隔离不同数据库的实现
JDBC封装的步骤:
1、定义实体类传输数据
2、将所有增删改查操作抽取
3、由不同数据库的实现类分别实现接口
4、将通用的操作(打开,关闭连接,增删改查等)封装到数据库工具类BaseDao的通用方法中
具体实现:
1、在src里面创建一个文件,命名为:database.properties
然后在里面添加一下数据
# 加载驱动
driver = com.mysql.jdbc.Driver
# 数据库地址
url = jdbc:mysql://127.0.0.1:3306/myschool
#用户名
username = root
#密码
password = root
2、定义实体类:实体类的表名与数据库的表名一致,表中大每一列为实体类的属性
//创建一个年纪类
public class Grade {
/**
* 年纪编号
*/
private int gradeId;
/**
* 年假名称
*/
private String gradeName;
public Grade() {
}
public Grade(int gradeId, String gradeName) {
this.gradeId = gradeId;
this.gradeName = gradeName;
}
/**
* 获取
* @return gradeId
*/
public int getGradeId() {
return gradeId;
}
/**
* 设置
* @param gradeId
*/
public void setGradeId(int gradeId) {
this.gradeId = gradeId;
}
/**
* 获取
* @return gradeName
*/
public String getGradeName() {
return gradeName;
}
/**
* 设置
* @param gradeName
*/
public void setGradeName(String gradeName) {
this.gradeName = gradeName;
}
@Override
public String toString() {
return "Grade{gradeId = " + gradeId + ", gradeName = " + gradeName + "}";
}
}
数据库如下图:
3、将用户对象的所有操作抽取成接口
/**
* @authorDesc 乾坤未定, 你我皆是黑马.乾坤已定, 那就扭转乾坤
* @author
* @date 2022-09-12 21:35:49
* @version 1.0.0
* @description 将年纪对象的所有操作抽取成接口
* 实现对数据库的增删改查
*/
public interface GradeDao {
/**
* @description 查询班级信息
* key为空查询所有班级信息
* key有值,根据key值进行模糊查询
* @author
* @date 2022-09-09 11:41:14
* @param key 进行模糊查询的关键字
* @return {@link List< Grade>}
*/
List<Grade> getALL(String key);
/**
* @description 添加数据
* @author
* @date 2022-09-09 11:41:18
* @param grade 年纪对象
* @return {@link int}
*/
int insertGrade(Grade grade);
/**
* @description 修改数据
* @author
* @date 2022-09-09 11:41:23
* @param grade 年纪对象
* @return {@link int}
*/
int updateGrade(Grade grade);
/**
* @description 删除数据
* @author
* @date 2022-09-09 11:41:26
* @param gradeId 年纪ID
* @return {@link int}
*/
int deleteGrade(int gradeId);
}
4、由不同数据库的实现类分别实现接口;实现类实现接口并继承数据库工具类
/**
* @authorDesc 乾坤未定, 你我皆是黑马.乾坤已定, 那就扭转乾坤
* @author 齐孟伟
* @date 2022-09-12 21:58:38
* @version 1.0.0
* @description 数据库的实现类分别实现接口
*/
public class GradeDaoImpl extends BaseDao implements GradeDao {
/**
* @description 查询班级信息
* key为空查询所有班级信息
* key有值,根据key值进行模糊查询
* @author
* @date 2022-09-09 11:41:14
* @param key 进行模糊查询的关键字
* @return {@link List< Grade>}
*/
@Override
public List<Grade> getALL(String key) {
//sql语句
String sql = "SELECT * FROM GRADE WHERE GRADENAME LIKE CONCAT('%',?,'%')";
//将获取的key放进数组
Object [] obj = {key};
//处理返回结果
ResultSet resultSet = this.select(sql,obj);
//创建年纪对象
Grade grade = null;
//创建数组用来存储年纪对象
List<Grade> gradeList = new ArrayList<>();
try{
//resultSet.next():判断返回结果是否有值
while (resultSet.next()){
grade = new Grade();
//获取数据库表的内容,这里的1可以是获取到表的列名,1表示第一列,2,表是第二列要有顺序
grade.setGradeId(resultSet.getInt(1));
grade.setGradeName(resultSet.getString(2));
gradeList.add(grade);
}
}catch (Exception e){
e.printStackTrace();
}finally {
//关闭资源
this.close(resultSet);
}
return gradeList;
}
/**
* @description 添加数据
* @author
* @date 2022-09-09 11:41:18
* @param grade 年纪对象
* @return {@link int}
*/
@Override
public int insertGrade(Grade grade) {
//sql语句
String sql = "INSERT INTO GRADE(GRADEID, GRADENAME) VALUES (?,?)";
//将对象的属性值添加到 数组中
Object [] obj = {grade.getGradeId(),grade.getGradeName()};
//调用 添加数据的方法
return this.update(sql,obj);
}
/**
* @description 修改数据
* @author
* @date 2022-09-09 11:41:23
* @param grade 年纪对象
* @return {@link int}
*/
@Override
public int updateGrade(Grade grade) {
//sql语句
String sql = "UPDATE GRADE SET GRADENAME = ? WHERE GRADEID = ?";
//将对象的属性值添加到 数组中
Object [] obj = {grade.getGradeName(),grade.getGradeId()};
//调用 添加数据的方法
return this.update(sql,obj);
}
/**
* @description 删除数据
* @author
* @date 2022-09-09 11:41:26
* @param gradeId 年纪ID
* @return {@link int}
*/
@Override
public int deleteGrade(int gradeId) {
//sql语句
String sql = "DELETE FROM GRADE WHERE GRADEID = ?";
//将对象的属性值添加到 数组中
Object [] obj = {gradeId};
//调用 添加数据的方法
return this.update(sql,obj);
}
}
5、将通用的操作(如打开、关闭连接等)封装到工具类数据库工具类
对BaseDao:增、删、改的通用方法
/**
* @authorDesc 乾坤未定, 你我皆是黑马.乾坤已定, 那就扭转乾坤
* @author
* @date 2022-09-12 22:01:34
* @version 1.0.0
* @description 将通用的操作(如打开、关闭连接等)封装到工具类
*/
public class BaseDao {
/**
* 获取驱动
*/
Connection connection = null;
/**
* 连接数据库并进行操作
*/
PreparedStatement preparedStatement = null;
/**
* 处理返回结果
*/
ResultSet resultSet = null;
/**
* @description 获取驱动
* @author
* @date 2022-09-09 11:50:58
* @param
* @return {@link Connection}
*/
public Connection getConnection(){
//根据指定的键获取对应的值
DataSourceConfig dataSourceConfig = new DataSourceConfig();
// 获取驱动
String driver = dataSourceConfig.getProperty("driver");
// 获取数据库地址
String url = dataSourceConfig.getProperty("url");
// 获取用户名
String username = dataSourceConfig.getProperty("username");
// 获取密码
String password = dataSourceConfig.getProperty("password");
try {
//加载驱动
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection(url,username,password);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return connection;
}
/**
* @description 查询班级信息
* key为空查询所有班级信息
* key有值,根据key值进行模糊查询
* @author
* @date 2022-09-09 11:54:58
* @param sql sql语句
* @param obj key值
* @return {@link ResultSet}
*/
public ResultSet select(String sql, Object[] obj){
this.getConnection();
try {
preparedStatement = connection.prepareStatement(sql);
//若传过来obj不为空,则解析参数集合
if (obj != null && obj.length > 0){
for (int i = 0; i < obj.length; i++) {
//对问号传参
preparedStatement.setObject((i + 1),obj[i]);
}
}
resultSet = preparedStatement.executeQuery();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return resultSet;
}
/**
* @description 对数据进行添加修改删除
* @author
* @date 2022-09-09 11:57:54
* @param sql sql语句
* @param obj key值
* @return {@link int}
*/
public int update(String sql, Object[] obj){
//
this.getConnection();
int count = 0;
try {
preparedStatement = connection.prepareStatement(sql);
if (obj != null && obj.length > 0){
for (int i = 0; i < obj.length; i++) {
preparedStatement.setObject((i + 1),obj [i]);
}
}
count = preparedStatement.executeUpdate();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
close(resultSet);
}
return count;
}
/**
* @description 关闭资源
* @author
* @date 2022-09-12 22:00:57
* @param res
* @return
*/
public void close(ResultSet res){
try {
if (res != null){
res.close();
}
if (resultSet != null){
resultSet.close();
}
if (preparedStatement != null){
preparedStatement.close();
}
if (connection != null){
connection.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
6、在测试类进行测试
/**
* @authorDesc 乾坤未定, 你我皆是黑马.乾坤已定, 那就扭转乾坤
* @author 齐孟伟
* @date 2022-09-12 22:20:56
* @version 1.0.0
* @description 测试类
*/
public class SchoolSystemApplication {
public static void main(String[] args) {
GradeDao gradeDao = new GradeDaoImpl();
/**
* 查询
*/
select("",gradeDao);
/**
* 添加数据
*/
Grade grade = new Grade(6,"第六阶段");
gradeDao.insertGrade(grade);
select("",gradeDao);
/**
* 修改数据
*/
// 获取所有的对象
List<Grade> gradeList = gradeDao.getALL("");
// 遍历数组
for (int i = 0; i < gradeList.size(); i++) {
if (gradeList.get(i).getGradeId() == 6){
int gradeId = gradeList.get(i).getGradeId();
String gradeName = "高三";
Grade grade1 = new Grade(gradeId,gradeName);
gradeDao.updateGrade(grade1);
}
}
select("",gradeDao);
/**
* 删除数据
*/
gradeDao.deleteGrade(6);
select("",gradeDao);
}
/**
* @description 遍历集合里的信息
* @author
* @date 2022-09-12 22:21:10
* @param key key值
* @param gradeDao
* @return
*/
public static void select(String key,GradeDao gradeDao){
List<Grade> gradeList = gradeDao.getALL(key);
for (int i = 0; i < gradeList.size(); i++) {
System.out.println(gradeList.get(i).toString());
}
System.out.println("______________________");
}
}
7、单例模式
Java中提供了Properties类来读取配置文件
方法名 | 说明 |
void load(InputStream inStream) | 通过输入流对指定文件进行装载,获取该文件中所有键-值对。 |
String getProperty(String key) | 用指定的键在此属性列表中搜索属性。通过参数key得到其所对应的值。 |
读取配置文件,单独放在一个utils包里
/**
* @authorDesc 乾坤未定, 你我皆是黑马.乾坤已定, 那就扭转乾坤
* @author
* @date 2022-09-10 10:47:31
* @version 1.0.0
* @description 数据库配置类---读取数据库连接配置
*/
public class DataSourceConfig {
/**
* 以类名声明的此类对象
*/
private static DataSourceConfig dataSourceConfig = null;
Properties properties = null;
/**
* @description
* @author
* @date 2022-09-10 10:48:02
* @param
* @return {@link null}
*/
public DataSourceConfig(){
properties = new Properties();
//配置文件路径
String configFile = "database.properties";
//加载配置文件到输入流
InputStream inputStream = DataSourceConfig.class.getClassLoader().getResourceAsStream(configFile);
try {
//从输入流中读取属性列表
properties.load(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* @description DataSourceConfig判定是否已经被创建
* 如果创建过,直接返回
* 如果没有,创建后返回
* @author
* @date 2022-09-10 10:45:49
* @param
* @return {@link DataSourceConfig}
*/
public synchronized static DataSourceConfig getInstance(){
if (dataSourceConfig == null){
dataSourceConfig = new DataSourceConfig();
}
return dataSourceConfig;
}
/**
* @description Properties对象根据传递的key值返回对应的value值
* @author
* @date 2022-09-10 10:45:55
* @param key
* @return {@link String}
*/
public String getProperty(String key){
String value = properties.getProperty(key);
return value;
}
}
读取配置文件,把获取驱动部分改为以下代码即可
/**
* @description 获取驱动
* @author
* @date 2022-09-10 10:52:34
* @param
* @return {@link Connection}
*/
public Connection getConnection(){
//根据指定的键获取对应的值
DataSourceConfig dataSourceConfig = new DataSourceConfig();
String driver = dataSourceConfig.getProperty("driver");
String url = dataSourceConfig.getProperty("url");
String username = dataSourceConfig.getProperty("username");
String password = dataSourceConfig.getProperty("password");
try {
//加载驱动
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection(url,username,password);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return connection;
}
此模式称为单例模式:系统运行期间,有且仅有一个实例
1、它必须自行创建这个实例
2、定义了静态的该类私有对象
3、一个类只有一个实例——最基本的要求
4、只提供私有构造器
5、它必须自行向整个系统提供这个实例
6、提供一个静态的公有方法,返回创建或者获取本身的静态私有对象
懒汉模式:在类加载时不创建实例,采用延迟加载的方式,在运行调用时创建实例。
/**
* @authorDesc 乾坤未定, 你我皆是黑马.乾坤已定, 那就扭转乾坤
* @author
* @date 2022-09-17 16:43:22
* @version 1.0.0
* @description 懒汉模式:在类加载时不创建实例,采用延迟加载的方式,在运行调用时创建实例。
*/
public class DataScoreConfig {
/**
* DataSourceConfig类的声明
*/
private static DataScoreConfig dataScoreConfig = null;
/**
* Properties类的文件处理引用
*/
Properties properties = null;
/**
* @description 私有话构造方法
* @author
* @date 2022-09-17 16:53:13
* @param
* @return {@link null}
*/
public DataScoreConfig(){
properties = new Properties();
String configFile = "database.properties";
InputStream inputStream = DataScoreConfig.class.getClassLoader().getResourceAsStream(configFile);
try {
properties.load(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* @description
* 查看dataSourceConfig是否为空
* 为空则重新创建引用
* 不为空直接返回
* @author
* @date 2022-09-17 16:53:05
* @param
* @return {@link DataScoreConfig}
*/
public static synchronized DataScoreConfig getInstance(){
if (dataScoreConfig == null){
dataScoreConfig = new DataScoreConfig();
}
return dataScoreConfig;
}
/**
* @description
* 通过properties对象的getProperty方法
* 获取database.properties文件中的对应可以的值
* @author
* @date 2022-09-17 16:53:01
* @param key
* @return {@link String}
*/
public String getProperty(String key){
String value = properties.getProperty(key);
return value;
}
饿汉模式:在类加载的时候,就完成初始化
/**
* @authorDesc 乾坤未定, 你我皆是黑马.乾坤已定, 那就扭转乾坤
* @author
* @date 2022-09-17 16:43:22
* @version 1.0.0
* @description 饿汉模式:在类加载的时候,就完成初始化
*/
public class DataScoreConfig {
/**
* DataSourceConfig类的声明
*/
private static DataScoreConfig dataScoreConfig = new DataScoreConfig;
/**
* Properties类的文件处理引用
*/
Properties properties = null;
/**
* @description 私有话构造方法
* @author
* @date 2022-09-17 16:53:13
* @param
* @return {@link null}
*/
public DataScoreConfig(){
properties = new Properties();
String configFile = "database.properties";
InputStream inputStream =
DataScoreConfig.class.getClassLoader().getResourceAsStream(configFile);
try {
properties.load(inputStream);
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* @description
* 查看dataSourceConfig是否为空
* 为空则重新创建引用
* 不为空直接返回
* @author
* @date 2022-09-17 16:53:05
* @param
* @return {@link DataScoreConfig}
*/
public static DataScoreConfig getInstance(){
return dataScoreConfig;
}
/**
* @description
* 通过properties对象的getProperty方法
* 获取database.properties文件中的对应可以的值
* @author
* @date 2022-09-17 16:53:01
* @param key
* @return {@link String}
*/
public String getProperty(String key){
String value = properties.getProperty(key);
return value;
}
注意: 在整个程序运行期间,有且仅有一个实例。若违背这一点,所设计的类就不是单例类
单例模式 | 懒汉模式 | 饿汉模式 |
概念 | 在类加载时不创建实例,采用延迟加载的方式,在运行调用时创建实例 | 在类加载的时候,就完成初始化 |
特点 | 类加载速度快,但是运行时获取对象的速度较慢。——“时间换空间” | 类加载较慢,但获取对象速度快。——“空间换时间” |
延迟加载 | 具备 | 不具备 |
线程安全 | 线程不安全,解决方法使用同步(synchronized) | 线程安全 |