草庐IT

day48-JDBC和连接池04-2

liyuelian 2023-04-16 原文

JDBC和连接池04-2

10.数据库连接池

10.5Apache-DBUtils

10.5.1resultSet问题

先分析一个问题

在之前的程序中,执行sql语句后返回的结果集存在如下问题:

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

    如果要使用结果集,就不能关闭连接,不能关闭连接,就会反过来影响别的程序去连接数据库,就会对多并发程序造成很大的影响

  2. resultSet不利于数据的管理

    如果其它的方法或者程序想要使用结果集,也需要一直保持连接,影响其他程序对数据库的连接

  3. 使用返回信息也不方便

解决方法:

定义一个类,该类的属性和表的字段是对应关系/映射关系,即用类的属性和表的字段(列)关联起来
我们把这种类叫做JavaBean,或者POJO,Domain。

一个Actor对象就对应一条actor表的记录,将Actor对象放入到ArrayList集合中(将结果集的记录封装到ArrayList中)

10.5.2土方法完成封装

Actor类(JavaBean):

package li.jdbc.datasource;

import java.util.Date;

/**
 * Actor对象和actor表的记录对应
 */
public class Actor {//JavaBean/POJO/Domain
    private Integer id;
    private String name;
    private String sex;
    private Date borndate;
    private String phone;

    public Actor() {//一定要给一个无参构造器[反射需要]
    }

    public Actor(Integer id, String name, String sex, Date borndate, String phone) {
        this.id = id;
        this.name = name;
        this.sex = sex;
        this.borndate = borndate;
        this.phone = phone;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Date getBorndate() {
        return borndate;
    }

    public void setBorndate(Date borndate) {
        this.borndate = borndate;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    @Override
    public String toString() {
        return "\nActor{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", borndate=" + borndate +
                ", phone='" + phone + '\'' +
                '}';
    }
}

测试程序:

package li.jdbc.datasource;

import org.junit.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;

public class JDBCUtilsByDruid_Use {
    //使用土方法尝试解决ResultSet问题==封装=>ArrayList
    @Test
    public void testSelectToArrayList() {//也可以设置返回值
        System.out.println("使用druid方式完成");
        //1.得到连接
        Connection connection = null;
        //2.组织一个sql语句
        String sql = "Select * from actor where id >=?";
        //3.创建PreparedStatement对象
        PreparedStatement preparedStatement = null;
        ResultSet set = null;
        ArrayList<Actor> list = new ArrayList<>();//创建ArrayList对象,存放actor对象
        try {
            connection = JDBCUtilsByDruid.getConnection();
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setInt(1, 1);//给?号赋值
            //执行sql,得到结果集
            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");
                //把得到的当前 resultSet的一条记录,封装到一个Actor对象中,并放入arraylist集合
                list.add(new Actor(id,name,sex,borndate,phone));
            }

            System.out.println("list集合数据="+list);
            //or
            for (Actor actor:list) {
                System.out.println("id="+actor.getId()+"\t"+"name="+actor.getName());
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //关闭资源(不是真的关闭连接,而是将Connection对象放回连接池中)
            JDBCUtilsByDruid.close(set, preparedStatement, connection);
        }
        //因为ArrayList 和 connection 没有任何关联,所以该集合可以复用
        //return list;
    }
}

10.5.3Apache-DBUtils

  • 基本介绍

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

  • DbUtils类

  1. QueryRunner类:该类封装了SQL的执行,是线程安全的。可以实现增、删、改、查、批处理
  2. 使用QueryRunner类实现查询
  3. ResultSetHandler接口:该接口用于处理 java.sql.ResultSet,将数据按要求转换为另一种形式
方法 解释
ArrayHandler 将结果集中的第一行数据转成对象数组
ArrayListHandler 把结果集中的每一行数据都转成一个数组,再存放到List中
BeanHandler 将结果集中的第一行数据封装到一个对应的JavaBean实例中
BeanListHandler 将结果集中的每一行数据都封装到一个对应的JavaBean实例中,再存放到List中
ScalarHandler 可以返回指定列的一个值或返回一个统计函数的值,比如count(1)
ColumnListHandler 将结果集中某一列的数据存放到List中
KeyedHandler(name) 将结果集中的每行数据都封装到Map中,再把这些map再存放到一个map里,其key为指定的key
MapHandler 将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值
MapListHandler 将结果集中的每一行数据都封装到一个Map里,然后再存放到List

DBUtils的jar包下载可以去官网下载

应用实例

使用DBUtils+数据库连接池(德鲁伊)方式,完成对表actor的crud操作

首先将DBUtils的jar包添加到项目的libs文件夹下面,右键选择add as library

Actor类详见10.5.2

DBUtils_USE:

package li.jdbc.datasource;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.junit.Test;

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

public class DBUtils_USE {

    //使用Apache-DBUtils工具类 + Druid 完成对表的crud操作
    @Test
    public void testQueryMany() throws SQLException {//返回结果是多行多列的情况
        //1.得到连接(Druid)
        Connection connection = JDBCUtilsByDruid.getConnection();
        //2.使用DBUtils类和接口(先引入相关的jar,加入到本地的project)
        //3.创建QueryRunner
        QueryRunner queryRunner = new QueryRunner();
        //4.然后就可以执行相关的方法,返回ArrayList结果集
        //String sql = "Select * from actor where id >=?";
        //注意 :sql语句也可以查询部分的列,没有查询的属性就在actor对象中置空
        String sql = "Select id,name 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语句中的?赋值,可以有多个值,因为是可变参数
         * (7) 底层得到的resultSet,会在query关闭,同时也会关闭PreparedStatement对象
         */
        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);
    }
}

10.5.4ApDBUtils源码分析

在上述10.5.3代码中,在List<Actor> list = queryRunner.query(connection, sql, new BeanListHandler<>(Actor.class), 1);语句旁打上断点,点击debug,点击step into

光标跳转到如下方法:

public <T> T query(Connection conn, String sql, ResultSetHandler<T> rsh,
        Object... params) throws SQLException {

    PreparedStatement stmt = null;//定义PreparedStatement对象
    ResultSet rs = null;//接收返回的resultSet
    T 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中[使用反射,对传入的class对象进行处理]

    } catch (SQLException e) {
        this.rethrow(e, sql, params);

    } finally {
        try {
            close(rs);//关闭resultSet
        } finally {
            close(stmt);//关闭preparedStatement
        }
    }

