JDBC(2)

2 篇文章 0 订阅

目录

一、事务

1.1 基本介绍

二、批处理

2.1 基本介绍

三、数据库连接池

3.1 传统获取Connection问题分析

3.2 数据库连接池基本介绍

3.3 数据库连接池种类

3.3.1 C3P0应用实例

3.3.2 Druid(德鲁伊)应用实例

3.3.3 将JDBCUtils工具类改成Druid(德鲁伊)实现

四、Apache—DBUtils

4.1 先分析一个问题

4.2 基本介绍

4.3 表和JavaBean的类型映射关系

五、DAO和增删改查通用方法—BasicDAO 

5.1 先分析一个问题

5.2 基本说明


一、事务

1.1 基本介绍

1. JDBC程序中当一个Connection对象创建时,默认情况下是自动提交事务:每次执行一个SQL语句时,如果执行成功,就会向数据库自动提交,而不能回滚。

2. JDBC程序中为了让多个SQL语句作为一个整体执行,需要使用事务

3. 调用Connection的setAutoCommit(false)可以取消自动提交事务

4. 在所有的SQL语句都成功执行后,调用Connection的 commit();方法提交事务

5. 在其中某个操作失败或者出现异常时,调用Connection的 rollback();方法回滚事务

package com.learn.jdbc.transaction_;

import com.learn.jdbc.utils.JDBCUtils;
import org.junit.jupiter.api.Test;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * @author 咕咕猫
 * @version 1.0
 */
public class Transaction_ {
    //没有使用事务
    @Test
    public void noTransaction() {

        //操作转账的业务
        //1.得到连接
        Connection connection = null;

        //2.组织一个sql
        String sql1 = "update account set balance = balance - 100 where id = 1";
        String sql2 = "update account set balance = balance + 100 where id = 2";
        PreparedStatement preparedStatement = null;
        //3.创建PreparedStatement对象
        try {
            connection = JDBCUtils.getConnection();//在默认情况下,connection是默认自动提交
            preparedStatement = connection.prepareStatement(sql1);
            preparedStatement.executeUpdate();//执行第一条sql

            int i = 1 / 0;
            preparedStatement = connection.prepareStatement(sql2);
            preparedStatement.executeUpdate();//执行第二条sql

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //关闭资源
            JDBCUtils.close(null, preparedStatement, connection);
        }
    }

    @Test
    //用事务来解决
    public void userTransaction() {
        //操作转账的业务
        //1.得到连接
        Connection connection = null;

        //2.组织一个sql
        String sql1 = "update account set balance = balance - 100 where id = 1";
        String sql2 = "update account set balance = balance + 100 where id = 2";
        PreparedStatement preparedStatement = null;
        //3.创建PreparedStatement对象
        try {
            connection = JDBCUtils.getConnection();//在默认情况下,connection是默认自动提交
            //将connection设置为不自动提交
            connection.setAutoCommit(false);
            preparedStatement = connection.prepareStatement(sql1);
            preparedStatement.executeUpdate();//执行第一条sql

            //int i = 1 / 0;
            preparedStatement = connection.prepareStatement(sql2);
            preparedStatement.executeUpdate();//执行第二条sql

            //在这里提交事务
            connection.commit();

        } catch (SQLException e) {
            //这里可以进行回滚,即撤销执行sql
            System.out.println("执行发生了异常,撤销执行的sql");
            try {
                connection.rollback();//默认回滚到事务开始的状态
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
            e.printStackTrace();
        }finally {
            //关闭资源
            JDBCUtils.close(null, preparedStatement, connection);
        }
    }


}

二、批处理

2.1 基本介绍

1. 当需要成批插入或者更新记录时,,可以采用Java的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理。通常情况下比单独提交处理更有效率。

2. JDBC的批量处理语句包括下面方法:

        ① addBatch():添加需要批量处理的SQL语句或参数

        ② executeBatch():执行批量处理语句

