JDBC学习笔记(三)高级篇

发布于:2024-06-05 ⋅ 阅读:(47) ⋅ 点赞:(0)

一、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 会话管理

 

  1. ThreadLocal对象.get:获取ThreadLocal中当前线程共享变量的值
  2. ThreadLocal对象.set:设置ThreadLocal中当前线程共享变量的值
  3. 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。

2.3 BaseDAO 搭建

2.4 BaseDAO 的应用

三、事务

3.1 事务回顾

3.2 JDBC 中事务实现

3.3 JDBC 事务代码实现


网站公告

今日签到

点亮在社区的每一天
去签到