    return result;//返回ArrayList
}

10.5.5ApDBUtils查询

使用DBUtils+数据库连接池(德鲁伊)方式,完成对表actor的查询操作

1.多行多列
package li.jdbc.datasource;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.junit.Test;

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

public class DBUtils_USE {

    //返回结果是多行多列的情况
    @Test
    public void testQueryMany() throws SQLException {
        //得到连接(Druid)
        Connection connection = JDBCUtilsByDruid.getConnection();
        //创建QueryRunner
        QueryRunner queryRunner = new QueryRunner();
        //然后就可以执行相关的方法,返回ArrayList结果集
        //sql语句也可以查询部分的列,没有查询的属性就在actor对象中置空
        String sql = "Select id,name from actor where id >=?";
        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);
    }
}
2.单行多列
package li.jdbc.datasource;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;

import org.junit.Test;

import java.sql.Connection;

public class DBUtils_USE {

    //演示DBUtils+druid完成-返回的结果是单行记录(单个对象)的情况-单行多列
    @Test
    public void testQuerySingle() throws Exception {
        //1.得到连接
        Connection connection = JDBCUtilsByDruid.getConnection();
        //2.创建QueryRunner对象
        QueryRunner queryRunner = new QueryRunner();
        //3.执行相关方法,返回单个对象
        String sql = "Select * from actor where id =?";
        //因为我们返回的是单行记录,对应单个对象,
        // 因此使用的 Handler是BeanHandler:将结果集中的第一行数据封装到一个对应的JavaBean实例中
        Actor actor =
                queryRunner.query(connection, sql, new BeanHandler<>(Actor.class), 2);
        System.out.println(actor);
        //释放资源
        JDBCUtilsByDruid.close(null, null, connection);
    }
}
3.单行单列
package li.jdbc.datasource;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import org.junit.Test;

import java.sql.Connection;

public class DBUtils_USE {
   
    //演示DBUtils+druid完成-查询结果是单行单列的情况-返回的就是Object
    @Test
    public void testScalar() throws Exception {//Scalar 单一值
        //获取连接
        Connection connection = JDBCUtilsByDruid.getConnection();
        //创建QueryRunner对象
        QueryRunner queryRunner = new QueryRunner();
        //执行相关方法,返回单行单列
        String sql = "Select name from actor where id =?";
        //因为返回的是一个对象,因此使用的 Handler是 ScalarHandler
        Object obj = queryRunner.query(connection, sql, new ScalarHandler(), 1);
        System.out.println(obj);
        //释放资源
        JDBCUtilsByDruid.close(null,null,connection);
    }
}

10.5.6ApDBUtilsDML

使用DBUtils+数据库连接池(德鲁伊)方式,完成对表actor的DML(update,insert,delete)操作

package li.jdbc.datasource;

import org.apache.commons.dbutils.QueryRunner;
import org.junit.Test;

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


public class DBUtils_USE {

    //演示DBUtils+druid完成 dml操作
    @Test
    public void testDML() throws SQLException {
        //获取连接
        Connection connection = JDBCUtilsByDruid.getConnection();
        //创建QueryRunner对象
        QueryRunner queryRunner = new QueryRunner();
        //这里组织sql完成update,insert,delete
        //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.返回的值是受影响的行数,如果返回的是0,代表sql执行失败 或者 执行成功但是表没受影响
         */
        //int affectedRow = queryRunner.update(connection, sql,"黎明","女","1999-10-09","123");
        int affectedRow = queryRunner.update(connection, sql,1000);
        System.out.println(affectedRow > 0 ? "执行成功" : "执行没有影响到表");
        //释放资源
        JDBCUtilsByDruid.close(null, null, connection);
    }
}

10.6表和JavaBean的类型映射关系