        ③ clearBatch():清空批处理包的语句

3. JDBC连接Mysql时,如需使用批处理功能,请在url中加参数 ?rewriteBatchedStatements=true

4. 批处理往往和PreparedStatement一起搭配使用,可以既减少编译次数,又减少运行次数,效率大大提高

package com.learn.jdbc.batch_;

import com.learn.jdbc.utils.JDBCUtils;
import org.junit.jupiter.api.Test;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * @author 咕咕猫
 * @version 1.0
 * 演示Java的批处理
 */
public class Batch_ {

    //传统方法, 添加5000条数据到admin2表
    @Test
    public void noBatch() throws SQLException {

        Connection connection = JDBCUtils.getConnection();
        String sql = "insert into admin2 values(null, ?, ?)";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);

        System.out.println("开始执行...");
        long start = System.currentTimeMillis();
        for (int i = 0; i < 5000; i++) {
            preparedStatement.setString(1, "jack" + i);
            preparedStatement.setString(2, "666");
            preparedStatement.executeUpdate();
        }
        long end = System.currentTimeMillis();
        System.out.println("传统方式 耗时= " + (end - start));//2298
        //关闭连接
        JDBCUtils.close(null, preparedStatement, connection);
    }

    @Test
    //使用批量处理添加方式
    public void batch() throws SQLException {
        Connection connection = JDBCUtils.getConnection();
        String sql = "insert into admin2 values(null, ?, ?)";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);

        System.out.println("开始执行...");
        long start = System.currentTimeMillis();
        for (int i = 0; i < 5000; i++) {
            preparedStatement.setString(1, "jack" + i);
            preparedStatement.setString(2, "666");
            //将sql语句加入到批处理包中
            preparedStatement.addBatch();
            //当有1000条记录时再批量执行
            if((i + 1) % 1000 == 0){ //满1000条sql
                preparedStatement.executeBatch();
                //满了以后再清空
                preparedStatement.clearBatch();
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("批处理方式 耗时= " + (end - start));//55
        //关闭连接
        JDBCUtils.close(null, preparedStatement, connection);
    }
}

三、数据库连接池

3.1 传统获取Connection问题分析

1. 传统的JDBC数据库连接使用DriverManager来获取,每次向数据库建立连接的时候都要将Connection加载到内存中,再验证IP地址,用户名和密码(0.05s~1s时间)。需要数据库连接的时候,就向数据库要求一个,频繁的进行数据库连接操作将占用很多的系统资源,容易造成服务器崩溃。

2. 每一次数据库连接,使用完后都得断开,如果程序出现异常而未能关闭,将导致数据库内存泄漏,最终将导致重启数据库

3. 传统获取连接的方式,不能控制创建的连接数量,如连接过多,也可能导致内存泄漏,MySQL崩溃

4. 解决传统开发中的数据库连接问题,可以采用数据库连接池技术(connection pool)

3.2 数据库连接池基本介绍

1. 预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去

2. 数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个

3. 当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中

3.3 数据库连接池种类

1. JDBC的数据库连接池使用 javax.sql.DataSource来表示,DataSource只是一个接口,该接口通常由第三方提供[提供.jar]

2. C3P0数据库连接池,速度相对较慢,但稳定性不错(hibernate,spring)

3. DBCP数据库连接池,速度相对C3P0较快,但不稳定

4. Proxool数据库连接池,有监控连接池状态的功能,稳定性较C3P0差一点

5. BoneCP数据库连接池,速度快

6. Druid(德鲁伊)是阿里提供的数据库连接池,集DBCP、C3P0、Proxool优点于一身的数据库连接池

3.3.1 C3P0应用实例

package com.learn.jdbc.datasource;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.junit.jupiter.api.Test;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

/**
 * @author 咕咕猫
 * @version 1.0
 * 演示C3P0的使用
 */
public class C3P0_ {
    //方式 1: 相关参数,在程序中指定 user, url , password 等
    @Test
    public void testC3P0_01() throws Exception {
        //1. 创建一个数据源对象
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
        //2. 通过配置文件 mysql.properties 获取相关连接的信息
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\mysql.properties"));
        //读取相关的属性值
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String url = properties.getProperty("url");
        String driver = properties.getProperty("driver");
        //给数据源 comboPooledDataSource 设置相关的参数
        //注意:连接管理是由 comboPooledDataSource 来管理
        comboPooledDataSource.setDriverClass(driver);
        comboPooledDataSource.setJdbcUrl(url);
        comboPooledDataSource.setUser(user);
        comboPooledDataSource.setPassword(password);
        //设置初始化连接数
        comboPooledDataSource.setInitialPoolSize(10);
        //最大连接数
        comboPooledDataSource.setMaxPoolSize(50);

        //测试连接池的效率, 测试对 mysql 5000 次操作
        long start = System.currentTimeMillis();
        for (int i = 0; i < 5000; i++) {
            Connection connection = comboPooledDataSource.getConnection(); //这个方法就是从 DataSource 接口实现的
        //System.out.println("连接 OK");
            connection.close();
        }
        long end = System.currentTimeMillis();
        //c3p0 5000 连接 mysql 耗时=391
        System.out.println("c3p0 5000 连接 mysql 耗时=" + (end - start));
    }

