JDBC高级,数据库连接池和DbUtils

JDBC高级,数据库连接池和DbUtils

1. BaseDao封装
1.1 BaseDao 通用查询方法封装
1.1.1 ORM思想
ORM思想
	数据库数据行 ==> Java中的类对象
	数据行:
		字段名字,对应当前字段的数据
	类对象:
		成员变量名字
	要求:
		1. 字段名 <==> 成员变量名
		2. 字段数据类型 <==> 成员变量数据类型一致。
1.1.2 通用查询方法功能分析
期望:
	1. 可以处理select 对应的 DQL 语句
	2. 根据用户约定,可以得到任意数据类型
	3. 查询返回的数据,可以是多个,可以是一个

SQL语句:
	1. SQL有可能带有参数
	2. 对应当前SQL语句的参数列表

用户指定类型问题:
	1. 任意类型:
		使用泛型来约束数据类型,用户既可以使用任意类型,同时也可以满足数据类型一
		致化要求。
	2. 类对象问题:
		Person类型 ==> Person类对象
		Student类型 ==> Student类对象
		方法内需要有创建对应类对象的能力:
			a. new + 构造方法
			b. 反射通过Class类对象,获取Constructor对象,调用newInstance方
			法 【选择】
	3. 方法参数怎么写???
		a. Class类对象
		b. 泛型约束 
		Class<T> 
			传入参数: 
				Person.class ==> Class<Person> T ==> Person
				Worker.class ==> Class<Worker> T ==> Worker

方法参数:
	1. String sql
	2. Class<T> cls
	3. Object... parameters [不定长参数有且只能是方法参数列表的最后一个]

方法返回值:
	List<T>
		LinkedList ArrayList

方法声明:
	public <T> List<T> query(String sql, Class<T> cls, Object... parameters);
1.1.3 方法流程分析
1. 准备必要的变量
2. 获取数据库连接
3. 预处理SQL语句
4. 赋值SQL语句参数
5. 执行方法,获取结果集对象
【重点】
	6. 解析结果集
		6.1 想要获取字段名 ==> 成员变量名字 [字段名获取]
			【结果集元数据】 MetaData
				getColumnName
				getColumnCount
				
		6.2 取出数据 ==> 赋值成员变量  [数据类型一致]
			【BeanUtils】
				符合JavaBean规范的对象赋值,取值,拷贝操作工具类
7. 关闭资源 
8. 返回List集合
【补充知识点 结果集元数据】
ResultSetMetaData metaData = resultSet.getMetaData();

int columnCount = metaData.getColumnCount();

System.out.println("columnCount : " + columnCount);
System.out.println("ColumnName : " + metaData.getColumnName(1));
System.out.println("ColumnName : " + metaData.getColumnName(2));
System.out.println("ColumnName : " + metaData.getColumnName(3));
System.out.println("ColumnName : " + metaData.getColumnName(4));
System.out.println("ColumnName : " + metaData.getColumnName(5));
【补充知识点 BeanUtils】
符合JavaBean规范类对象,赋值,取值,拷贝的工具类
	依赖第三方Jar
		commons-beanutils-1.8.3.jar
		commons-logging-1.1.3.jar
		beanutils 依赖于 logging 没有依赖,无法使用

涉及到的方法:
	static void setProperty(Object bean, String name, Object value);
	设置指定符合JavaBean规范的类对象中,对应成员变量赋值操作。
        bean:
			任何一个符合JavaBean规范的类对象
        name:
			当前符合JavaBean规范类对象对应的成员变量名字
        value:
        	需要赋值给对应成员变量的数据
        	
	static String getProperty(Object bean, String name);
	获取符合JavaBean规范类对象中的指定成员变量数据,返回值是String类型
		bean:
			任何一个符合JavaBean规范的类对象
		name:	
			指定成员变量的名字
		返回值:
			String 对应当前成员变量数据的String类型。
	
	static void copyProperties(Object dest, Object src);
	从src中拷贝数据到dest中,要求两个对象都是符合JavaBean规范,并且是同一个类型
	对象。
