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;
                }
            }
        }
        
        
        
        
        
        
        
    }

}

 

 

posted @ 2019-08-06 10:53  三十六烦恼风x  阅读(234)  评论(0编辑  收藏  举报