09.JDBC核心,自制DbUtils工具类及连接池

DAO模式、连接池和DBUtils应用

第一节 工具类封装、DAO模式和自定义连接池

1.1 工具类封装

案例实现:实现emp表的查询、添加、删除、修改

1.1.1 封装DbUtils

由于多个地方都需要使用数据库连接和释放,所以把功能封装到工具类中DbUtils

五个个功能:1注册驱动 2 获取连接 3 释放资源 【4 执行命令】 【5 执行查询】

package per.damon.utils;

import java.beans.PropertyDescriptor;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * @Classname DbUtils
 * @Date 2019/8/27 21:56
 * @Created by damon
 * @Description 数据库工具类
 * 1 注册驱动
 * 2 获取连接
 * 3 释放资源
 * 4 执行sql语句(增删改)1.0
 */
public class DbUtils {
    private static String driver;
    private static String url;
    private static String username;
    private static String password;

    //读取文件
    static{
        try {
            Properties properties = new Properties();
            //使用类加载器加载配置文件
            InputStream is = DbUtils.class.getClassLoader().getResourceAsStream("db.properties");
            properties.load(is);
            is.close();
            driver = properties.getProperty("driver");
            url = properties.getProperty("url");
            username=properties.getProperty("username");
            password = properties.getProperty("password");
            Class.forName(driver);

        } catch (Exception e) {
            System.out.println("注册驱动失败");
        }
    }