    @Test
    //第二种方式 使用配置文件模板来完成
    //1. 将 c3p0 提供的 c3p0.config.xml 拷贝到 src 目录下
    //2. 该文件指定了连接数据库和连接池的相关参数
    public void testC3P0_02() throws SQLException {
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("ggm");

        Connection connection = comboPooledDataSource.getConnection();
        System.out.println("连接ok~");
        connection.close();
    }


}

3.3.2 Druid(德鲁伊)应用实例

package com.learn.jdbc.datasource;

import com.alibaba.druid.pool.DruidDataSourceFactory;
import org.junit.jupiter.api.Test;

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

/**
 * @author 咕咕猫
 * @version 1.0
 * 测试druid的使用
 */
public class Druid_ {

    @Test
    public void testDruid() throws Exception {
        //1. 加入Druid jar包
        //2. 加入 配置文件 druid.properties , 将该文件拷贝项目的 src目录下
        //3. 创建 Properties 对象, 读取配置文件
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\druid.properties"));

        //4. 创建一个指定参数的数据库连接池,Druid连接池
        DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);

        long start = System.currentTimeMillis();
        for (int i = 0; i < 500000; i++) {
            Connection connection = dataSource.getConnection();
//            System.out.println("连接成功");
            connection.close();
        }
        long end = System.currentTimeMillis();
        System.out.println("druid 连接池 操作 500000 耗时=" + (end -start));

    }
}

3.3.3 将JDBCUtils工具类改成Druid(德鲁伊)实现

package com.learn.jdbc.datasource;

import com.alibaba.druid.pool.DruidDataSourceFactory;

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

/**
 * @author 咕咕猫
 * @version 1.0
 * 基于Druid数据库连接池
 */
public class JDBCUtilsByDruid {

    private static DataSource ds;

