自定义数据库工具类,以及三种常用的连接池DBCP、C3p0、Druid

一.自定义数据库工具类DbUtils
1.1

由于多个地方都需要使用数据库连接和释放,所以把功能封装到工具类中DbUtils
四个功能:1注册驱动 2 获取连接 3 释放资源 4 执行命令 【5 执行查询】
注册驱动 需要四个基本属性 url Driver user password
1.为了代码更加的灵活 我们通常都是把 这些 配置在属性文件中 ,通常命名为db.properties.
2.然后再将属性文件用类加载器 加载到程序中去,具体步骤和代码如下:

public class DbUtils {
    private static String driver;
    private static String url;
    private static String user;
    private static String password;
    static{
    //这种方式  太麻烦  我们通常采用配置文件方式来加载
//        driver="com.mysql.jdbc.Driver";
//        url="jdbc:mysql://localhost:3306/myschool?useSSL=true&characterEncoding=utf8";
//        user="root";
//        password="root";

        //注册驱动
        try {
            //读取文件1  此方式  src目录下太过于局限
//            Properties properties=new Properties();
//            FileInputStream fis=new FileInputStream("src\\db.properties");
//            properties.load(fis);
//            fis.close();

            //读取文件2 使用类加载器 加载配置文件(推荐使用)
            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");  //获取url
            user=properties.getProperty("user");//获取user
            password=properties.getProperty("password");//获取密码

            Class.forName(driver);//加载驱动
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("注册驱动失败");
        }
    }
    //获取连接  (后面会用连接池技术来获取链接)
    public static Connection getConnection(){
        try {
            return DriverManager.getConnection(url, user, password);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
//关闭各种要关闭的类
    public static void closeAll(Connection conn, Statement stat, ResultSet rs){
        try {
            if(rs!=null){
                rs.close();
            }
            if(stat!=null){
                stat.close();
            }
            if(conn!=null){
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
//执行通用查询语句
    public static int executeUpdate(String sql,Object...params){ //insert update delete  ?????
        Connection conn =null;
        PreparedStatement pstat=null;
        try {
            conn = getConnection();
            pstat = conn.prepareStatement(sql);
            //设置参数
            if(params!=null){
                for (int i = 0; i < params.length; i++) {
                    pstat.setObject(i+1, params[i]);
                }
            }
            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){
    //Class<T> class1 是为了获取对象   传进来什么类型  就是什么类型
        List<T> list=new ArrayList<>();
        Connection conn=null;
        PreparedStatement pstat=null;
        ResultSet rs=null;
        //查询数据
        try {
            conn=getConnection();
            pstat = conn.prepareStatement(sql);
            if(params!=null){
                for (int i = 0; i < params.length; i++) {
                    pstat.setObject(i+1, params[i]);
                }
            }
            rs = pstat.executeQuery();
            //获取rs中的列名
            ResultSetMetaData metaData = rs.getMetaData();
            while(rs.next()){
                //创建一个对象
                T t=convertToObject(metaData, rs, class1);
                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=null;
        PreparedStatement pstat=null;
        ResultSet rs=null;
        //查询数据
        try {
            conn=getConnection();
            pstat = conn.prepareStatement(sql);
            if(params!=null){
                for (int i = 0; i < params.length; i++) {
                    pstat.setObject(i+1, params[i]);
                }
            }
            rs = pstat.executeQuery();
            //获取rs中的列名
            ResultSetMetaData metaData = rs.getMetaData();
            if(rs.next()){
                //创建一个对象
                return convertToObject(metaData, rs, class1);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            closeAll(conn, pstat, rs);
        }
        return null;
    }

    public static <T> T convertToObject(ResultSetMetaData metaData,ResultSet rs,Class<T> class1){
        try {
            T t=class1.newInstance();
            for(int i=0;i<metaData.getColumnCount();i++){
                String columnLabel=metaData.getColumnLabel(i+1);
                Object value = rs.getObject(columnLabel);//empno  ename job
                //System.out.println(columnLabel+"==="+value);
                //创建属性描述符
                try {
                    PropertyDescriptor pd=new PropertyDescriptor(columnLabel, class1);
                    if(pd!=null){
                        //System.out.println(pd.getName());
                        Method writeMethod = pd.getWriteMethod(); //setEmpno setEname setJob
                        writeMethod.invoke(t,value);
                    }
                } catch (Exception e) {
                    continue;
                }
            }
            return t;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
1.2Dao模式

Dao模式就是将业务所要实现的功能,都集中到接口中去,然后创建接口的实现类,利用实现类来对业务进行功能的实现。

DAO模式的组成部分
​ 1 DAO接口(主要包 添加 修改 查询 删除方法)
​ 2 DAO实现类
​ 3 实体类 (domain(领域)、beans、entity、pojo、model)
​ --作用:用在数据访问代码和业务逻辑代码之间通过实体类来传输数据
​ --实体类特征:
​ ◦属性一般使用private修饰
​ ◦提供public修饰的getter/setter方法
​ ◦实体类提供无参构造方法,根据业务提供有参构造
​ ◦实现java.io.Serializable接口,支持序列化机制

二.常用的三种连接池

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

2.1 DBCP连接池的使用

使用不同的连接池需要导入不同的jar包,DBCP需要导入的jar包:
mysql驱动包
commons-dbcp.jar
commons-pool.jar
commons-logging.jar 日志支持

还有就是使用硬编码或者软编码来配置信息
1.硬编码:所谓的硬编码方式就是在代码中添加配置,很麻烦,就像加载驱动时候直接在代码中写出来四种基本属性一样。
2.软编码:将配置信息写到配置文件中,用的时候加载就行。
项目中添加配置
​ 文件名称: 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

代码实现DBCP连接池:

public class DbUtils_DBCP {
//DBCP是BasicDataSource 类型
  private static BasicDataSource dataSource;
    static{
        try {
        Properties properties=new Properties();
        //类加载器 加载配置文件
        InputStream ins = DbUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcp.properties");
        properties.load(ins);
        ins.close();
        //给dataBase初始化赋值
        dataSource= BasicDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("初始化连接池失败");
        }
    }
    public static Connection getConnection(){
        try {
            //从数据库连接池获取连接,不用在加载驱动获取链接
          return dataSource.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
    }


测试类
public class TestDBCP_Utils {
    public static void main(String[] args) {
        try {
            for (int i = 1; i <=100 ; i++) {
                //从连接池中取出连接
                Connection con = DbUtils_DBCP.getConnection();
                //这里并不是关闭连接,而是释放连接  把连接放进连接池中
                con.close();
                System.out.println("获取连接"+i+": "+con.hashCode());
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

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

1. dbcp没有自动回收空闲连接的功能
   c3p0有自动回收空闲连接功能
	      
 2. dbcp需要手动加载配置文件
      c3p0自动加载

C3p需要的jar包:
c3p0-0.9.1.2.jar
​ mchange-commons-java-0.2.11.jar
​ mysql驱动包

c3p0是在外部添加配置文件,工具直接进行应用,因为直接引用,所以要求固定的命名和文件位置,该连接池不需要初始化,直接new就行,但是配日志文件格式要求固定
文件位置: src

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

配置文件名称必须是:c3p0-config.xml/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
c3p0.checkoutTimeout=5000

==注意:

1: c3p0的配置文件内部可以包含命名配置文件和默认配置文件!默认是选择默认配置!如果需要切换命名配置可以在创建c3p0连接池的时候填入命名即可!
2:如果xml配置文件和属性文件都存在时,xml优先级高于属性文件

代码实现:

public class DbUtils_C3p0 {
//c3p0默认的是ComboPooledDataSource 类型
    private static ComboPooledDataSource dataSource;
    static{
      //c3p0自动初始化  自动加载配置文件  但是  配置文件的名字固定  而且文件中的  属性前加c3p0前缀
        dataSource=new ComboPooledDataSource();
    }
    public static Connection getConnection(){
        try {
            return dataSource.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
    }

//测试类
public class TestDBCP_C3p0 {
    public static void main(String[] args) {
        try {
            for (int i = 1; i <=100 ; i++) {
                //从连接池中取出连接
                Connection con = DbUtils_C3p0.getConnection();
                //释放连接  把连接放进连接池中
                con.close();
                System.out.println("获取连接"+i+": "+con.hashCode());
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
2.3Druid连接池(重点使用)

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

配置文件 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

jar包:
druid-1.1.5.jar

代码实现:

public class DbUtils_Druid {
  private static DruidDataSource dataSource;
    static{
        try {
        Properties properties=new Properties();
        //类加载器 加载配置文件
        InputStream ins = DbUtils_Druid.class.getClassLoader().getResourceAsStream("druid.properties");
        properties.load(ins);
        ins.close();
        //给dataBase初始化赋值   因为  返回值是DataSourse类型  所以强转
        dataSource=(DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("初始化连接池失败");
        }
    }

    public static Connection getConnection(){
        try {
            //从数据库连接池获取连接
          return dataSource.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
    }


测试:
public class TestDruid_Utils {
    public static void main(String[] args) {
        try {
            for (int i = 1; i <=100 ; i++) {
                //从连接池中取出连接
                Connection con = DbUtils_Druid.getConnection();
                //释放连接  把连接放进连接池中
                con.close();
                System.out.println("获取连接"+i+": "+con.hashCode());
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值