	//获取连接
    public static Connection getConnection(){
        try {
            return DriverManager.getConnection(url, username, password);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

	//释放所有资源,若无则参数填空
    public static void closeAll(Connection conn, Statement stat, ResultSet rs){
        try{
            if(conn != null){
                conn.close();
            }
            if(stat != null){
                stat.close();
            }
            if(rs != null){
                rs.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    //sql中执行语句返回值为int,传入具体的参数
    public static int executeUpdate(String sql,Object...params){
        Connection conn = getConnection();//因为该方法已经处理了异常,所以不用放入try
        PreparedStatement pstat = null;
        try {
            //preparedStatement创建时即声明使用的是什么语句,语句中可能存在
            //待确定的参数,需要后续使用set进行赋值,注意数据库中下标从1开始
            pstat = conn.prepareStatement(sql);
            if(params != null){
                for (int i = 0; i < params.length; i++) {
                    pstat.setObject(i+1, params[i]);//参数列表中的第几个,0开始
                }
                return pstat.executeUpdate();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            closeAll(conn, pstat, null);
        }
        return -1;
    }

    //返回list集合的方法
    public static <T> List<T> findList(String sql,Class<T> class1,Object...params){
        List<T> list=new ArrayList<>();

		//放在try语句之前,方便后续调用closeAll释放资源
        Connection conn = getConnection();
        PreparedStatement pstat = null;
        ResultSet rs = null;
        try{
            pstat=conn.prepareStatement(sql);
            if(params!=null){
                for (int i = 0; i < params.length; i++) {
                    pstat.setObject(i+1, params[i]);
                }
            }
            //可能语句如select * ...  无参所以执行放在if外面,不论有无参数都执行
            rs = pstat.executeQuery();
            //获取rs中的列名,此时rs中的指针指向表头
            ResultSetMetaData metaData = rs.getMetaData();
//            for (int i = 0; i < metaData.getColumnCount(); i++) {
//                System.out.println(metaData.getColumnLabel(i+1));
//            }
            while (rs.next()){//返回true或false
                //创建一个对象
                T t = class1.newInstance();
                for (int i = 0; i < metaData.getColumnCount(); i++) {
                    String columnLabel = metaData.getColumnLabel(i + 1);
                    Object value = rs.getObject(columnLabel);

                    //创建属性描述符
                    PropertyDescriptor pd = new PropertyDescriptor(columnLabel, class1);

                    try {
                    //如果数据库中有该字段,但是类中没有该字段可能会为空或异常哪个?
                        if(pd != null){
                            Method writeMethod = pd.getWriteMethod();
                            writeMethod.invoke(t, value);
                        }
                    } catch (Exception e) {
                        continue;//本质上没有任何功能,但是增强可读性
                    }
                }
                list.add(t);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            closeAll(conn, pstat, rs);
        }
        return list;
    }

    //返回单个词条
    public static <T> T findSingle(String sql,Class<T> class1,Object...params){
        Connection conn = getConnection();
        PreparedStatement pstat = null;
        ResultSet rs = null;
        T t = null;//与查询list不同,拿出来用以返回
        try {
            pstat=conn.prepareStatement(sql);
            if(params != null){//如果有参,则赋值
                for (int i = 0; i < params.length; i++) {
                    pstat.setObject(i+1, params[i]);
                }
            }
            rs = pstat.executeQuery();//执行查询,返回set结果集
            t=class1.newInstance();//创建一个对象
            ResultSetMetaData metaData = rs.getMetaData();//获取表头
            rs.next();//指向实际数据
            for (int i = 0; i < metaData.getColumnCount(); i++) {
                String columnLabel = metaData.getColumnLabel(i + 1);
//                System.out.println(columnLabel);
                Object value = rs.getObject(columnLabel);
//                System.out.println(value);
                //使用columnLabel的原因就是类中属性不是全部都有用,
                //我们能够取到的数据只有数据库中有的
                //另外,不能保证数据库中的字段类一定有,提供安全性判断。
                try {
                    PropertyDescriptor pd = new PropertyDescriptor(columnLabel,class1);
                    if(pd!=null){
                        Method writeMethod = pd.getWriteMethod();
                        writeMethod.invoke(t, value);
                    }
                } catch (Exception e) {
                    continue;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            closeAll(conn, pstat, rs);
        }
        return t;
    }
}

1.1.2把数据库连接信息封装到Properties文件中

			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");
1.2 DAO设计模式

DAO(Database Access Object 数据库访问对象)

为了降低耦合性,提出了DAO封装数据库操作的设计模式。

它可以实现业务逻辑与数据库访问相分离。相对来说,数据库是比较稳定的,其中DAO组件依赖于数据库系统,提供数据库访问的接口,隔离了不同的数据库实现。

DAO模式的组成部分

​ 1 DAO接口(主要包 添加 修改 查询 删除方法)

​ 2 DAO实现类

​ 3 实体类 (domain、beans、entity、pojo、model)

​ PO (VO)(Persistent Object, Value Object)

​ VO (View Object)

​ DTO (Data Transfer Object)

​ --作用:用在数据访问代码和业务逻辑代码之间通过实体类来传输数据

​ --实体类特征:

​ ◦属性一般使用private修饰

​ ◦提供public修饰的getter/setter方法

​ ◦实体类提供无参构造方法,根据业务提供有参构造/无参构造用以反射获取对象

​ ◦实现java.io.Serializable接口,支持序列化机制

​ 4 数据库连接和关闭工具类

设计的包名 :

domain 存放实体类

utils 存放工具类

dao 存放接口

dao.impl 存放实现类

使用DAO设计模式实现emp表的查询、添加、删除、修改

Employee类
代码无逻辑,字段必须要与数据库中的表头相匹配。

package per.damon.domain;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;

/**
 * @Classname Emp
 * @Date 2019/8/27 21:43
 * @Created by damon
 * @Description 该类用来表示数据库中的学生信息
 */
public class Emp implements Serializable {

    private static final long serialVersionUID=12459873456976L;

    //加入数据库中emp的八个字段,
    private Integer empno;
    private String ename;
    private String job;
    private Integer mgr;
    private Date hiredate;
    private BigDecimal sal;
    private BigDecimal comm;
    private Integer deptno;

    public Emp() {
    }

    public Emp(Integer empno, String ename, String job, Integer mgr, Date hiredate, BigDecimal sal, BigDecimal comm, Integer 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;
    }

    public Integer getEmpno() {
        return empno;
    }

    public void setEmpno(Integer empno) {
        this.empno = empno;
    }

    public String getEname() {
        return ename;
    }

    public void setEname(String ename) {
        this.ename = ename;
    }

    public String getJob() {
        return job;
    }

    public void setJob(String job) {
        this.job = job;
    }

    public Integer getMgr() {
        return mgr;
    }

    public void setMgr(Integer mgr) {
        this.mgr = mgr;
    }

    public Date getHiredate() {
        return hiredate;
    }

    public void setHiredate(Date hiredate) {
        this.hiredate = hiredate;
    }

    public BigDecimal getSal() {
        return sal;
    }

    public void setSal(BigDecimal sal) {
        this.sal = sal;
    }

    public BigDecimal getComm() {
        return comm;
    }

    public void setComm(BigDecimal comm) {
        this.comm = comm;
    }

    public Integer getDeptno() {
        return deptno;
    }

    public void setDeptno(Integer deptno) {
        this.deptno = deptno;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "empno=" + empno +
                ", ename='" + ename + '\'' +
                ", job='" + job + '\'' +
                ", mgr=" + mgr +
                ", hiredate=" + hiredate +
                ", sal=" + sal +
                ", comm=" + comm +
                ", deptno=" + deptno +
                '}';
    }
}

接口:

public interface EmployeeDao {
	
	 //1查询
	 List<Employee> findAll();
	 //2更新
	 void update(Employee e);
	 //3删除
	 void delete(int empno);
	 //4添加
	 void add(Employee e);	
}

实现类

package per.damon.dao.impl;

import per.damon.dao.EmpDao;
import per.damon.domain.Emp;
import per.damon.utils.DbUtils;

import java.util.List;

/**
 * @Classname EmpDao
 * @Date 2019/8/27 21:47
 * @Created by damon
 * @Description TODO
 */
public class EmpDaoImpl implements EmpDao {

    public List<Emp> findAll(){
        List<Emp> list = DbUtils.findList("select * from emp", Emp.class,null);
        return list;
    }

    @Override
    public Emp findByEmpno(Integer empno) {
        Emp emp = DbUtils.findSingle("select * from emp where empno = ?", Emp.class, empno);
        return emp;
    }

    //加入数据库中的不可以是对象,需要将对象内的值拿出来,给一个数组一起提交
    @Override
    public void addEmp(Emp emp){
//        System.out.println("add执行了");
        Object[] params={emp.getEmpno(),emp.getEname(),emp.getJob(),emp.getMgr(),emp.getHiredate(),emp.getSal(),emp.getComm(),emp.getDeptno()};
        int count = DbUtils.executeUpdate("insert into emp values(?,?,?,?,?,?,?,?)", params);
        System.out.println(count);
    }

    @Override
    public void update(Emp emp){
        Object[] params={emp.getEname(),emp.getJob(),emp.getMgr(),emp.getHiredate(),emp.getSal(),emp.getComm(),emp.getDeptno(),emp.getEmpno()};
        int count = DbUtils.executeUpdate("update emp set ename=?,job=?,mgr=?,hiredate=?,sal=?,comm=?, deptno=? where empno=?",params);
        System.out.println(count);
    }

    @Override
    public void delete(Integer empno){
        int count = DbUtils.executeUpdate("delete from emp where empno=?", empno);
        System.out.println(count);
    }

}

测试类:
注意,这里全部都是创建一个接口,然后用该接口来引用接口的实现类,这样的作法实现了多态,至于优势暂不知道。

package per.damon.test;

import org.junit.Test;
import per.damon.dao.EmpDao;
import per.damon.dao.impl.EmpDaoImpl;
import per.damon.domain.Emp;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

/**
 * @Classname Demo
 * @Date 2019/8/27 21:50
 * @Created by damon
 * @Description TODO
 */
public class EmpDaoTest {

    @Test
    public void testAdd(){
        EmpDaoImpl empDao=new EmpDaoImpl();
        Emp emp = new Emp(1234,"damon","java开发",7777,new Date(),new BigDecimal(3000.0),new BigDecimal(3000.0),20);
        empDao.addEmp(emp);
    }

    @Test
    public void testUpdate(){
        EmpDao empDao=new EmpDaoImpl();
        Emp emp = new Emp(1234,"lin","java开发",7777,new Date(),new BigDecimal(3000.0),new BigDecimal(3000.0),20);
        empDao.update(emp);
    }

    @Test
    public void testDelete(){
        EmpDaoImpl empDao=new EmpDaoImpl();
        empDao.delete(1234);
    }

    @Test
    public void testFindlist(){
        EmpDao empDao = new EmpDaoImpl();
        List<Emp> list = empDao.findAll();
        for (Emp emp : list) {
            System.out.println(emp);
        }
    }

    @Test
    public void testFindSingle(){
        EmpDao empDao = new EmpDaoImpl();
        Emp emp = empDao.findByEmpno(1234);
        System.out.println(emp.toString());
    }

}

1.3 自定义实现连接池

为什么要使用连接池:

​ 用户每次请求都需要向数据库获得连接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长。假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大的浪费数据库的资源,并且极易造成数据库服务器内存溢出、拓机。

Java为连接池实现提供了一个规范(接口),规范的写法,我们需要实现DataSource接口!

以下是只重写了接口中一个方法的代码

package per.damon.pool;

import javax.sql.DataSource;
import java.io.InputStream;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.logging.Logger;

/**
 * @Classname ConnectionPool
 * @Date 2019/8/28 17:18
 * @Created by damon
 * @Description TODO
 */
public class ConnectionPool implements DataSource {

    //创建集合,并且线程安全,用于存放连接
    public static List<Connection> connections=
            Collections.synchronizedList(new LinkedList<Connection>());
    static{
        try{
            InputStream is=ConnectionPool.class.getClassLoader().getResourceAsStream("db.properties");
            Properties properties = new Properties();
            properties.load(is);//load从inputStream中读取数据

            String driver=properties.getProperty("driver");
            String url = properties.getProperty("url");
            String username = properties.getProperty("username");
            String password = properties.getProperty("password");

            //加载驱动
            Class.forName(driver);

            for (int i = 0; i < 5; i++) {
                Connection connection = DriverManager.getConnection(url, username, password);
                connections.add(connection);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public Connection getConnection() {
        if(connections.size()>0){
            Connection conn = connections.remove(0);
            return conn;
        }else {
            return null;
        }
    }

    public void release(Connection conn){
        connections.add(conn);
        System.out.println("放入了一个连接"+conn.hashCode());
    }
}

第二节 DBCP连接池

DBCP(DataBase Connection Pool),[数据库连接池]。是 apache 上的一个 java 连接池项目,也是 tomcat 使用的连接池组件。单独使用dbcp需要2个包:commons-dbcp.jar,commons-pool.jar由于建立数据库连接是一个非常耗时的行为,所以通过连接池预先同数据库建立一些连接,放在内存中,应用程序需要建立数据库连接时直接到连接池中申请一个就行,用完后再放回去。

2.1 DBCP连接池的使用
2.1.1 创建项目

创建Java项目

2.1.2 导入相应jar包

​ mysql驱动包

​ commons-dbcp.jar

​ commons-pool.jar

​ commons-logging.jar 日志支持

2.1.3 硬编码使用DBCP

所谓的硬编码方式就是在代码中添加配置

@Test
public void testHard() throws SQLException{
		//TODO 硬编码 使用DBCP连接池子
		BasicDataSource source = new BasicDataSource();
		//设置连接的信息  
		source.setDriverClassName("com.mysql.jdbc.Driver");
		source.setUrl("jdbc:mysql://localhost:3306/day2");
		source.setUsername("root");
		source.setPassword("111");
		
		Connection connection = source.getConnection();
		
		String sql = "select * from student";
		
		Statement createStatement = connection.createStatement();
		
		ResultSet executeQuery = createStatement.executeQuery(sql);
		
		while (executeQuery.next()) {
			 
			System.out.println(executeQuery.getString(2));
		}
		connection.close(); //回收
	}
2.1.4 软编码使用DBCP

所谓的软编码,就是在项目中添加配置文件,这样就不需要每次代码中添加配合!

  1. 项目中添加配置

​ 文件名称: dbcp.properties

​ 文件位置: src下

#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/school
username=root
password=root
#<!-- 初始化连接 -->
initialSize=10
#最大连接数量
maxTotal=50
#<!-- 最大空闲连接 -->
maxIdle=20
#<!-- 最小空闲连接 -->
minIdle=5
#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
maxWaitMillis=5000
  1. 代码实现
	@Test
	public void testSoft() throws Exception{
		Properties properties = new  Properties();
		//配置文件添加到properties对象中  javase
		properties.load(new FileInputStream("src/info.properties"));
		//生成连接池子  需要配置文件
		DataSource source = BasicDataSourceFactory.createDataSource(properties);
         Connection connection = source.getConnection();
		String sql = "select * from student";
		Statement createStatement = connection.createStatement();
		ResultSet executeQuery = createStatement.executeQuery(sql);
		while (executeQuery.next()) {
			System.out.println(executeQuery.getString(2));
		}
		connection.close(); //回收
	}

第三节 C3P0连接池

C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。

c3p0与dbcp区别
	 1.
		dbcp没有自动回收空闲连接的功能
		c3p0有自动回收空闲连接功能
	 2. 
	 	dbcp需要手动加载配置文件
	    c3p0自动加载
3.1 使用步骤
3.1.1 创建项目
3.1.2 导入jar包

​ c3p0-0.9.1.2.jar

​ mchange-commons-java-0.2.11.jar

​ mysql驱动包

3.1.3.添加配置文件

c3p0是在外部添加配置文件,工具直接进行应用,因为直接引用,所以要求固定的命名和文件位置

文件位置: src

文件命名:c3p0-config.xml/c3p0.properties

<c3p0-config>
	<!-- 默认配置,如果没有指定则使用这个配置 -->
	<default-config>
		<!-- 基本配置 -->
		<property name="driverClass">com.mysql.jdbc.Driver</property>
		<property name="jdbcUrl">jdbc:mysql://localhost:3306/school</property>
		<property name="user">root</property>
		<property name="password">root</property>
		<!--扩展配置-->
		<!-- 连接超过10秒报错-->
		<property name="checkoutTimeout">10000</property>
		<!--30秒检查空闲连接 -->
		<property name="idleConnectionTestPeriod">30</property>
		<!-- 初始大小 -->
		<property name="initialPoolSize">10</property>
		<!-- 每次增长的个数 -->
		<property name="acquireIncrement">5</property>
		 <!-- 30秒不适用丢弃-->
		<property name="maxIdleTime">30</property>
		<property name="maxPoolSize">50</property>
		<property name="minPoolSize">5</property>
	</default-config> 
	<!-- 命名的配置 -->
	<named-config name="bj1805">
		<property name="driverClass">com.mysql.jdbc.Driver</property>
		<property name="jdbcUrl">jdbc:mysql://localhost:3306/day2</property>
		<property name="user">root</property>
		<property name="password">111</property>
		<!-- 如果池中数据连接不够时一次增长多少个 -->
		<property name="acquireIncrement">5</property>
		<property name="initialPoolSize">20</property>
		<property name="minPoolSize">10</property>
        <property name="maxPoolSize">40</property>
	</named-config>
</c3p0-config> 

c3p0.properties

c3p0.driverClass=com.mysql.jdbc.Driver
c3p0.jdbcUrl=jdbc:mysql://localhost:3306/school
c3p0.user=root
c3p0.password=root
c3p0.acquireIncrement=5
c3p0.initialPoolSize=20
c3p0.minPoolSize=10
c3p0.maxPoolSize=40

注意:

1: c3p0的配置文件内部可以包含命名配置文件和默认配置文件!默认是选择默认配置!如果需要切换命名配置可以在创建c3p0连接池的时候填入命名即可!

2:如果xml配置文件和属性文件都存在时,xml优先级高于属性文件

3.1.4 c3p0进行数据库操作
public class TestC3p0 {
  
	public static void main(String[] args) throws Exception {
      	//创建ComboPooledDataSource对象使用默认配置
		ComboPooledDataSource  dataSource = new ComboPooledDataSource();
		//1.创建C3P0连接池子
		Connection connection = dataSource.getConnection();
		
		Statement createStatement = connection.createStatement();
		
		String sql = "select * from student;";
		
		ResultSet resultSet = createStatement.executeQuery(sql);
		
		while (resultSet.next()) {
			
			System.out.println(resultSet.getString(1));
		}
		resultSet.close();
      	createStatement.close();
      	connection.close();
      
    }	
}

第四节 Druid连接池

Druid 是目前比较流行的高性能的,分布式列存储的OLAP框架(具体来说是MOLAP)。它有如下几个特点:
一. 亚秒级查询
     druid提供了快速的聚合能力以及亚秒级的OLAP查询能力,多租户的设计,是面向用户分析应用的理想方式。
二.实时数据注入
     druid支持流数据的注入,并提供了数据的事件驱动,保证在实时和离线环境下事件的实效性和统一性
三.可扩展的PB级存储
     druid集群可以很方便的扩容到PB的数据量,每秒百万级别的数据注入。即便在加大数据规模的情况下,也能保证时其效性
四.多环境部署
     druid既可以运行在商业的硬件上,也可以运行在云上。它可以从多种数据系统中注入数据,包括hadoop,spark,kafka,storm和samza等
五.丰富的社区
     druid拥有丰富的社区,供大家学习
4.1 使用步骤

配置文件 database.properties:

#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/school
username=root
password=root
#<!-- 初始化连接 -->
initialSize=10
#最大连接数量
maxActive=50
#<!-- 最小空闲连接 -->
minIdle=5
#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
maxWait=5000
4.1.1 导入jar包

​ druid-1.1.5.jar

4.1.2 编写工具类
 /**
 * 阿里的数据库连接池
 * 性能最好的
 * Druid
 * */
public class DbUtils {
	//声明连接池对象
	private static DruidDataSource ds;
	static{
		
		//实例化配置对象
		Properties properties=new Properties();
		try {
			//加载配置文件内容
              properties.load(DbUtils.class.getResourceAsStream("database.properties"));
              ds = (DruidDataSource)DruidDataSourceFactory.createDataSource(properties);	
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	//获取连接对象
	public static Connection getConnection() {
		try {
			return ds.getConnection();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}	
}
4.1.3 测试
package com.qf.utils;

import java.sql.Connection;

public class Test {
	public static void main(String[] args) throws Exception {
		for(int i=0;i<100;i++) {
			Connection connection=DbUtils.getConnection();
			if(connection!=null) {
				System.out.println("连接成功"+i+"..."+connection.hashCode()+connection.toString());
			}
			connection.close();
		}
	}
}

第五节 DBUtils使用

Commons DbUtils是Apache组织提供的一个对JDBC进行简单封装的开源工具类库,使用它能够简化JDBC应用程序的开发,同时也不会影响程序的性能。

5.1 DBUtils简介

DBUtils是java编程中的数据库操作实用工具,小巧简单实用,

1.对于数据表的读操作,可以把结果转换成List,Array,Set等java集合,便于程序员操作。

2.对于数据表的写操作,也变得很简单(只需写sql语句)。

DBUtils包括主要类

DbUtils类:启动类

ResultSetHandler接口:转换类型接口

​ --ArrayHandler类:实现类,把记录转化成数组

​ --ArrayListHandler类:把记录转化成数组,并放入集合中

​ --ColumnListHandler类:取某一列的数据。封装到List中。

​ –ScalarHandler类:适合获取一行一列数据。

​ –BeanHandler类:实现类,把记录转成对象。

​ –BeanListHandler类:实现类,把记录转化成List,使记录为JavaBean类型的对象

QueryRunner类:执行SQL语句的类

5.2 DBUtils工具类封装
5.2.1 项目准备
  • 创建项目
  • 导入jar包 工具类 配置文件
    commons-dbutils-1.6.jar
    druid-1.1.5.jar
    DruidUtils.java工具类
    database.properties配置文件
5.2.2 实现代码
public class ResultHanlder {

	@Test
	public void testArrayHander() throws SQLException {

		// ArrayHandler:适合取1条记录。把该条记录的每列值封装到一个数组中Object[]
		QueryRunner runner = new QueryRunner(DruidUtils.getDataSource());

		Object[] query = runner.query("select * from school where empno = ?", new ArrayHandler(), 1234);

		for (Object object : query) {

			System.out.println(object);
		}

	}

	@Test
	public void testArrayListHander() throws SQLException {

		// ArrayHandler:适合取1条记录。把该条记录的每列值封装到一个数组中Object[]
		QueryRunner runner = new QueryRunner(DruidUtils.getDataSource());

		List<Object[]> query = runner.query("select * from emp ", new ArrayListHandler());

		for (Object[] objects : query) {
			for (Object object : objects) {

				System.out.println(object);
			}
		}

	}

	@Test
	public void testColumnListHander() throws SQLException {

		// ColumnListHandler:取某一列的数据。封装到List中。
		QueryRunner runner = new QueryRunner(DruidUtils.getDataSource());

		List<Object> query = runner.query("select * from emp ", new ColumnListHandler<Object>(2));

		for (Object objects : query) {

			System.out.println(objects);
		}

	}


	@Test
	public void testScalarHandler() throws SQLException {

		// ScalarHandler:适合取单行单列数据
		QueryRunner runner = new QueryRunner(DruidUtils.getDataSource());

		Object query = runner.query("select count(*) from emp ", new ScalarHandler());
		System.out.println(query);
	}

	@Test
	public void testBeanHandler() throws SQLException {
		// BeanHandler:适合取单行单列数据
		QueryRunner runner = new QueryRunner(DruidUtils.getDataSource());
		Employee query = runner.query("select * from emp where empno=1234 ", new BeanHandler<Employee>(Employee.class));
		System.out.println(query.toString());
	}
  
  @Test
	public void testBeanListHandler() throws SQLException {
		// BeanHandler:适合取多行多列数据
		QueryRunner runner = new QueryRunner(DruidUtils.getDataSource());
		List<Employee> query2 = runner.query("select * from emp", new BeanListHandler<Employee>(Employee.class));
		for (Employee employee : query2) {
			System.out.println(employee);
		}
	}
}

总结

1 封装工具类

2 Dao设计模式: 把数据访问代码抽离出来。降低代码的耦合性和提高扩展性。

​ dao接口

​ dao实现

​ 实体类

​ 数据库工具类

3 连接池

​ dbcp

​ c3p0

​ druid重点

4 Dbutils工具

面试题

1、描述数据库连接池的优缺点


版权声明:本文为qq_38243113原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。