1.1.4 BaseDao query方法实现
/**
 * 通用query查询方法,用于处理select语句
 *
 * @param sql        Select SQL 语句 DQL语句
 * @param cls        当前查询目标的数据类型Class对象,
 * @param parameters 对应SQL语句参数
 * @param <T>        泛型约束当前数据类型,需要通过参数传入
 * @return List集合包含有用户查询的目标数据,如果为找到任何数据,返回null
 * @throws SQLException              SQL异常
 * @throws NoSuchMethodException     没有指定方法异常
 * @throws IllegalAccessException    非法权限操作异常
 * @throws InvocationTargetException 执行指定目标失败异常
 * @throws InstantiationException    实例化对象异常
 */
public <T> List<T> query(String sql, Class<T> cls, Object... parameters)
        throws SQLException, NoSuchMethodException, IllegalAccessException,
        InvocationTargetException, InstantiationException {
    // 1. 准备必要的变量
    ResultSet resultSet = null;
    Connection connection = null;
    PreparedStatement statement = null;

    // 2. 获取数据库连接
    connection = JDBCUtil.getConnection();

    // 3. 预处理SQL语句
    statement = connection.prepareStatement(sql);

    // 4. 赋值SQL语句参数
    int parameterCount = statement.getParameterMetaData().getParameterCount();

    if (parameters != null && parameterCount == parameters.length && parameterCount != 0) {
        for (int i = 0; i < parameters.length; i++) {
            statement.setObject(i + 1, parameters[i]);
        }
    }

    // 5. 执行方法,获取结果集对象
    resultSet = statement.executeQuery();

    // 6. 解析结果集
    // 【结果集元数据】 MetaData
    ResultSetMetaData metaData = resultSet.getMetaData();
    List<T> list = new ArrayList<>();

    while (resultSet.next()) {
        // 创建目标类型对象
        T t = cls.getConstructor().newInstance();
        /*
         6.1 想要获取字段名 ==> 成员变量名字 [字段名获取]
         	【结果集元数据】 MetaData
                 getColumnName
                 getColumnCount
         */
        for (int i = 1; i <= metaData.getColumnCount(); i++) {
            // 获取字段名字
            String fieldName = metaData.getColumnName(i);
            // 根据字段名,从结果集对象中,获取对应的数据
            Object object = resultSet.getObject(fieldName);

            /*
             6.2 取出数据 ==> 赋值成员变量  [数据类型一致]
                【BeanUtils】
             符合JavaBean规范的对象赋值,取值,拷贝操作工具类
            */
            BeanUtils.setProperty(t, fieldName, object);
        }

        list.add(t);
    }

    // 7. 关闭资源
    JDBCUtil.close(resultSet, statement, connection);

    // 8. 返回List集合
    return list.isEmpty() ? null : list;
}
2. 数据库连接池
2.1 回顾线程池
线程池的优点:
	1. 降低了线程创建和销毁的时间浪费
	2. 可以自行增加线程对象,同时也可以根据当前线程池,线程的空闲时间,进行多余线
	程关闭
	3. 提交任务方便,不再需要考虑针对线程的继承或者遵从问题。Runnable target

数据库操作存在类似问题
	针对于数据库的连接对象Connection 需要频繁的打开和关闭,浪费时间。同时可以会出现多线程打开数据库操作的情况。
	使用数据库连接池来解决类似的问题!!!
2.2 数据库连接池的核心参数
1. 数据库连接对象获取方式必要的参数:
	driverClass jdbcUrl userName password
2. 初始化数据库连接池容量
3. 最大数据库连接对象容量
4. 等待时间 Timeout
5. 最小容量

数据库连接池的配置都是通过【配置文件完成】。
数据库连接池对象使用【润物细无声】

C3P0  SSH框架中 Hibernate内置数据库连接池方式
Druid From China Alibaba
2.3 C3P0数据库连接池使用
2.3.1 导包
需要导入第三方Jar包
	c3p0-0.9.5.2.jar
	mchange-commons-java-0.2.15.jar