    //在静态代码块里 完成ds初始化
    static {
        Properties properties = new Properties();
        try {
            properties.load(new FileInputStream("src\\druid.properties"));
            ds = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //编写getConnection方法
    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }

    //关闭连接,在数据库连接池技术中,close不是真的断掉连接,而是把使用的connection对象放回连接池
    public static void close(ResultSet resultSet, Statement statement, Connection connection){

        try {
            if (resultSet != null){
                resultSet.close();
            }
            if (statement != null){
                statement.close();
            }
            if(connection != null){
                connection.close();
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}
package com.learn.jdbc.datasource;


import com.alibaba.druid.pool.DruidPooledConnection;
import com.learn.jdbc.utils.JDBCUtils;
import org.junit.jupiter.api.Test;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;

/**
 * @author 咕咕猫
 * @version 1.0
 */
public class JDBCUtilsByDruid_Use {
    @Test
    public void testSelect() {

        System.out.println("使用Druid方式完成");
        //1.得到连接
        Connection connection = null;

        //2.组织一个sql
        String sql = "select * from actor where id >= ?";
        PreparedStatement preparedStatement = null;
        ResultSet set = null;
        //3.创建PreparedStatement对象
        try {
            connection = JDBCUtilsByDruid.getConnection();
            System.out.println(connection.getClass()); //com.alibaba.druid.pool.DruidPooledConnection
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setInt(1, 1);//给?号赋值
            //执行,得到结果集
            set = preparedStatement.executeQuery();
            //遍历该结果集
            while (set.next()) {
                int id = set.getInt("id");
                String name = set.getString("name");
                String sex = set.getString("sex");
                Date borndate = set.getDate("borndate");
                String phone = set.getString("phone");
                System.out.println(id + "\t" + name + "\t" + sex + "\t" + borndate + "\t" + phone);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            JDBCUtilsByDruid.close(set, preparedStatement, connection);
        }
    }


    //使用土方法解决ResultSet封装到ArrayList集合中
    @Test
    public ArrayList<Actor> testSelectToArrayList() {

        System.out.println("使用Druid方式完成");
        //1.得到连接
        Connection connection = null;

        //2.组织一个sql
        String sql = "select * from actor where id >= ?";
        PreparedStatement preparedStatement = null;
        ResultSet set = null;
        ArrayList<Actor> list = new ArrayList<Actor>();//创建ArrayList对象,存放Actor对象
        //3.创建PreparedStatement对象
        try {
            connection = JDBCUtilsByDruid.getConnection();
            System.out.println(connection.getClass()); //com.alibaba.druid.pool.DruidPooledConnection
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setInt(1, 1);//给?号赋值
            //执行,得到结果集
            set = preparedStatement.executeQuery();
            //遍历该结果集
            while (set.next()) {
                int id = set.getInt("id");
                String name = set.getString("name");
                String sex = set.getString("sex");
                Date borndate = set.getDate("borndate");
                String phone = set.getString("phone");
                //System.out.println(id + "\t" + name + "\t" + sex + "\t" + borndate + "\t" + phone);
                //把得到的resultset的记录,封装到Actor对象,放入到list集合
                list.add(new Actor(id, name, sex, borndate, phone));
            }

            System.out.println("list集合数据=" + list);

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            JDBCUtilsByDruid.close(set, preparedStatement, connection);
        }
        //因为ArrayList和connection没有任何关联,所以该集合可以复用
        return list;
    }
}

四、Apache—DBUtils

4.1 先分析一个问题

1. 关闭connection后,resultSet结果集无法使用

2. resultSet不利于数据的管理

3. 示意图

    //使用土方法解决ResultSet封装到ArrayList集合中
    @Test
    public ArrayList<Actor> testSelectToArrayList() {

        System.out.println("使用Druid方式完成");
        //1.得到连接
        Connection connection = null;

        //2.组织一个sql
        String sql = "select * from actor where id >= ?";
        PreparedStatement preparedStatement = null;
        ResultSet set = null;
        ArrayList<Actor> list = new ArrayList<Actor>();//创建ArrayList对象,存放Actor对象
        //3.创建PreparedStatement对象
        try {
            connection = JDBCUtilsByDruid.getConnection();
            System.out.println(connection.getClass()); //com.alibaba.druid.pool.DruidPooledConnection
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setInt(1, 1);//给?号赋值
            //执行,得到结果集
            set = preparedStatement.executeQuery();
            //遍历该结果集
            while (set.next()) {
                int id = set.getInt("id");
                String name = set.getString("name");
                String sex = set.getString("sex");
                Date borndate = set.getDate("borndate");
                String phone = set.getString("phone");
                //System.out.println(id + "\t" + name + "\t" + sex + "\t" + borndate + "\t" + phone);
                //把得到的resultset的记录,封装到Actor对象,放入到list集合
                list.add(new Actor(id, name, sex, borndate, phone));
            }

            System.out.println("list集合数据=" + list);

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            JDBCUtilsByDruid.close(set, preparedStatement, connection);
        }
        //因为ArrayList和connection没有任何关联,所以该集合可以复用
        return list;
    }

4.2 基本介绍

        commons—dbutils是Apache组织提供的一个开源JDBC工具类库,它是对JDBC的封装,使用dbutils能极大简化jdbc编码的工作量

  • DBUtils类

        ①QueryRunner类:该类封装了SQL的执行,是线程安全的。可以实现增、删、改、查、批处理

        ②使用QueryRunner类实现查询

        ③ResultSetHandler接口:该接口用于处理 java.sql.ResultSet,将数据按要求转换为另一种形式

ArrayHandler:把结果集中的第一行数据转成对象数组。
ArrayListHandler:把结果集中的每一行数据都转成一个数组,再存放到List中。
BeanHandler:将结果集中的第一行数据封装到一个对应的JavaBean实例中。
BeanListHandler:将结果集中的每一行数据都封装到一个对应JavaBean实例中,存到List里

ColumnListHandler:将结果集中某一列的数据存放到List中。
KeyedHandler(name):将结果集中的每行数据都封装到Map里,再把这些map再存到一个map里,其key为指定的key。

MapHandler:将结果集中的第一行数据封装到一个Map里, key是列名,value就是对应的值。
MapListHandler:将结果集中的每一行数据都封装到一个Map里,然后再存放到List

package com.learn.jdbc.datasource;

import jdk.nashorn.internal.ir.CallNode;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import org.junit.jupiter.api.Test;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

/**
 * @author 咕咕猫
 * @version 1.0
 */
public class DBUtils_USE {

    //使用 apache-DBUtils 工具类 + druid 完成对表的 crud 操作
    @Test
    public void testQueryMany() throws SQLException {

        //1. 得到连接
        Connection connection = JDBCUtilsByDruid.getConnection();
        //2.使用DBUtils的类和接口,先引入DBUtils相关的jar文件,加入到本Project
        //3.创建QueryRunner
        QueryRunner queryRunner = new QueryRunner();
        //4.就可以执行相关的方法,返回ArrayList结果集
        String sql = "select * from actor where id >= ?";
        //解读
        //(1)query 方法就是执行 sql 语句,得到 resultset ---封装到 --> ArrayList 集合中
        //(2) 返回集合
        //(3) connection: 连接
        //(4) sql : 执行的 sql 语句
        //(5) new BeanListHandler<>(Actor.class): 在将 resultset -> Actor 对象 -> 封装到 ArrayList
        // 底层使用反射机制 去获取 Actor 类的属性,然后进行封装
        //(6) 1 就是给 sql 语句中的? 赋值,可以有多个值,因为是可变参数 Object... params
        //(7) 底层得到的 resultset ,会在 query 关闭, 关闭 PreparedStatmen
        /**
         * 分析queryRunner.query方法:
         * public <T> T query(Connection conn, String sql, ResultSetHandler<T> rsh, Object... params) throws SQLException {
         *         PreparedStatement stmt = null;//定义PreparedStatement对象
         *         ResultSet rs = null;//返回ResultSet结果集
         *         Object result = null;//返回ArrayList
         *
         *         try {
         *             stmt = this.prepareStatement(conn, sql);//创建PreparedStatement
         *             this.fillStatement(stmt, params);//对sql进行?赋值
         *             rs = this.wrap(stmt.executeQuery());//执行sql,返回resultSet
         *             result = rsh.handle(rs);返回resultSet ----->arraylist[result](使用反射对传入的class对象处理)
         *         } catch (SQLException var33) {
         *             this.rethrow(var33, sql, params);
         *         } finally {
         *             try {
         *                 this.close(rs);//关闭resultSet
         *             } finally {
         *                 this.close((Statement)stmt);//关闭preparedStatement对象
         *             }
         *         }
         *
         *         return result;
         *     }
         */
        List<Actor> list =
                queryRunner.query(connection, sql, new BeanListHandler<>(Actor.class), 1);
        System.out.println("输出集合的信息");
        for (Actor actor : list) {
            System.out.print(actor);
        }
        //释放资源
        JDBCUtilsByDruid.close(null, null, connection);
    }


    //演示 apache-dbutils + druid 完成 返回的结果是单行记录(单个对象)
    @Test
    public void testQuerySingle() throws SQLException {

        //1. 得到连接
        Connection connection = JDBCUtilsByDruid.getConnection();
        //2.使用DBUtils的类和接口,先引入DBUtils相关的jar文件,加入到本Project
        //3.创建QueryRunner
        QueryRunner queryRunner = new QueryRunner();
        //4.就可以执行相关的方法,返回ArrayList结果集
        String sql = "select * from actor where id = ?";
        //解读:因为我们返回的单行记录<--->单个对象,使用的Handler就是BeanHandler
        Actor actor = queryRunner.query(connection, sql, new BeanHandler<>(Actor.class), 2);
        System.out.println(actor);

        //释放资源
        JDBCUtilsByDruid.close(null, null, connection);
    }


    //演示 apache-dbutils + druid 完成查询结果是单行单列-返回的就是 object
    @Test
    public void testScalar() throws SQLException {

        //1. 得到连接
        Connection connection = JDBCUtilsByDruid.getConnection();
        //2.使用DBUtils的类和接口,先引入DBUtils相关的jar文件,加入到本Project
        //3.创建QueryRunner
        QueryRunner queryRunner = new QueryRunner();
        //4.就可以执行相关的方法,返回ArrayList结果集
        String sql = "select name from actor where id = ?";
        //解读:因为返回的是一个对象,所以handlerj就是ScalarHandler
        Object obj = queryRunner.query(connection, sql, new ScalarHandler(), 1);
        System.out.println(obj);

        //释放资源
        JDBCUtilsByDruid.close(null, null, connection);
    }


    //演示 apache-dbutils + druid 完成 dml (update, insert ,delete)
    @Test
    public void testDML() throws SQLException {

        //1. 得到连接
        Connection connection = JDBCUtilsByDruid.getConnection();
        //2.使用DBUtils的类和接口,先引入DBUtils相关的jar文件,加入到本Project
        //3.创建QueryRunner
        QueryRunner queryRunner = new QueryRunner();
        //4.就可以执行相关的方法,返回ArrayList结果集
//        String sql = "update actor set name = ? where id = ?";
//        String sql = "insert into actor values(null,?,?,?,?)";
        String sql = "delete from actor where id = ?";
        //解读
        //(1) 执行 dml 操作是 queryRunner.update()
        //(2) 返回的值是受影响的行数
//        int affectedRow = queryRunner.update(connection, sql, "林青霞", "女", "1966-10-10", "116");
        int affectedRow = queryRunner.update(connection, sql, 3);
        System.out.println(affectedRow > 0 ? "执行成功" : "执行没有影响到表");

        //释放资源
        JDBCUtilsByDruid.close(null, null, connection);
    }
}

4.3 表和JavaBean的类型映射关系

五、DAO和增删改查通用方法—BasicDAO 

5.1 先分析一个问题

apache-dbutils+ Druid简化了JDBC开发,但还有不足:
1. SQL语句是固定,不能通过参数传入,通用性不好,需要进行改进,更方便执行增删改查2. 对于select操作,如果有返回值,返回类型不能固定,需要使用泛型
3. 将来的表很多,业务需求复杂,不可能只靠一个Java类完成
4. 引出--->BasicDAO画出示意图,看看在实际开发中,应该如何处理

5.2 基本说明

1. DAO:全称:data access object(数据访问对象)

2. 这样的通用类称为BasicDAO,是专门和数据库交互的,即完成对数据库(表)的crud操作

3. 在BasicDAO的基础上,实现一张表对应一个DAO,更好的完成功能

 

package com.learn.dao_.dao;

import com.learn.jdbc.datasource.JDBCUtilsByDruid;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

/**
 * @author 咕咕猫
 * @version 1.0
 * 开发 BasicDAO , 是其他 DAO 的父类, 使用到 apache-dbutils
 */
public class BasicDAO<T> { //泛型指定具体类型

    private QueryRunner qr = new QueryRunner();

    //开发通用的dml方法,针对任意的表
    public int update(String sql, Object... parameters) {

        Connection connection = null;

        try {
            connection = JDBCUtilsByDruid.getConnection();
            int update = qr.update(connection, sql, parameters);
            return update;

        } catch (SQLException e) {
            throw new RuntimeException(e); //将编译异常转成运行异常抛出
        } finally {
            JDBCUtilsByDruid.close(null, null, connection);
        }
    }


    //返回多个对象(即查询的结果是多行),针对任意的表

    /**
     * @param sql        sql 语句,可以有 ?
     * @param clazz      传入一个类的 Class 对象 比如 Actor.class
     * @param parameters 传入 ? 的具体的值,可以是多个
     * @return 根据 Actor.class 返回对应的 ArrayList 集合
     */
    public List<T> queryMulti(String sql, Class<T> clazz, Object... parameters) {

        Connection connection = null;
        try {
            connection = JDBCUtilsByDruid.getConnection();
            return qr.query(connection, sql, new BeanListHandler<T>(clazz), parameters);

        } catch (SQLException e) {
            throw new RuntimeException(e); //将编译异常转成运行异常抛出
        } finally {
            JDBCUtilsByDruid.close(null, null, connection);
        }
    }


    //查询单行结果 的通用方法
    public T querySingle(String sql, Class<T> clazz, Object... parameters) {

        Connection connection = null;
        try {
            connection = JDBCUtilsByDruid.getConnection();
            return qr.query(connection,sql,new BeanHandler<T>(clazz),parameters);

        } catch (SQLException e) {
            throw new RuntimeException(e); //将编译异常转成运行异常抛出
        } finally {
            JDBCUtilsByDruid.close(null, null, connection);
        }
    }


    //查询单行单列的方法,即返回单值的方法
    public Object queryScalar(String sql, Object... parameters){

        Connection connection = null;
        try {
            connection = JDBCUtilsByDruid.getConnection();
            return qr.query(connection,sql,new ScalarHandler(),parameters);

        } catch (SQLException e) {
            throw new RuntimeException(e); //将编译异常转成运行异常抛出
        } finally {
            JDBCUtilsByDruid.close(null, null, connection);
        }
    }


}
package com.learn.dao_.test;

import com.learn.dao_.dao.ActorDAO;
import com.learn.dao_.domain.Actor;
import org.junit.jupiter.api.Test;

import java.util.List;

/**
 * @author 咕咕猫
 * @version 1.0
 */
public class TestDAO {
@Test
    //测试 ActorDAO对 actor 表 crud 操作
    public void testActorDAO() {

        ActorDAO actorDAO = new ActorDAO();
        //1.查询
        List<Actor> actors = actorDAO.queryMulti("select * from actor where id >= ?", Actor.class, 1);
        System.out.println("===查询结果===");
        for (Actor actor : actors) {
            System.out.println(actor);
        }

        //2. 查询单行记录
        Actor actor = actorDAO.querySingle("select * from actor where id = ?", Actor.class, 6);
        System.out.println("====查询单行结果====");
        System.out.println(actor);

        //3. 查询单行单列
        Object o = actorDAO.queryScalar("select name from actor where id = ?", 6);
        System.out.println("====查询单行单列值===");
        System.out.println(o);

        //4. dml 操作 insert ,update, delete
        int update = actorDAO.update("insert into actor values(null, ?, ?, ?, ?)", "张无忌", "男", "2000-11-11", "999");
        System.out.println(update > 0 ? "执行成功" : "执行没有影响表");
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值