一.数据库连接池
1.传统的数据库连接方式存在的问题
普通的JDBC数据库连接池采用的是DriverManager来获取连接,
每次都需要向数据库建立连接,而建立连接的同时需要将Connection加载到内存
然后在验证账号和密码是否正确,需要连接的时候就向数据库索要一次Connection
对象而每次都需要验证账号和密码是否正确,这个验证是非常的占用时间的,大约在【0.4~1.0】秒之间。
若同时几千人在线,频繁的对数据库进行连接操作,将占用大量的系统资源,
严重的可能造成服务器宕机。
2.数据库连接池的基本思想
1.数据库连接之初预先建立在一个 "缓冲池",在这个池子中预先放入一定数量的连接。
当需要连接数据库时,只需要从 "缓冲池" 中取一个,使用完毕之后再放回去。
2.数据库连接池负责分配、管理、释放数据库连接,它允许程序重复使用一个现有的数据库
连接而不是重新创建一个。
初始化连接数:
数据库连接池在初始化时,会创建一定数量的连接,放入到连接池中,这些
数据库连接的数量是由初始化连接数来确定的。
无论这些数据库连接是否被使用,连接池都将保证至少拥有这些数量的连接对象。
最大活跃连接数:
连接的池最大数据库连接数量限定了这个连接池能占有的最大连接对象。
最大等待时长:
当程序向连接池请求连接数超过了最大连接数量时,这些请求将被加入到等待队列中。
3.常用连接池
-
DBCP
DataBase Connection Pool 数据库连接池 它是Apache组织下,开源的一个免费项目。 Apache组织: Apache软件基金会(也就是 Apache Software Foundation,简称 ASF),是专门为支持开源软件项目而办的一个非盈利性组织。在它所支持的 Apache 项目与子项目中,所发行的软件产品都遵循 Apache 许可证(Apache License)。
-
Druid
阿里巴巴开源项目,俗称德鲁伊。 由阿里巴巴团队负责维护和开发。
4.Druid的开发
1.导包: druid-1.1.14.jar mysql-connector-java-5.1.7-bin.jar
二.三层架构
1.什么是三层架构?
三层架构是一种程序设计结构,使用分层式策略将整个应用分为三层:
1.表示层
2.业务逻辑层
3.数据访问层
分层的目的:
实现高内聚,低耦合。
高内聚:
每一层都相互调用。并且相互不受影响。
在调用过程中,调用者不需要了解被调用者的底层细节。
低耦合:
当被调用者的底层细节发生了根本性的变化
不会影响调用者。
三层架构整体思想:
每一层分工明确,相互独立,任何一层发生任何修改都与其他层没有任何关系。
每一层都不该出现其它层的技术。
2.每一层的含义
1.表示层,也称为显示层【view】
用于实现和系统用户进行数据交互。
向用户展示数据,如网页,导出文件,显示表格,提供表单录入信息...
2.业务逻辑层,也称为业务层【service】
用于实现具体的逻辑功能。
它承担承上启下的作用。
它可以接收由表示层传入的数据,然后分析数据来决定是否调用
数据层。
它可以接收由数据层传回来的数据,然后根据数据来决定返回哪一个表示层。
3.数据访问层,也称为【dao】
用于实现对数据的访问操作,即数据的持久化操作。
可以接收来自于业务层的调用,来根据业务层传进来的数据
来到数据库进行 增 删 改 查一系列操作。然后将结果集返回给业务层。
三.DAO
1.什么DAO?
Data Access Object【数据访问对象】
调用者【service】不需要了解底层的数据访问细节就可以实现对数据的访问。
这样一来当底层的访问细节发生了编号,不会影响到service层。
2.如何写一个DAO?
1.实体类
为了方便处理数据库中的记录,可以定义与巨鹿对应的实体类,
即可以将数据库中的某条记录转换成实体类的一个实例对象。
比如 Student 类,提供与表中列相关属性及相关的get/set方法。
我们就可以将数据库中 student 表 映射成Student类。
实体类简称:pojo entity domain
实体类创建的规范:
一般为:公司域名倒写 + 模块名称 + domain + 映射于表的名称。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NFMVMsEY-1657536151311)(image/image-20220704120247625.png)]
2.dao接口
声明一些数据访问方法,这些方法不需要涉及具体的技术。
主要是用于应用的数据功能。
比如:
a)根据学生的姓名模糊查询学生的信息。
b)根据学号查询学生的信息。
.....
创建dao接口的规范:
公司域名倒写 + 模块名称 + dao + 实体类名Dao
3.dao实现类
采用具体的技术来实现dao接口
比如:
使用 JDBC Mybatis Hibernater 及其它映射框架。
创建dao实现类的规范:
公司域名倒写 + 模块名称 + dao + impl + 实体类名DaoImpl
4.dao工厂
封装了对象的创建细节。为调用者提供符合要求的dao对象。
本质上是为数据层进行高内聚、低耦合做粘合作用。
为接口动态提供不同的实现类对象。
创建一个工厂类:ObjectFactory
四.雇员管理系统
雇员管理系统可以管理员工和部门。
对员工和部门进行增删改查。
员工与部门是一对多关系。
员工功能:
1.根据雇员的雇员编号查询雇员信息。
2.根据雇员的工资范围查询雇员信息。
3.增加一个新员工
4.修改员工的信息
5.根据员工编号删除员工
6.根据部门编号查询部门员工
部门功能:
1.添加部门
2.删除部门
3.修改部门
4.查询所有部门
5.根据部门编号查询部门
6.根据部门名称模糊查询部门信息。
实体类
public Emp(int empno, String ename, String job, int mgr, Date hiredate, double sal, int comm, int deptno) {
this.empno = empno;
this.ename = ename;
this.job = job;
this.mgr = mgr;
this.hiredate = hiredate;
this.sal = sal;
this.comm = comm;
this.deptno = deptno;
}
DAO层增删改查操作 (1-4)
public class EmpDaoJdbcImpl implements EmpDao {
@Override
public Emp selectByEmpno(int empno) throws SQLException {
// 1.获取连接
Connection conn = JdbcUtil.getConnection();
// 2.获取预编译对象
String sql = "select * from emp where empno = ?";
PreparedStatement ps = conn.prepareStatement(sql);
//3. 设置占位符
ps.setInt(1, empno);
//4. 执行sql语句
ResultSet rs = ps.executeQuery();
//5. 处理结果集
Emp emp = new Emp();
while (rs.next()) {
/*
遍历,将数据库查询出来的结果,放入实体类中
*/
emp.setEmpno(rs.getInt(1));
emp.setEname(rs.getString(2));
emp.setJob(rs.getString(3));
emp.setMgr(rs.getInt(4));
emp.setHiredate(rs.getDate(5));
emp.setSal(rs.getDouble(6));
emp.setComm(rs.getInt(7));
emp.setDeptno(rs.getInt(8));
}
//6. 释放资源
rs.close();
ps.close();
conn.close();
return emp;
}
@Override
public List<Emp> selectBySal(double minSal, double maxSal) throws Exception {
// 1.获取连接
Connection conn = JdbcUtil.getConnection();
// 2.获取预编译对象
String sql = "select * from emp where sal between ? and ?";
PreparedStatement ps = conn.prepareStatement(sql);
//3. 设置占位符
ps.setDouble(1, minSal);
ps.setDouble(2, maxSal);
//4. 执行sql语句
ResultSet rs = ps.executeQuery();
//5. 处理结果集
List<Emp> emps = new ArrayList<>();
while (rs.next()) {
Emp emp = new Emp();
/*
将数据库查询出来的结果,放入实体类中
*/
emp.setEmpno(rs.getInt(1));
emp.setEname(rs.getString(2));
emp.setJob(rs.getString(3));
emp.setMgr(rs.getInt(4));
emp.setHiredate(rs.getDate(5));
emp.setSal(rs.getDouble(6));
emp.setComm(rs.getInt(7));
emp.setDeptno(rs.getInt(8));
emps.add(emp);
}
//6. 释放资源
rs.close();
ps.close();
conn.close();
return emps;
}
@Override
public boolean addEmp(Emp emp) throws SQLException {
// 1.获取连接
Connection conn = JdbcUtil.getConnection();
// 2.获取预编译对象
String sql = "insert into emp values (?,?,?,?,?,?,?,?)";
PreparedStatement ps = conn.prepareStatement(sql);
//3. 设置占位符
ps.setInt(1, emp.getEmpno());
ps.setString(2, emp.getEname());
ps.setString(3, emp.getJob());
ps.setInt(4, emp.getMgr());
ps.setDate(5, emp.getHiredate());
ps.setDouble(6, emp.getSal());
ps.setInt(7, emp.getComm());
ps.setInt(8, emp.getDeptno());
//4. 执行sql语句
int i = ps.executeUpdate();
//5.关闭资源
ps.close();
conn.close();
return i > 0;
}
@Override
public boolean updateEmp(Emp emp) throws SQLException {
// 1.获取连接
Connection conn = JdbcUtil.getConnection();
// 2.获取预编译对象
String sql = "update emp set ENAME=?,JOB=?,MGR=?,HIREDATE=?,SAL=?,COMM=?,DEPTNO=? where EMPNO=?";
PreparedStatement ps = conn.prepareStatement(sql);
//3. 设置占位符
ps.setInt(8, emp.getEmpno());
ps.setString(1, emp.getEname());
ps.setString(2, emp.getJob());
ps.setInt(3, emp.getMgr());
ps.setDate(4, emp.getHiredate());
ps.setDouble(5, emp.getSal());
ps.setInt(6, emp.getComm());
ps.setInt(7, emp.getDeptno());
//4. 执行sql语句
int i = ps.executeUpdate();
//5.关闭资源
ps.close();
conn.close();
return i > 0;
}
@Override
public boolean deleteEmp(int empno) throws SQLException {
// 1.获取连接
Connection conn = JdbcUtil.getConnection();
// 2.获取预编译对象
String sql = "delete from emp where EMPNO=?";
PreparedStatement ps = conn.prepareStatement(sql);
//3. 设置占位符
ps.setInt(1, empno);
//4. 执行sql语句
int i = ps.executeUpdate();
//5.关闭资源
ps.close();
conn.close();
return i > 0;
}
}
.properties
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/gz2205?useUnicode=true&characterEncoding=utf-8
username=root
password=123456
initialSize=10
maxActive=15
maxWait=6000
//数据库,name ,password 设置成自己的
连接数据库
public class JdbcUtil {
/*
获取数据连接对象。
*/
public static Connection getConnection() {
try {
/*
解析对象
*/
Properties ps = new Properties();
/*
将文件通过输入流加载到内存
*/
InputStream in = JdbcUtil.class.getClassLoader().getResourceAsStream("dbSource.properties");
/*
加载输入流
*/
ps.load(in);
/*
使用德鲁伊工厂对象,根据配置文件创建连接池。
*/
DataSource ds = DruidDataSourceFactory.createDataSource(ps);
/*
返回一个从缓冲池创建的连接对象。
*/
return ds.getConnection();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/*
释放资源
*/
public static void close(Connection conn, PreparedStatement ps, ResultSet rs){
try {
conn.close();
ps.close();
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}