2.3.2 c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
	<!-- 默认配置,如果没有指定则使用这个配置 -->
	<default-config>
		<property name="driverClass">com.mysql.jdbc.Driver</property>
		<property name="jdbcUrl">jdbc:mysql://localhost:3306/javaee2009?useSSL=false</property>
		<property name="user">root</property>
		<property name="password">123456</property>
		<!-- 初始化池大小 -->
		<property name="initialPoolSize">10</property>
		<!-- 最大空闲时间 -->
		<property name="maxIdleTime">30</property>
		<!-- 最多有多少个连接 -->
		<property name="maxPoolSize">30</property>
		<!-- 最少几个连接 -->
		<property name="minPoolSize">5</property>
		<!-- 每次最多可以执行多少个批处理语句 -->
		<property name="maxStatements">50</property>
		<!-- 最大等待时间,毫秒值 -->
		<property name="checkoutTimeout">1000</property>
	</default-config>
</c3p0-config> 
2.3.3 修改JDBCUtil工具类,使用C3P0
// 创建C3P0数据库连接池核心类对象 自动读取src目录下的c3p0-config.xml
private static ComboPooledDataSource dataSource = new ComboPooledDataSource();

/**
 * 获取数据库连接对象方法
 *
 * @return java.sql.Connection 对象。如果获取连接失败返回null
 */
public static Connection getConnection() {
    Connection connection = null;
    
    try {
        // 获取数据库连接从 dataSource 数据库连接池对象中获取对应的数据库连接对象。
        connection = dataSource.getConnection();
    } catch (SQLException e) {
        e.printStackTrace();
    }
    
    return connection;
}
2.4 Druid 数据库连接池
2.4.1 导包
druid-1.2.3.jar
	Druid第三方Jar包
2.4.2 Druid数据库连接池配置文件
# druid.properties文件
# 文件名 druid.properties 存储在src目录下
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/javaee2009?useSSL=false
username=root
password=123456

# 初始化数据库连接池容量
initialSize=10

# 最大容量
maxActive=30

# TimeOut 等待超时时间
maxWait=2000
2.4.3 使用Druid优化JDBCUitl工具
package util;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

/**
 * 使用Druid数据库完备JDBC工具类
 * 1. JDBC数据库连接所需的必要资源准备和驱动加载
 * 2. 提供一个工具类方法,获取数据库连接对象 Connection getConnection
 * 3. 关闭用户使用的数据库资源
 *
 * @author Anonymous
 */
public class JDBCUtil {

    private static DataSource dataSource = null;

