1.封装DBUtils
为什么要进行JDBC封装?
主要是因为业务代码和数据访问代码的耦合。这就导致了可读性差、不利于后期修改和维护、不利于代码复用。
所以我们采用面向接口编程,可以降低代码之间的耦合性。
将对宠物的所有操作抽取成接口:
package com.qf.dao;
import java.util.List;
import com.qf.bean.Dog;
public interface IDogDao {
/**
* 添加宠物
* @param dog
* @return
*/
public int insert(Dog dog);
/**
* 删除宠物
* @param id
* @return
*/
public int delete(int id);
/**
* 修改的方法
* @param dog
* @return
*/
public int update(Dog dog);
/**
* 查询的方法
* @return
*/
public List find();
}
在我们的实现类中基本上每个方法中都有数据库连接信息,执行的操作,关闭数据连接的一些资源,那么这些通用的方法和操作是否能进一步简化呢?这里我们就可以自己动手把相同或者类似的方法抽取出来封装成一个Dbutils的工具类。
package com.qf.util;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
* JDBC封装的工具类
* @author chenxuewen
*
*/
public class Dbutils {
//一些我们需要使用到的基本常量
private static final String driver = "com.mysql.jdbc.Driver";
private static final String url = "jdbc:mysql://localhost:3306/pet";
private static final String user = "root";
private static final String password = "root";
//每次都会加载驱动,所以,我们把这个方法放到一个静态代码块中
//每次调用这个类都会主动加载
static {
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//获取连接对象的方法
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, user, password);
}
// 关闭资源 1.结果集 2.命令对象 3.链接
public static void close(ResultSet resultSet,Statement statement,Connection connection) {
if(resultSet!=null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(statement!=null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(connection!=null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
再来看看封装后的实现类的代码:
public int update(Dog dog) {
Connection connection = null;
Statement statement = null;
try {
// 获取链接对象
connection = Dbutils.getConnection();
// 创建命令对象
statement = connection.createStatement();
// 执行命令,返回结果
int result = statement.executeUpdate("update dog set name='"+dog.getName()+"',health="+dog.getHealth()+",love="+dog.getLove()+",kind='"+dog.getKind()+"' where id="+dog.getId()+"");
return result;
} catch (Exception e) {
e.printStackTrace();
}finally {
Dbutils.close(null, statement, connection);
}
return 0;
}
这时,我们需要学习PreparedStatement,这个类继承了Statement类。因为Statement会造成很严重的数据库注入SQL语句安全问题,所以以后的编程过程中,我们都需要使用PreparedStatement类,不能使用Statement。
1.声明PreparedStatement:
PreparedStatement pStatement = null;
2.使用占位符:
String sql = “update dog set name=?,health=?,love=? where id=?”;
3.创建命令对象
pStatement = connection.prepareStatement(sql);
4.设置每个占位符的值,这里需要按照先后顺序输入值,并且注意类型
pStatement.setString(1,dog.getName);
pStatement.setInt(2,dog.getHealth);
pStatement.SetInt(3,dog.getLove);
pStatement.SetInt(4,dog.getId);
5.执行SQL语句
int result = pStatement.executeUpdate();
进一步的抽取我们的实现类里面的共有方法,增删改的方法类似,我们抽取出来写到Dbutils类里:
// 增删改的方法
public static int executeUpdate(String sql, Object[] params) {
Connection connection = null;
PreparedStatement pStatement = null;
// 执行命令,返回结果
int result;
try {
// 获取链接对象
connection = Dbutils.getConnection();
// 创建命令对象
pStatement = connection.prepareStatement(sql);
for (int i = 0; i < params.length; i++) {
pStatement.setObject(i + 1, params[i]);
}
result = pStatement.executeUpdate();
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
close(null,pStatement,connection);
}
return result;
}
这时,我们的实现类中的方法只需要传入两个参数,并调用Dbutils中的方法就行了。
//实现类中修改宠物的方法
public int update(Dog dog) {
String sql = "update pet set name=?,health=?,love=?,kind=? where=?";
Object[] params = {dog.getName(),dog.getHealth(),dog.getLove(),dog.getKind(),dog.getId()};
return Dbutils.executeUpdate(sql, params);
}
注意:查询的方法和增删改的方法不一样,暂时还不需要修改我们的查询方法。
什么是DAO?
DAO模式是非常流行的数据访问模式。 位于业务逻辑和持久化数据之间。 实现对持久化数据的访问。
DAO模式的组成部分:
DAO接口、DAO实现类、实体类、数据库连接和关闭工具类
3.DAO层作用:
数据访问和业务逻辑分离,便于数据维护,业务逻辑不需要了解访问细节,如数据源是数据库、文件、还是XML ,隔离了不同数据库实现。
4.数据持久化:
将程序中的数据在瞬时状态和持久状态间转换的机制。持久化的实现方式:数据库、普通文件、XML文件
为什么要使用Properties类,主要是让用户脱离程序本身修改相关变量设置-----使用配置文件。
Java中的配置文件常为Properties文件,后缀为.properties,格式是“键=值”格式,使用“#”来注释。
Java中提供了Properties类来读取配置文件。
我们可以通过配置一个preperty文件,就不需要修改代码,从而修改配置文件就行了。
首先创建一个.properties为后缀的文件。
驱动
driver=com.mysql.jdbc.Driver
url url=jdbc:mysql://localhost:3306/pet1
用户名
user=root
密码
password=root
读取配置文件时:
1》在静态代码块中调用,类加载时执行
2》配置文件路径
3》加载配置文件到输入流中
4》从输入流中读取属性列表
5》根据指定的键获取对应的值
完成后的Dbutils:
package com.qf.util;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
/**
* JDBC封装的工具类
*
* @author chenxuewen
*
*/
public class Dbutils {
// 一些我们需要使用到的基本常量
private static String driver;
private static String url;
private static String user;
private static String password;
// 每次都会加载驱动,所以,我们把这个方法放到一个静态代码块中
// 每次调用这个类都会主动加载
static {
try {
//读取配置文件内容,,使用.properties的目的:
//1.util包提供了properties类.load方法可以直接获取配置文件中的字节流
//2.避免路径问题
Properties properties = new Properties();
//获取流的方法。
InputStream is = Dbutils.class.getClassLoader().getResourceAsStream("database.properties");
//加载流
properties.load(is);
//赋值,这里括号中的值需要和配置文件中的键相同;
driver = properties.getProperty("driver");
url=properties.getProperty("url");
user=properties.getProperty("user");
password=properties.getProperty("password");
//加载驱动
Class.forName(driver);
} catch (Exception e) {
e.printStackTrace();
}
}
// 获取连接对象的方法
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, user, password);
}
// 增删改的方法
public static int executeUpdate(String sql, Object[] params) {
Connection connection = null;
PreparedStatement pStatement = null;
// 执行命令,返回结果
int result;
try {
// 获取链接对象
connection = Dbutils.getConnection();
// 创建命令对象
pStatement = connection.prepareStatement(sql);
for (int i = 0; i < params.length; i++) {
pStatement.setObject(i + 1, params[i]);
}
result = pStatement.executeUpdate();
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
close(null,pStatement,connection);
}
return result;
}
// 关闭资源 1.结果集 2.命令对象 3.链接
public static void close(ResultSet resultSet, Statement statement, Connection connection) {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
软件系统的三层架构:
用户请求----》表示层(UI、web)-----》业务逻辑层(BLL)-----》数据访问层(DAO,持久层)
分层原则:
每个层次向外公开接口,但是隐藏内部细节。
顺序访问原则:下一层为上一层服务,但是不使用上一层的服务。
分层结构中,不同层之间是通过我们定义的实体类来进行传输数据的。
分层的特点:
每一层都有自己的职责
上一层不用关心下一层的实现细节,上一层通过下一层提供的对外接口来使用其功能
上一层调用下一层的功能,下一层不能调用上一层功能
分层开发的优势:
代码复用
分离开发人员的关注
无损替换
降低了系统间的依赖