• 5JDBC


    1.JDBC概述

    1.驱动

    • 为了能让程序员利用java程序操作数据库,数据库厂商提供了一套jar包,通过导入这个jar包就可以直接调用其中的方法操作数据库,这个jar包称之为驱动。两个数据库驱动互不兼容。
    • 行业中有很多种的数据库,要使用这么多数据库需要学习很多数据库驱动,对于程序员来说学习成本非常高。
    • 想要让java程序兼容数据库,所有的数据库驱动都实现了jdbc这套接口。

    2.JDBC简介

           JDBC全称为:Java Data Base Connectivity(java数据库连接),它主要由接口组成。

           组成JDBC的2个包:java.sql包  javax.sql包

           开发JDBC应用需要以上2个包的支持外,还需要导入相应JDBC的数据库实现(即数据库驱动)。

           不仅需要jdbc接口,还需要驱动这个实现,驱动中就是对jdbc接口的一些实现。

    有时候会发生classnotfoundExcption异常,主要原因如下:

    确认包已经被导入web工程目录。

    原来是tomcat找不到MYSQL JAR包的问题。后来又把mysql-connector-java-5.1.7-bin.jar导入到tomcat的lib目录下面就ok了,嘿……

    在java项目中,只需要引入mysql-connector-java-5.1.7-bin.jar就可以运行java项目。

    在web项目中,当Class.forName("om.mysql.jdbc.Driver");时myeclipse是不会去查找字符串,不会去查找驱动的。所以只需要把mysql-connector-java-5.1.7-bin.jar拷贝到tomcat下lib目录就可以了。

    3.   6步实现jdbc

    • 注册数据库驱动
    • 获取数据库连接
    • 创建传输器
    • 传输sql并返回结果
    • 遍历结果
    • 关闭资源

     在使用的时候一般导入的是接口而不是具体类,因为JDBC是对应不同的数据库驱动,所以如果采用的是具体类的话,更改了数据库代码就全要大改,而采用接口就不会了,因为所以的数据库都要实现JDBC接口。

    package cn.tedu.jdbc;
    
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    
    import com.mysql.jdbc.Driver;
    
    public class Demo1 {
        public static void main(String[] args) {
            Connection conn=null;
            ResultSet rs=null;
            Statement state=null;
             //获取数据库驱动
            //手动注册一次,底层注册一次,总共两次注册驱动,应该一次就可以啊?
            //代码与mysql驱动包包名绑死,如果切换数据库则要修改导入包名
            //DriverManager.registerDriver(new Driver());
            try {
                Class.forName("com.mysql.jdbc.Driver");
                //创建数据库连接
                //Connection conn=DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/lx", "root", "root"); //jdbc是主协议 :mysql是子协议
                conn=DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/lx?&user=root&password=root");
                //获取传输器
                state=conn.createStatement();
                //利用传输器传输sql,并获取返回结果
                rs=state.executeQuery("select * from exam"); //增删改用excuteUpdate()
                //遍历结果
                while(rs.next()) {
                    int id=    rs.getInt("id");
                    String name=    rs.getString("name");
                    System.out.println(id+""+name);
    
                }
            } catch (Exception e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
            finally {
    
                //关闭资源  后创建的先关闭
                if(rs!=null)
                {
                    try {
                        rs.close();//关闭resultSet防止返回的结果堆积在内存
                    } catch (SQLException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                        throw new RuntimeException(e);
    
                    } 
                    finally {
                        rs=null; //置空交给GC处理
                    }
                }
    
    
                if(state!=null)
                {
                    try {
                        state.close();//关闭掉传输器
                    } catch (SQLException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                        throw new RuntimeException(e);
                    }
                    finally {
                        state=null;
                    }
                
                }
                if(conn!=null)
                {
                    try {
                        conn.close();//关闭掉连接,mysql有最大连接数的,不关闭就一直占用着连接数
                    } catch (SQLException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                        throw new RuntimeException(e);
                    }
                    finally {
                        conn=null;
                    }
                }
            }
        }
    
    }

    二程序详解

    1.    程序详解—DriverManager

    •      Jdbc程序中的DriverManager用于加载驱动,并创建与数据库的链接,这个API的常用方法:

    DriverManager.registerDriver(new Driver())

    DriverManager.getConnection(url, user, password),

    •      注意:在实际开发中并不推荐采用registerDriver方法注册驱动。原因有二:

    o     查看Driver的源代码可以看到,如果采用此种方式,会导致驱动程序注册两次,也就是在内存中会有两个Driver对象。

    o     程序依赖mysql的api,脱离mysql的jar包,程序将无法编译,将来程序切换底层数据库将会非常麻烦。

    •      推荐方式:Class.forName(“com.mysql.jdbc.Driver”);

    o     采用此种方式不会导致驱动对象在内存中重复出现,并且采用此种方式,程序仅仅只需要一个字符串,不需要依赖具体的驱动,使程序的灵活性更高。

    o     同样,在开发中也不建议采用具体的驱动类型指向getConnection方法返回的connection对象。

    2.    数据库URL

    URL用于标识数据库的位置,程序员通过URL地址告诉JDBC程序连接哪个数据库,URL的写法为:

     jdbc:mysql://localhost:3306/test ?参数名=参数值

    3.    常用数据库URL地址的写法:sid是库名

    Oracle写法:jdbc:oracle:thin:@localhost:1521:sid

    SqlServer—jdbc:microsoft:sqlserver://localhost:1433; DatabaseName=sid

    MySql—jdbc:mysql://localhost:3306/sid

    Mysql的url地址的简写形式: jdbc:mysql:///sid  这个简写的前提是跟得地址名和服务器就是localhost:3306

    常用属性:useUnicode=true&characterEncoding=UTF-8

    4.    程序详解—Connection

    o     Jdbc程序中的Connection,它用于代表数据库的链接,Connection是数据库编程中最重要的一个对象,客户端与数据库所有交互都是通过connection对象完成的,这个对象的常用方法:

    createStatement():创建向数据库发送sql的statement对象。

    prepareStatement(sql) :创建向数据库发送预编译sql的PrepareSatement对象。

    prepareCall(sql):创建执行存储过程的callableStatement对象。

    setAutoCommit(boolean autoCommit):设置事务是否自动提交。

    commit() :在链接上提交事务。

    rollback() :在此链接上回滚事务。

    5.    程序详解—Statement

    o     Jdbc程序中的Statement对象用于向数据库发送SQL语句, Statement对象常用方法:

    executeQuery(String sql) :用于向数据发送查询语句。

    executeUpdate(String sql):用于向数据库发送insert、update或delete语句

    execute(String sql):用于向数据库发送任意sql语句

    addBatch(String sql) :把多条sql语句放到一个批处理中。

    executeBatch():向数据库发送一批sql语句执行。

    6.    程序详解—ResultSet

    o     Jdbc程序中的ResultSet用于代表Sql语句的执行结果。Resultset封装执行结果时,采用的类似于表格的方式。ResultSet 对象维护了一个指向表格数据行的游标,初始的时候,游标在第一行之前,调用ResultSet.next() 方法,可以使游标指向具体的数据行,进行调用方法获取该行的数据。

    o     ResultSet既然用于封装执行结果的,所以该对象提供的都是用于获取数据的get方法:

    o     获取任意类型的数据

    getObject(int index)

    getObject(string columnName)

    o     获取指定类型的数据,例如:

    getString(int index)

    getString(String columnName)

    o     提问:数据库中列的类型是varchar,获取该列的数据调用什么方法?Int类型呢?bigInt类型呢?Boolean类型?

    o     常用数据类型转换表

    8.    ResultSet中的api

    o     ResultSet还提供了对结果集进行滚动的方法:

    next():移动到下一行

    Previous():移动到前一行

    absolute(int row):移动到指定行

    beforeFirst():移动resultSet的最前面。

    afterLast() :移动到resultSet的最后面。

    9.    程序详解—释放资源

    o     为什么要关闭资源?

    在安装数据库的时候,设置过最大连接数量,如果用了不还连接,别人就无法使用了。

    rs对象中可能包含很大的一个数据,对象保存在内存中,这样就十分占用内存。需要将他关闭。

    最晚创建的对象,最先关闭。

    o     Jdbc程序运行完后,切记要释放程序在运行过程中,创建的那些与数据库进行交互的对象,这些对象通常是ResultSet, Statement和Connection对象。

    o     特别是Connection对象,它是非常稀有的资源,用完后必须马上释放,如果Connection不能及时、正确的关闭,极易导致系统宕机。Connection的使用原则是尽量晚创建,尽量早的释放。

    o     为确保资源释放代码能运行,资源释放代码也一定要放在finally语句中。

    o     释放资源

    o     在关闭过程中可能会出现异常,为了能够关闭资源,需要将资源在finally中关闭。

    o     如果在finally中关闭资源则需要将conn,stat,rs三个对象定义成全局的变量。

    o     在conn,stat,rs三个变量出现异常的时候可能会关闭不成功,我们需要将他们在finally中置为null。conn,stat,rs这三个对象是引用,将引用置为null,它引用的对象就会被JVM回收,也能保证资源的释放。

    三.JDBC工具类

    配置文件放置在src文件夹下

    1. 提出冗余代码原因:

    在程序中,大量代码重复导致代码复用性低,工作效率低下,不美观。为了提供代码复用性,我们将创建连接和关闭连接提取到工具类中,方便以后调用,提升工作效率,增强代码复用性。

    package cn.tedu.utils;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    import java.util.Properties;
    
    //工具类   (工厂模式)
    public class JDBCUtils {
        //类中的方法只能通过类名.的方式来调用
        private JDBCUtils(){
            
        }
        public static Properties prop = new Properties();
        static{
            try {
                prop.load(new FileInputStream(new File(
                        //获取类加载器,JDBCUtils.class.getClassLoader()
                        //通过类加载器获取src目录,getResource()
                        //getResource()会得到从盘符到src目录的路径,
                        //直接在括号中书写文件名称即可得到文件路径。
                        //getPath()是为了将url转换为String类型的数据
                        JDBCUtils.class.getClassLoader().getResource("conf.properties").getPath())));
            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        //创建连接
        public static Connection getConnection() throws Exception{
            Class.forName(prop.getProperty("driver"));
            return DriverManager.getConnection(prop.getProperty("url")
                    , prop.getProperty("user"), prop.getProperty("password"));
        }
        //关闭资源
        public static void close(Connection conn,Statement stat,ResultSet rs){
            if(rs !=null){
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                    throw new RuntimeException(e);
                }finally{
                    rs = null;
                }
            }
            if(stat != null){
                try {
                    stat.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                    throw new RuntimeException(e);
                }finally{
                    stat = null;
                }
            }
            if(conn != null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                    throw new RuntimeException(e);
                }finally{
                    conn = null;
                }
            }
            
        }
        
        
        
        
        
    }

    四.登录案例练习

    1.Login程序需求:

    编写一个Java程序,要求在控制台输入用户名和密码,如果用户名和密码与数据库中的内容匹配,则提示登录成功,如果不匹配则提示登录失败。

    2.代码实现

    package cn.tedu.jdbc;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.Statement;
    import java.util.Scanner;
    
    import cn.tedu.utils.JDBCUtils;
    
    //登录功能
    public class Login {
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入用户名:");
            String username = sc.nextLine();
            System.out.println("请输入密码:");
            String password = sc.nextLine();
            //testLogin(username,password);
            PreparedtestLogin(username,password);
        }
    
        private static void PreparedtestLogin(String username, String password) {
            Connection conn = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                conn = JDBCUtils.getConnection();
                //发送sql主干
                ps = conn.prepareStatement("select * from user where username=? and password=?");
                //发送参数
                ps.setString(1, username); 
                ps.setString(2, password);
                //通知数据库服务器执行sql
                rs = ps.executeQuery();
                if(rs.next()){
                    System.out.println("登录成功");
                }else{
                    System.out.println("登录失败");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }finally{
                JDBCUtils.close(conn, ps, rs);
            }
        }
    
        private static void testLogin(String username, String password) { //这个是statement的
            Connection conn = null;
            Statement stat = null;
            ResultSet rs = null;
            try {
                conn = JDBCUtils.getConnection();
                stat = conn.createStatement();
                rs = stat.executeQuery("select * from user where username= '"+username+"' and password='"+password+"'");
                if(rs.next()){//如果为true,则证明能够查询到用户名,可以登录
                    System.out.println("登录成功");
                }else{//其他情况都不能登录。
                    System.out.println("登录失败");
                }
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }finally{
                JDBCUtils.close(conn, stat, rs);
            }
        }
    
    }

    5sql注入

    1.    sql注入攻击

    在网页中输入'#,或者' or '1=1 就能够直接登录。

    select * from user where name =  'name' and password = 'password';

    select * from user where name='name'#' and password='password'  //#后买你的都是注释

    由于执行的sql语句是在后台拼接出来的,其中有一部分内容是由用户从客户端传入,所以当用户传入数据中包含sql关键字时,就有可能通过这些关键字改变sql语句的语义,从而执行一些特殊的操作,这样的攻击方式就叫做sql注入攻击。

    2.  解决方案 采用Statement子接口PreparedStatement可以有效防止sql注入

                  PreparedStatement是Statement的一个子接口。

                  具有预编译功能。

                  a. PreparedStatement发送sql 的步骤:

                         i. 先将sql语句的主干部分发送到数据库服务器中,参数位置使用"?"预留,sql语句到达服务器中时,会立刻变成一段机器码(二进制数据)这个机器码不能被操作。

                         ii. 再讲sql语句中的参数发送到数据库服务器,这些参数到达数据库服务器中时只会作为纯文本内容使用。

                  b. PreparedStatement优势:

                         参数可以单独传入,避免sql语句的拼接错误。

                         拥有预编译功能,可以防止sql注入攻击。

                  c. 拓展:

                                PreparedStatement 和 statement 谁能传入参数?

                  两者都可以。

    六.批处理

          1. 批处理机制

                  a. 在sql语句执行过程中,每个JDBC六步仅操作一个语句,如果有多个sql要执行,则在成很大的代码冗余,书写不便利。

                  b. 可以将这些sql语句放入一个JDBC的批处理中,一同发送的数据库服务器执行。

           2. Statement批处理和PreparedStatement批处理

                  a. Statement批处理:

                         stat.addBatch(String sql);     添加sql 到批处理中

                         stat.addBatch(String sql);

                         stat.addBatch(String sql);

                         stat.executeBatch();      执行批处理

                  b.代码实现

    package cn.tedu.batch;
    
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.Statement;
    
    import cn.tedu.utils.JDBCUtils;
    
    //Statement批处理
    /*
         create table t1(id int,name varchar(20))
          insert into t1 values(1,'鸣人')
          insert into t1 values(2,'佐助')
          insert into t1 values(3,'小樱')
          insert into t1 values(4,'蝎子')
          
      Statement特点:
          优点:1.可以执行不同语义的sql
          缺点:1.没有预编译功能
              2.每次都会将sql语句完整的发送到数据库服务器。
              3.无法预留sql语句在服务器中,执行效率较低。
              
     
     * */
    public class StateBatchDemo1 {
        public static void main(String[] args) {
            Connection conn = null;
            Statement stat = null;
            ResultSet rs = null;
            try {
                conn = JDBCUtils.getConnection();
                stat = conn.createStatement();
                stat.addBatch("create table t1(id int,name varchar(20))");
                stat.addBatch("insert into t1 values(1,'鸣人')");
                stat.addBatch("insert into t1 values(2,'佐助')");
                stat.addBatch("insert into t1 values(3,'小樱')");
                stat.addBatch("insert into t1 values(4,'蝎子')");
                //通知数据库服务器
                stat.executeBatch();
                System.out.println("Statement批处理执行成功");
            } catch (Exception e) {
                e.printStackTrace();
            }finally{
                JDBCUtils.close(conn, stat, rs);
            }
        }
    
    }

     PreparedStatement批处理:

                         ps = conn.preparedStatement(String sql);

                         ps.setString(1,5);

     ps.addBatch() 添加sql参数 到批处理中
    ps.executeBatch() 执行批处理
      ps.clearBatch();  清空批处理

                      

    代码实现

    package cn.tedu.batch;
    
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    
    import cn.tedu.utils.JDBCUtils;
    //PreparedStatement批处理
    /*
     * PreparedStatement特点:
         优点:1.有预编译功能。
             2.将sql主干预留在数据库服务器中,不必重复发送sql语句。
             3.每次仅发送sql参数部分,执行效率较高。
         缺点:1.只能执行同一语义的sql语句。
     * 
     * */
    public class PreparedBatchDemo1 {
        public static void main(String[] args) {
            Connection conn = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                conn = JDBCUtils.getConnection();
                ps = conn.prepareStatement("insert into t1 values(?,?)");
                for(int i=0;i<100000;i++){
                    ps.setInt(1, i);
                    ps.setString(2, "name"+i);
                    ps.addBatch();
                    if(i%1000 ==0){
                        ps.executeBatch();
                        ps.clearBatch();
                        System.out.println("执行完毕,当前批次数为:"+i/1000);
                    }
    
                }
                //循环可能有不满一千的数据,通过本句来执行。
                ps.executeBatch();
                System.out.println("PreparedStatement执行完毕");
            } catch (Exception e) {
                e.printStackTrace();
            }finally{
                JDBCUtils.close(conn, ps, rs);
            }
        }
    }

    八连接池  连接池就是数据源

    a.    为什么使用连接池?

     

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

     

    o     它是将那些已连接的数据库连接存放在一个容器里(连接池),这样以后别人要连接数据库的时候,将不会重新建立数据库连接,会直接从连接池里取出可用的连接,用户使用完毕后,连接又重新还回到连接池中。

    o     注意:连接池里的连接将会一直保存在内存里,即使你没用也是一样。所以这个时候你得权衡一下连接池的连接数量了。

    2.    实现:

    o     编写连接池需实现javax.sql.DataSource接口。DataSource接口中定义了两个重载的getConnection方法:

    Connection getConnection()

    Connection getConnection(String username, String password)

    o     实现DataSource接口,并实现连接池功能的步骤:

    •      在DataSource构造函数中批量创建与数据库的连接,并把创建的连接保存到一个集合对象中。

    •      实现getConnection方法,让getConnection方法每次调用时,从集合对象中取一个Connection返回给用户。

    •      当用户使用完Connection,调用Connection.close()方法时,Collection对象应保证将自己返回到连接池的集合对象中,而不要把conn还给数据库。

    •      扩展Connection的close方法。

    •      在关闭数据库连接时,将connection存回连接池中,而并非真正的关闭。

     已开启服务器启动的时候就有一定的连接池数量,当你的服务器访问量达到了就会增加连接数量,所以是一点点增加连接数量的
    package cn.tedu.pool;
     
    import java.io.PrintWriter;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    import java.util.LinkedList;
    import java.util.List;
     
    import javax.sql.DataSource;
    /**
     * 手写连接池
     * @author 16
     *
     */
    public class MyPool implements DataSource{
            //定义一个能够存储连接的数据结构,由于经常使用插入和删除操作,所以List较好。
            private static List<Connection> pool = new LinkedList<Connection>();
            static{//在程序之后立刻创建一批连接以备使用
                    try{
                            Class.forName("com.mysql.jdbc.Driver");
                            for(int i=0;i<5;i++){
                                    //每次都创建一个新的连接对象
                                    Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb2?user=root&password=root");
                                    //将创建好的每一个连接对象添加到List中,模拟将连接加入连接池
                                    pool.add(conn);
                            }
                    }catch(Exception e){
                            e.printStackTrace();
                            throw new RuntimeException(e);
                    }
            }
            
            //创建连接(从连接池中取出一个连接)
            @Override
            public Connection getConnection() throws SQLException {
                    if(pool.size()==0){//取出连接之前首先判断当前连接池中是否还有连接,如果没有则重新创建一批连接
                            for(int i=0;i<5;i++){
                                    Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb2?user=root&password=root");
                                    pool.add(conn);
                            }
                    }
                    //从List中取出一个连接对象
                    //此处不能使用get(),get()方法只能读取对应下标的元素,没有将读取到的元素移除,如果是取出连接对象,应将对象移除。
                    Connection conn = pool.remove(0);
                    ConnDecorate connpool = new ConnDecorate(conn,this);
                    System.out.println("成功获取一个连接,池中还剩:"+pool.size()+"个连接");
                    return connpool;
            }
            //返还连接
            //手写一个返还连接的方法
            public void retConn(Connection conn){
                    try {
                            //归还的连接如果已经关闭或者为空,则不允许放入池中。
                            if(conn!=null&&!conn.isClosed()){
                                    pool.add(conn);
                                    System.out.println("成功还回一个连接,池中还剩:"+pool.size()+"个连接");
                            }
                    } catch (SQLException e) {
                            e.printStackTrace();
                    }
            }
            
            @Override
            public PrintWriter getLogWriter() throws SQLException {
                    return null;
            }
     
            @Override
            public void setLogWriter(PrintWriter out) throws SQLException {
                    // TODO Auto-generated method stub
                    
            }
     
            @Override
            public void setLoginTimeout(int seconds) throws SQLException {
                    // TODO Auto-generated method stub
                    
            }
     
            @Override
            public int getLoginTimeout() throws SQLException {
                    // TODO Auto-generated method stub
                    return 0;
            }
     
            @Override
            public <T> T unwrap(Class<T> iface) throws SQLException {
                    // TODO Auto-generated method stub
                    return null;
            }
     
            @Override
            public boolean isWrapperFor(Class<?> iface) throws SQLException {
                    // TODO Auto-generated method stub
                    return false;
            }
     
            
     
            @Override
            public Connection getConnection(String username, String password)
                            throws SQLException {
                    // TODO Auto-generated method stub
                    return null;
            }
     
    }

     

    c3p0的连接池技术比DBCP要好 ,推荐使用c3p0

    开源连接池:

    现在很多WEB服务器(Weblogic, WebSphere, Tomcat)都提供了DataSoruce的实现,即连接池的实现。通常我们把DataSource的实现,按其英文含义称之为数据源,数据源中都包含了数据库连接池的实现。

    也有一些开源组织提供了数据源的独立实现:

    DBCP 数据库连接池

    C3P0 数据库连接池

    实际应用时不需要编写连接数据库代码,直接从数据源获得数据库的连接。程序员编程时也应尽量使用这些数据源的实现,以提升程序的数据库访问性能。

    DBCP

    DBCP 是 Apache 软件基金组织下的开源连接池实现,使用DBCP数据源,应用程序应在系统中增加如下两个 jar 文件:

    Commons-dbcp.jar:连接池的实现

    Commons-pool.jar:连接池实现的依赖库

    DBCP示例代码:

    static{

    InputStream in = JdbcUtil.class.getClassLoader().

    getResourceAsStream("dbcpconfig.properties");

    Properties prop = new Properties();

    prop.load(in);

    BasicDataSourceFactory factory = new BasicDataSourceFactory();   //生成一个数据源工厂,通过工厂生产数据源

    dataSource = factory.createDataSource(prop);

    }

    #<!-- 初始化连接 -->

    initialSize=10

    #最大连接数量

    maxActive=50

    #<!-- 最大空闲连接 -->

    maxIdle=20

    #<!-- 最小空闲连接 -->

    minIdle=5

    #<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->

    maxWait=60000

    下面的橘色代码和红色代码都是配置数据库连接参数,橘色的是程序内设置,红色的是配置文件设置

    package cn.tedu.pool;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    import java.util.Properties;
    
    import javax.sql.DataSource;
    
    import org.apache.commons.dbcp.BasicDataSource;
    import org.apache.commons.dbcp.BasicDataSourceFactory;
    
    import cn.tedu.utils.JDBCUtils;
    
    //DBCP连接池测试使用
    public class DBCPDemo1 {
        public static void main(String[] args) {
            Connection conn = null;
            Statement stat = null;
            ResultSet rs =  null;
            BasicDataSource source = new BasicDataSource(); //basicDataSource是Dbcp 数据源的类型 ,这句话的意思是直接生成数据源 但是这个是没有配置信息的所以在下main我们要自己设置
            source.setDriverClassName("com.mysql.jdbc.Driver");
            source.setUrl("jdbc:mysql://localhost:3306/mydb1");
            source.setUsername("root");
            source.setPassword("root");
            //利用工厂生产一个DBCP数据源对象
            try {
                /*Properties prop = new Properties();
                prop.load(new FileInputStream(new File(DBCPDemo1.class.getClassLoader().getResource("dbcp.properties").getPath())));*/
                /*BasicDataSourceFactory factory = new BasicDataSourceFactory();
                DataSource source = factory.createDataSource(prop);*/
                conn = source.getConnection();
                stat = conn.createStatement();
                rs = stat.executeQuery("select * from exam");
                while(rs.next()){
                    int id = rs.getInt(1);
                    String name = rs.getString(2);
                    System.out.println("id:"+id+">>name:"+name);
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }finally{
                if(rs !=null){
                    try {
                        rs.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                        throw new RuntimeException(e);
                    }finally{
                        rs = null;
                    }
                }
                if(stat != null){
                    try {
                        stat.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                        throw new RuntimeException(e);
                    }finally{
                        stat = null;
                    }
                }
                if(conn != null){
                    try {
                        //归还连接
                        conn.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                        throw new RuntimeException(e);
                    }finally{
                        conn = null;
                    }
                }
            }
            
            
            
            
            
            
            
        }
    
    }

    2.c3p0开源连接库

    1.导入c3p0的jar包

     配置文件的键一定要和api文档一致并且首字母小写

    package cn.tedu.pool;
    
    import java.beans.PropertyVetoException;
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    
    import com.mchange.v2.c3p0.ComboPooledDataSource;
    
    //C3P0连接池测试使用
    public class C3P0Demo1 {
        public static void main(String[] args) {
            Connection conn  = null;
            Statement stat = null;
            ResultSet rs = null;
            
            ComboPooledDataSource source = new ComboPooledDataSource();
            try {
                /*source.setDriverClass("com.mysql.jdbc.Driver");
                source.setJdbcUrl("jdbc:mysql://localhost:3306/mydb1");
                source.setUser("root");
                source.setPassword("root");*/   //这个是自己写的配置
                conn = source.getConnection(); //如果配置文件的设置完全参照c3p0的要求,那么c3p0会自动获取配置文件的信息
                stat = conn.createStatement();
                rs = stat.executeQuery("select * from exam");
                while(rs.next()){
                    String name = rs.getString("name");
                    System.out.println("name:"+name);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }finally{
                if(rs !=null){
                    try {
                        rs.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                        throw new RuntimeException(e);
                    }finally{
                        rs = null;
                    }
                }
                if(stat != null){
                    try {
                        stat.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                        throw new RuntimeException(e);
                    }finally{
                        stat = null;
                    }
                }
                if(conn != null){
                    try {
                        //归还连接
                        conn.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                        throw new RuntimeException(e);
                    }finally{
                        conn = null;
                    }
                }
            }
            
            
            
            
            
            
            
        }
    
    }

     

  • 相关阅读:
    2019 Java 第四周总结
    2019第三周总结
    Java 第二周总结
    2019春第十二周作业
    Day3
    Day3
    Day3
    Day3
    Day2
    Day2
  • 原文地址:https://www.cnblogs.com/xuwangqi/p/11307582.html
Copyright © 2020-2023  润新知