一、JDBC 优化及工具类封装
1.1 现有问题
1.2 JDBC 工具类封装 V1.0
resources/db.properties配置文件:
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql:///atguigu
username=root
password=123456
initialSize=10
maxActive=20
工具类代码:
package com.atguigu.advanced.senior.util;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
/**
* JDBC工具类(V1.0)
* 1.维护一个连接池对象
* 2.对外提供在连接池中获取连接的方法
* 3.对外提供回收连接的方法
* 【注意】:工具类仅对外提供共性的功能代码,所以方法均为静态方法!
*/
public class JDBCUtil {
//创建连接池引用,因为要提供给当前项目的全局使用,所以创建为静态的
private static DataSource dataSource;
//在项目启动时,即创建连接池对象,赋值给 dataSource
static {
try {
Properties properties = new Properties();
InputStream inputStream = JDBCUtil.class.getClassLoader().getResourceAsStream("db.properties");
properties.load(inputStream);
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//对外提供在连接池中获取连接的方法
public static Connection getConnection(){
try {
return dataSource.getConnection();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
//对外提供回收连接的方法
public static void release(Connection connection){
try {
connection.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
测试代码:
package com.atguigu.advanced.senior;
import com.atguigu.advanced.senior.util.JDBCUtil;
import org.junit.Test;
import java.sql.Connection;
public class JDBCUtilTest {
@Test
public void testGetConnection() {
Connection connection = JDBCUtil.getConnection();
System.out.println(connection);
//CRUD
JDBCUtil.release(connection);
}
}
1.3 ThreadLocal (本地线程)
问题:
同一用户线程多次操作获取了多个连接,造成连接资源的浪费
怎么取?
怎么存?
怎么移除?
- 在进行对象跨层传递的时候,使用ThreadLocal可以避免多次传递,打破层次间的约束
- 线程间数据隔离
- 进行事务操作,用于存储线程事务信息
- 数据库连接, Session 会话管理
- ThreadLocal对象.get:获取ThreadLocal中当前线程共享变量的值
- ThreadLocal对象.set:设置ThreadLocal中当前线程共享变量的值
- ThreadLocal对象.remove:移除ThreadLocal中当前线程共享变量的值。
1.4 JDBC 工具类封装 V2.0
package com.atguigu.advanced.senior.util;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
/**
* JDBC工具类(V2.0)
* 1.维护一个连接池对象,维护了一个线程绑定变量的ThreadLocal对象
* 2.对外提供在ThreadLocal中获取连接的方法
* 3.对外提供回收连接的方法,回收过程中,将要回收的连接从ThreadLocal中移除!
* 【注意】:工具类仅对外提供共性的功能代码,所以方法均为静态方法!
* 【注意】:使用ThreadLocal就是为了一个线程在多次数据库操作过程中,使用的是同一个连接!
*/
public class JDBCUtilV2 {
//创建连接池引用,因为要提供给当前项目的全局使用,所以创建为静态的
private static DataSource dataSource;
private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
//在项目启动时,即创建连接池对象,赋值给 dataSource
static {
try {
Properties properties = new Properties();
InputStream inputStream = JDBCUtil.class.getClassLoader().getResourceAsStream("db.properties");
properties.load(inputStream);
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//对外提供在连接池中获取连接的方法
public static Connection getConnection(){
try {
//在ThreadLocal中获取Connection
Connection connection = threadLocal.get();
//threadLoacl里没有存储Connection,也就是第一次获取
if(connection == null){
connection = dataSource.getConnection();
threadLocal.set(connection);
}
return connection;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
//对外提供回收连接的方法
public static void release(Connection connection){
try {
connection = threadLocal.get();
if (connection != null){
//从threadLocal中移除当前已经存储的Connection对象
threadLocal.remove();
//将Connection对象归还给连接池
connection.close();
}
connection.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
测试代码
@Test
public void testJDBCV2(){
/*
JDBCUtil 获取连接
*/
Connection connection1 = JDBCUtil.getConnection();
Connection connection2 = JDBCUtil.getConnection();
Connection connection3 = JDBCUtil.getConnection();
System.out.println(connection1);
System.out.println(connection1);
System.out.println(connection1);
System.out.println("================================");
/*
JDBCUtilV2 获取连接
*/
Connection connectionA = JDBCUtilV2.getConnection();
Connection connectionB = JDBCUtilV2.getConnection();
Connection connectionC = JDBCUtilV2.getConnection();
System.out.println(connectionA);
System.out.println(connectionB);
System.out.println(connectionC);
}
二、DAO封装及BaseDAO 工具类
2.1 DAO 概念
1、DAO:Data Access Object,数据访问对象。
2、Java 是面向对象语言,数据在 Java 中通常以对象的形式存在。一张表对应一个实体类,一张表的操作对应一个 DAO 对象。
3、在 Java 操作数据库时,我们会将对同一张表的增删改查操作统一维护起来,维护的这个类就是 DAO 层。
4、DAO 层只关注对数据库的操作,供业务层 Service 调用,将职责划分清楚!
EmployeeDao.java
package com.atguigu.advanced.senior.dao;
import com.atguigu.advanced.senior.pojo.Employee;
import java.util.List;
/**
* EmployeeDao 这个类对应的是 t_emp 这张表的增删改查的操作
*/
public interface EmployeeDao {
/**
* 数据库对应的查询所有的操作
* @return 表中所有的数据
*/
List<Employee> selectAll();
/**
* 数据库对应的根据empId查询单个员工数据操作
* @param empId
* @return 一个员工对象(一行数据)
*/
Employee selectByEmpId(Integer empId);
/**
* 数据库对应的新增一条员工数据
* @param employee ORM思想中的一个员工对象
* @return 受影响的行数
*/
int insert(Employee employee);
/**
* 数据库对应的修改一条员工数据
* @param employee ORM思想中的一个员工对象
* @return 受影响的行数
*/
int update(Employee employee);
/**
* 数据库对应的根据empId删除一条员工数据
* @param empId 主键列
* @return 受影响的行数
*/
int delete(Integer empId);
}
EmployeeDaoImpl.java
package com.atguigu.advanced.senior.dao.impl;
import com.atguigu.advanced.senior.dao.EmployeeDao;
import com.atguigu.advanced.senior.pojo.Employee;
import java.util.List;
public class EmployeeDaoImpl implements EmployeeDao {
@Override
public List<Employee> selectAll() {
//1.注册驱动
//2.获取连接
//3.预编译SQL语句
//4.为占位符赋值,执行SQL,接受返回结果
//5.处理结果
//6.释放资源
return null;
}
@Override
public Employee selectByEmpId(Integer empId) {
return null;
}
@Override
public int insert(Employee employee) {
return 0;
}
@Override
public int update(Employee employee) {
return 0;
}
@Override
public int delete(Integer empId) {
return 0;
}
}
2.2 BaseDAO 概念
基本上每一个数据表都应该有一个对应的 DAO 接口及其实现类,发现对所有表的操作(增、删、改、查)代码重复度很高,所以可以抽取公共代码,给这些 DAO 的实现类可以抽取一个公共的父类,复用增删改查的基本操作,我们称为 BaseDAO。