    static  {
        Properties properties = new Properties();
        try {
            // 读取Properties配置文件
            properties.load(new FileInputStream("./src/druid.properties"));

            // Druid数据库连接池工厂类创建一个数据库连接池
            dataSource = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取数据库连接对象方法
     *
     * @return java.sql.Connection 对象。如果获取连接失败返回null
     */
    public static Connection getConnection() {

        Connection connection = null;
        try {
            // 获取数据库连接从 dataSource 数据库连接池对象中获取对应的数据库连接对象。
            connection = dataSource.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }

    /**
     * 数据库操作使用的资源都是AutoCloseable接口的实现类,可以使用
     * 不定长参数直接完成关闭方法,传入的参数是AutoCloseable实现类
     * 个数不限
     *
     * @param res AutoCloseable实现类对象,个数不限
     */
    public static void close(AutoCloseable... res) {
        try {
            // 遍历当前AutoCloseable数组,使用增强for循环
            for (AutoCloseable re : res) {
                // 当前资源不为null,直接关闭
                if (re != null) {
                    re.close();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

3. DBUtils轻量级ORM框架
3.1 DbUtils工具类
最后更新是2017年7月
	核心类 QueryRunner
	提供了大量的 Handler 方式,处理方式。
		原生 ResultSetHandler
		升级版:
			BeanHandler<T>(Class<T> cls);
			BeanListHandler<T>(Class<T> cls);	
            ArrayHandler();
            ArrayListHandler();
            MapHandler();
            MapListHandler();
3.2 Handler使用
3.2.1 BeanHandler
@Test
public void testBeanHandler() throws SQLException {
    // 1. 创建QueryRunner核心类对象,并且参数是DataSource数据库连接池对象
    QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());

    String sql = "select * from javaee2009.student where id = 10";

    /*
    BeanHandler使用
        将SQL语句查询操作得到的数据行内容 映射为一个符合JavaBean规范类对象
        在当前方法参数中需要明确告知BeanHandler要求处理的数据类型是哪一个
        格式: new BeanHandler<>(Student.class)
     */
    Student student = queryRunner.query(sql, new BeanHandler<>(Student.class));
    System.out.println(student);
}
3.2.2 BeanListHandler
@Test
public void testBeanListHandler() throws SQLException {
    // 1. 创建QueryRunner核心类对象,并且参数是DataSource数据库连接池对象
    QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());

    String sql = "select * from javaee2009.student;";

    /*
    BeanListHandler
        将SQL数据查询结果的所有数据行转换为一个List集合
        每一个数据行对应用户要求的符合JavaBean规范类对象,保存到一个List集合中。
        格式:
            new BeanListHandler<>(Student.class)
     */
    List<Student> list = queryRunner.query(sql, new BeanListHandler<>(Student.class));

    for (Student student : list) {
        System.out.println(student);
    }
}
3.2.3 ArrayHandler
@Test
public void testArrayHandler() throws SQLException {
    // 1. 创建QueryRunner核心类对象,并且参数是DataSource数据库连接池对象
    QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());

    String sql = "select name, age, id, score, info from javaee2009.student where id = ?;";

    /*
    ArrayHandler
        将SQL语句对应查询结果集数据行内容,所有数据变成一个Object类型数组
        数组中的数据顺序根据查询字段要求来约束
   【重要方法】
        多表数据联查情况下数据传递和保存。
     */
    Object[] objects = queryRunner.query(sql, new ArrayHandler(), 10);

    System.out.println(Arrays.toString(objects));
}
3.2.4 ArrayListHandler
@Test
public void testArrayListHandler() throws SQLException {
    // 1. 创建QueryRunner核心类对象,并且参数是DataSource数据库连接池对象
    QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());

    String sql = "select name, age, info from javaee2009.student;";

    /*
    ArrayListHandler
        将查询结果集每一个数据看作是一个Object类型数组,数据顺序根据
        提供的SQL语句约束,所有的数据都保存到一个List集合中
        List集合中数据类型为Object[]
            List<Object[]>
     */
    List<Object[]> list = queryRunner.query(sql, new ArrayListHandler());
    for (Object[] objects : list) {
        System.out.println(Arrays.toString(objects));
    }
}
3.2.5 MapHandler
@Test
public void testMapHandler() throws SQLException {
    // 1. 创建QueryRunner核心类对象,并且参数是DataSource数据库连接池对象
    QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());

    String sql = "select name, age, id, score, info from javaee2009.student where id = ?;";

    /*
    MapHandler
        将SQL数据查询数据行结果映射为一个Map双边队列,字段对应键,数据对应value
     */
    Map<String, Object> map = queryRunner.query(sql, new MapHandler(), 10);

    System.out.println(map);
}
3.2.6 MapListHandler
@Test
public void testMapListHandler() throws SQLException {
    // 1. 创建QueryRunner核心类对象,并且参数是DataSource数据库连接池对象
    QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());

    String sql = "select name, age, info from javaee2009.student;";

    /*
    MapListHandler
        将SQL语句查询结果集对象,每一行数据对应一个Map双边队列,Key=>字段名
        value=>数据,所有的map存储在一个List集合中
        List<Map<String, Object`>>
     */
    List<Map<String, Object>> mapList = queryRunner.query(sql, new MapListHandler());

    for (Map<String, Object> map : mapList) {
        System.out.println(map);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值