有关day48-JDBC和连接池04-2的更多相关文章

  1. ruby - 续集在添加关联时访问many_to_many连接表 - 2

    我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以

  2. ruby - 无法在 60 秒内获得稳定的 Firefox 连接 (127.0.0.1 :7055) - 2

    我使用的是Firefox版本36.0.1和Selenium-Webdrivergem版本2.45.0。我能够创建Firefox实例,但无法使用脚本继续进行进一步的操作无法在60秒内获得稳定的Firefox连接(127.0.0.1:7055)错误。有人能帮帮我吗? 最佳答案 我遇到了同样的问题。降级到firefoxv33后一切正常。您可以找到旧版本here 关于ruby-无法在60秒内获得稳定的Firefox连接(127.0.0.1:7055),我们在StackOverflow上找到一个类

  3. kvm虚拟机安装centos7基于ubuntu20.04系统 - 2

    需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc

  4. ruby - 我的 Ruby IRC 机器人没有连接到 IRC 服务器。我究竟做错了什么? - 2

    require"socket"server="irc.rizon.net"port="6667"nick="RubyIRCBot"channel="#0x40"s=TCPSocket.open(server,port)s.print("USERTesting",0)s.print("NICK#{nick}",0)s.print("JOIN#{channel}",0)这个IRC机器人没有连接到IRC服务器,我做错了什么? 最佳答案 失败并显示此消息::irc.shakeababy.net461*USER:Notenoughparame

  5. ruby-on-rails - 连接字符串时如何在 <%=%> block 内输出 html_safe? - 2

    考虑一下:现在这些情况:#output:http://domain.com/?foo=1&bar=2#output:http://domain.com/?foo=1&bar=2#output:http://domain.com/?foo=1&bar=2#output:http://domain.com/?foo=1&bar=2我需要用其他字符串输出URL。我如何保证&符号不会被转义?由于我无法控制的原因,我无法发送&。求助!把我的头发拉到这里:\编辑:为了澄清,我实际上有一个像这样的数组:@images=[{:id=>"fooid",:url=>"http://

  6. ruby - Faye WebSocket,关闭处理程序被触发后重新连接到套接字 - 2

    我有一个super简单的脚本,它几乎包含了FayeWebSocketGitHub页面上用于处理关闭连接的内容:ws=Faye::WebSocket::Client.new(url,nil,:headers=>headers)ws.on:opendo|event|p[:open]#sendpingcommand#sendtestcommand#ws.send({command:'test'}.to_json)endws.on:messagedo|event|#hereistheentrypointfordatacomingfromtheserver.pJSON.parse(event.d

  7. ruby - 在 Ubuntu 14.04 中使用 Curl 安装 RVM 时出错 - 2

    我试图在Ubuntu14.04中使用Curl安装RVM。我运行了以下命令:\curl-sSLhttps://get.rvm.io|bash-sstable出现如下错误:curl:(7)Failedtoconnecttoget.rvm.ioport80:Networkisunreachable非常感谢解决此问题的任何帮助。谢谢 最佳答案 在执行curl之前尝试这个:echoipv4>>~/.curlrc 关于ruby-在Ubuntu14.04中使用Curl安装RVM时出错,我们在Stack

  8. ruby-on-rails - 什么会导致与 APNS 的连接间歇性断开连接? - 2

    我有一个ruby​​脚本可以打开与Apple推送服务器的连接并发送所有待处理的通知。我看不出任何原因,但当Apple断开我的脚本时,我遇到了管道损坏错误。我已经编写了我的脚本来适应这种情况,但我宁愿只是找出它发生的原因,这样我就可以在第一时间避免它。它不会始终根据特定通知断开连接。它不会以特定的字节传输大小断开连接。一切似乎都是零星的。您可以在单个连接上发送的数据传输或有效负载计数是否有某些限制?看到人们的解决方案始终保持一个连接打开,我认为这不是问题所在。我看到连接在3次通知后断开,我看到它在14次通知后断开。我从未见过它能超过14点。有没有人遇到过这种类型的问题?如何处理?

  9. ruby - 如何断开现有的 ruby​​ 续集与数据库的连接? - 2

    我的意思是之前建立的那个DB=Sequel.sqlite('my_blog.db')或DB=Sequel.connect('postgres://user:password@localhost/my_db')或DB=Sequel.postgres('my_db',:user=>'user',:password=>'password',:host=>'localhost')等等。Sequel::Database类没有名为“disconnect”的公共(public)实例方法,尽管它有一个“connect”。也许有人已经遇到过这个问题。我将不胜感激。 最佳答案

  10. ruby-on-rails - rails : Find tasks that were created on a certain day? - 2

    我有一个任务列表(名称、starts_at),我试图在每日View中显示它们(就像iCal)。deftodays_tasks(day)Task.find(:all,:conditions=>["starts_atbetween?and?",day.beginning,day.ending]end我不知道如何将Time.now(例如“2009-04-1210:00:00”)动态转换为一天的开始(和结束),以便进行比较。 最佳答案 deftodays_tasks(now=Time.now)Task.find(:all,:conditio

随机推荐