JDBC

JDBC

一、概述

1.什么是JDBC

JDBC(Java Data Base Connectivity,java数据库连接):是一种用于SQL语句的JavaAPI,可以为多种关系数据库提供统一的访问,它由一组用Java语言编写的类和接口组成。jdbc提供了一个基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序,同时,JDBC也时商标名。

2.什么是数据库驱动

  • 驱动:两个设备(应用)之间通信的桥梁。

3.为什么学习JDBC

没有JDBC的时候,如果现在要开发一套系统,使用Java连接MySQL数据库,那么这时候Java程序员需要了解MySQL驱动API,如果使用Java连接Oracle数据库,那么这个时候Java程序员需要了解Oracle数据库驱动API。

SUN公司提供一套统一的规范(接口)。然后各个数据库生产商提供这套接口的实现。这套接口规范就是JDBC的规范。

二、入门

1.环境准备

  1. 创建数据库和表

    create database web_test3;
    use web_test3;
    create table user(
        id int primary key auto_increment,
        username varchar(20),
        password varchar(20),
        nickname varchar(20),
        age int
    );
    insert into user values (null,'aaa','123','小丽',34);
    insert into user values (null,'bbb','123','大王',32);
    insert into user values (null,'ccc','123','小明',28);
    insert into user values (null,'ddd','123','大黄',21);
    
  2. 创建项目,引入jar包(mysql-connector-java-5.0.8-bin.jar)

2.代码实现

  • 开发步骤

    • 加载驱动
    • 获得连接
    • 基本操作
    • 释放资源
  • 代码实现

    import org.junit.Test;
    
    public class JDBCDemo1 {
     
        @Test
        /**
         \* JDBC的入门
         */
        public void demo1() throws Exception{
            // 1.加载驱动
            Class.forName("com.mysql.jdbc.Driver");
            // 2.获得连接
            Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/web_test3", "root", "abc");
            // 3.基本操作:执行SQL
            // 3.1获得执行SQL语句的对象
            Statement statement = conn.createStatement();
            // 3.2编写SQL语句:
            String sql = "select * from user";
            // 3.3执行SQL:
            ResultSet rs = statement.executeQuery(sql);
            // 3.4遍历结果集:
           while(rs.next()){
              System.out.print(rs.getInt("id")+" ");               System.out.print(rs.getString("username")+" ");     System.out.print(rs.getString("password")+" ");    System.out.print(rs.getString("nickname")+" ");
    System.out.print(rs.getInt("age"));
    System.out.println();
    }
            // 4.释放资源
            rs.close();
            statement.close();
            conn.close();
        }
    
    }
    

三、DriverManager:驱动管理类

作用一:注册驱动

registerDriver(Driver driver)

  • 这个方法可以完成驱动的注册,但是实际开发中一般不会使用这个方法完成驱动的注册!!!

  • 原因:如果需要注册驱动,就会使用DriverManager.registerDriver(new Driver());,但是查看源代码发现,在代码中有一段静态代码块,静态代码块已经调用了注册驱动的方法。

    static {
      try {
          java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException E) {
              throw new RuntimeException("Can't register driver");
      }
    }
    

    如果再手动调用该方法注册驱动,就会导致驱动被注册两次。实际开发中一般会采用:

    Class.forname("");来加载驱动

作用二:获得连接

getConnection(String url, String user, String password)建立给定数据库URL的连接

这个方法就是用来获得与数据库连接的方法:这个方法中有三个参数:

  • url:与数据库连接的路径
  • user:与数据库连接的用户名
  • password:与数据库连接的密码

主要关注的是url的写法:jdbc:mysql://localhost:3306/web_test3 注:如果连接本地书据库,可简写为 jdbc:mysql:///web_test3

  • jdbc:连接数据库的协议
  • mysql:是jdbc的子协议
  • localhost:连接的MySQL数据库服务器的主机地址。(连接是本机就可以写成localhost),如果连接不是本机的,就需要写上连接主机的IP地址。
  • 3306:MySQL数据库服务器的端口号
  • web_test3:数据库名称

四、Connection:与数据库连接对象

作用一:创建执行SQL语句的对象

createStatement()创建一个Statement对象来将SQL语句发送到数据库。

prepareCall(String sql)创建一个CallableStatement对象来调用数据库存储过程

prepareStatement(String sql)创建一个prepareStatement对象来将参数化的SQL语句发送到数据库

执行SQL语句对象:

  • Statement:执行SQL
  • CallableStatement:执行数据库中存储过程
  • PreparedStatement:执行SQL.对SQL进行预处理。解决SQL注入漏洞。

作用二:管理事务

setAutoCommit(boolean autoCommit)将此连接的自动提交模式设置为给定状态。

commit()使所有上一次提交/回滚后进行的更改成为持久更改,并释放Connection对象当前持有的所有数据库锁。

rollback()取消在当前事务中进行所有更改,并释放此Connection对象当前持有的所欲哦数据库锁。

五、Statement:执行SQL

作用一:执行SQL

execute(String sql)执行给定的SQL语句,该语句可能返回多个结果

excutQuery(String sql)执行给定的SQL语句,该语句返回单个ResultSet对象

excuteUpdate(String sql)执行给定SQL语句,该语句可能为INSERT语句,或者不返回任何内容的SQL语句(如SQL DDL语句)

执行SQL的方法

  • boolean execute(String sql); 执行查询,修改,添加,删除的SQL语句。
  • ResultSet executeQuery(String sql);执行查询(执行select语句)。
  • int executeUpate(String sql);执行修改,添加,删除的SQL语句。

作用二:执行批处理

addBatch(String sql)将给定的SQL命令添加到此Statement对象的当前命令列表中。

clearBatch()清空此Statement对象的当前SQL命令列表。

executeBatch()将一批命令交给数据库执行,如果全部命令执行成功,则返回更新技术组成的数组。

六、ResultSet:结果集

通过select语句的查询结果。

1.结果集的遍历

next()将光标从当前位置向前移一行

结果集遍历原理

jdbc.png

代码实现

while(rs.next()){
    System.out.print(rs.getInt("id")+" ");
    System.out.print(rs.getString("username")+" ");
    System.out.print(rs.getString("password")+" ");
    System.out.print(rs.getString("password")+" ");
    System.out.print(rs.getString("nickname")+" ");
    System.out.print(rs.getString("age"));
    System.out.print(rs.getInt("age"));
}

2.结果集的获取

int getInt(int columnIndex)以java编程语言中int的形式获取此ResultSet对象的当前行中指定列的值。

int getInt(String cloumnLabel)以Java编程语言中int的形式获取此ResultSet对象的当前行中指定列的值。

long getLong(String cloumnIndex)以Java编程语言中long的形式获取此ResultSet对象的当前行中指定列的值。

long getLong(String columnLabel)以Java编程语言中long的形式获取此ResultSet对象的当前行中指定列的值。

getString(int columnIndex)以Java编程语言中String的形式获取此ResultSet对象的当前行中指定列的值。

getString(String columnLabel)以Java编程语言中String的形式获取此ResultSet对象的当前行中指定列的值。

  • 结果集获取可以使用结果集中的:

    getXXX()方法通常都会有一个重载的方法。

    • getXXX(int columnIndex);
    • getXXX(String columnName);

七、JDBC资源释放

JDBC程序执行结束后,将与数据库进行交互的对象释放掉,通常是ResultSet,Statement,Connection。

这几个对象中尤其是Connection对象是非常稀有的。这个对象一定要做到尽量晚创建,尽早释放掉。
  • 将资源释放的代码写入到finally的代码块中。
  • 资源释放的代码应该写的标准:
if(rs !=null){
    try {
        rs.close();
    } catch (SQLException e) {
        e.printStackTrace();
    }            
    rs = null;
}
if(statement !=null){
    try {
        statement.close();
    } catch (SQLException e) {
        e.printStackTrace();
    }
    statement = null;
}
if(conn !=null){
    try {
        conn.close();
    } catch (SQLException e) {
        e.printStackTrace();
    }            
    conn = null;
}

八、CRUD操作

1.保存操作

@Test
    /**
     \* 保存操作的代码实现
     */
    **public** **void** demo1(){
        Connection conn = **null**;
        Statement stmt = **null**;
        **try**{
            // 注册驱动:
            Class.*forName*("com.mysql.jdbc.Driver");
            // 获得连接:
            conn = DriverManager.*getConnection*("jdbc:mysql:///web_test3", "root", "abc");
            // 执行操作:
            // 创建执行SQL语句对象:
            stmt = conn.createStatement();
            // 编写SQL语句:
            String sql = "insert into user values (null,'eee','123','阿黄',21)";
            // 执行SQL语句:
            int num = stmt.executeUpdate(sql);
            if(num > 0){
                System.out.println("保存用户成功!!!");
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            // 资源释放:
            if(stmt != null){
                try {
                   stmt.close();
                } catch (SQLException e) {
                   e.printStackTrace();
                }
                stmt = null;
            }
            if(conn != null){
                try {
                   conn.close();
                } catch (SQLException e) {
                   e.printStackTrace();
                }
                conn = null;
            }
        }
    }

2.修改操作

@Test
    /**
     * 修改操作的代码实现
     */
    public void demo2(){
        Connection conn = null;
        Statement stmt  = null;
        try{
            // 注册驱动:
            Class.forName("com.mysql.jdbc.Driver");
            // 获得连接
            conn = DriverManager.getConnection("jdbc:mysql:///web_test3", "root", "abc");
            // 执行操作:
            // 创建执行SQL语句的对象:
            stmt = conn.createStatement();
            // 编写SQL语句:
            String sql = "update user set password='abc',nickname='旺财' where id = 5";
            // 执行SQL语句:
            int num = stmt.executeUpdate(sql);
            if(num > 0){
                System.out.println("修改用户成功!!!");
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            // 资源释放:
            if(stmt != null){
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }   
                stmt = null;
            }
            if(conn != null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                conn = null;
            }
        }
    }

3.删除操作

@Test
    /**
     * 删除操作的代码实现
     */
    public void demo3(){
        Connection conn = null;
        Statement stmt = null;
        try{
            // 注册驱动:
            Class.forName("com.mysql.jdbc.Driver");
            // 获得连接:
            conn = DriverManager.getConnection("jdbc:mysql:///web_test3", "root", "abc");
            // 创建执行SQL语句对象:
            stmt = conn.createStatement();
            // 编写SQL:
            String sql = "delete from user where id = 5";
            // 执行SQL:
            int num = stmt.executeUpdate(sql);
            if(num > 0){
                System.out.println("删除用户成功!!!");
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            // 资源释放:
            if(stmt != null){
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                
                stmt = null;
            }
            if(conn != null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                conn = null;
            }
        }
    }

4.查询多条记录

@Test
    /**
     * 查询多条记录
     */
    public void demo4(){
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try{
            // 注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            // 获得连接
            conn = DriverManager.getConnection("jdbc:mysql:///web_test3", "root", "abc");
            // 执行操作
            // 创建执行SQL语句的对象:
            stmt = conn.createStatement();
            // 编写SQL:
            String sql = "select * from user";
            // 执行SQL:
            rs = stmt.executeQuery(sql);
            // 遍历结果集:
            while(rs.next()){
                System.out.println(rs.getInt("id")+" "+rs.getString("username")+" "+rs.getString("password"));
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            // 资源释放:
            if(rs != null){
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                
                rs = null;
            }
            if(stmt != null){
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                
                stmt = null;
            }
            if(conn != null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                conn = null;
            }
        }
    }

5.查询一条语句

@Test
    /**
     * 查询一条记录
     */
    public void demo5(){
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try{
            // 注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            // 获得连接
            conn = DriverManager.getConnection("jdbc:mysql:///web_test3", "root", "abc");
            // 执行SQL
            // 创建执行SQL语句对象:
            stmt = conn.createStatement();
            // 编写SQL:
            String sql = "select * from user where id = 4";
            rs = stmt.executeQuery(sql);
            // 判断就可以:
            if(rs.next()){
                System.out.println(rs.getInt("id")+" "+rs.getString("username")+" "+rs.getString("password"));
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            // 资源释放:
            if(rs != null){
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                
                rs = null;
            }
            if(stmt != null){
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                
                stmt = null;
            }
            if(conn != null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                conn = null;
            }
        }
    }

6.抽取一个JDBC的工具类

/**
 * JDBC的工具类
 * @author jt
 *
 */
public class JDBCUtils {
    private static final String driverClassName;
    private static final String url;
    private static final String username;
    private static final String password;
    
    static{
        driverClassName="com.mysql.jdbc.Driver";
        url="jdbc:mysql:///web_test3";
        username="root";
        password="abc";
    }

    /**
     * 注册驱动的方法
     */
    public static void loadDriver(){
        try {
            Class.forName(driverClassName);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 获得连接的方法
     */
    public static Connection getConnection(){
        Connection conn = null;
        try{
            // 将驱动一并注册:
            loadDriver();
            // 获得连接
            conn = DriverManager.getConnection(url,username, password);
        }catch(Exception e){
            e.printStackTrace();
        }
        return conn;
    }
    
    /**
     * 释放资源的方法
     */
    public static void release(Statement stmt,Connection conn){
        if(stmt != null){
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            
            stmt = null;
        }
        if(conn != null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            conn = null;
        }
    }
    
    public static void release(ResultSet rs,Statement stmt,Connection conn){
        // 资源释放:
        if(rs != null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            
            rs = null;
        }
        if(stmt != null){
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            
            stmt = null;
        }
        if(conn != null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            conn = null;
        }
    }
}

7.配置文件

  • 属性文件
    • 格式:扩展名是.properties
    • 内容:key=value
  • XML文件

8.提取信息到配置文件

  • 定义一个配置文件
jdbc3.png

9.在工具类中解析属性文件

static{
    Properties properties = new Properties();
    try{
        properties.load(new FileInputStream("src/db.properties"));
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } 
    driveClassName = properties.getProperty("driverClassName");
    url = properties.getProperty("url");
    username = properties.getProperty("username");
    password = properties.getProperty("password");
}

九、SQL注入漏洞

  • 输入用户名
    • aaa’ or ‘1=1 密码随意
    • aaa’ -- 密码随意
public class JDBCDemo4 {
    @Test
    /**
     *SQL注入漏洞的演示
     */
     public void demo1(){
         UserDao userDao = new UserDao();
         //boolean flag = userDao.login("aaa' or '1=1","d");
         boolean flag = userDao.login("aaa' --","d");
         if(flag) {
             System.out.println("登录成功!");
         } else {
             System.out.println("登陆失败!");
         }
     }
}

1.注入漏洞解决

需要采用PreparedStatement对象解决SQL注入漏洞。这个对象将SQL预先进行编译,使用?作为占位符。?所代表内容是SQL所固定。再次传入变量(包含SQL的关键字)。这个时候也不会识别这些关键字。
public class UserDao {
    
    public boolean login(String username,String password){
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        // 定义一个变量:
        boolean flag = false;
        try{
            // 获得连接:
            conn = JDBCUtils.getConnection();
            // 编写SQL语句:
            String sql = "select * from user where username = ? and password = ?";
            // 预编译SQL
            pstmt = conn.prepareStatement(sql);
            // 设置参数:
            pstmt.setString(1, username);
            pstmt.setString(2, password);
            // 执行SQL语句:
            rs = pstmt.executeQuery();
            if(rs.next()){
                // 说明根据用户名和密码可以查询到这条记录
                flag = true;
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            JDBCUtils.release(rs, pstmt, conn);
        }
        return flag;
    }

2.CRUD操作

保存

@Test
    /**
     * 保存操作
     */
    public void demo1(){
        Connection conn = null;
        PreparedStatement pstmt = null;
        try{
            // 获得连接:
            conn = JDBCUtils.getConnection();
            // 编写SQL语句:
            String sql = "insert into user values (null,?,?,?,?)";
            // 预编译SQL:
            pstmt = conn.prepareStatement(sql);
            // 设置参数:
            pstmt.setString(1, "eee");
            pstmt.setString(2, "abc");
            pstmt.setString(3, "旺财");
            pstmt.setInt(4, 32);
            // 执行SQL
            int num = pstmt.executeUpdate();
            if(num > 0){
                System.out.println("保存成功!");
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            JDBCUtils.release(pstmt, conn);
        }
    }

修改

@Test
    /**
     * 修改操作
     */
    public void demo2(){
        Connection conn = null;
        PreparedStatement pstmt = null;
        try{
            // 获得连接:
            conn = JDBCUtils.getConnection();
            // 编写SQL语句:
            String sql = "update user set username = ?,password =?,nickname=?,age = ? where id = ?";
            // 预编译SQL:
            pstmt = conn.prepareStatement(sql);
            // 设置参数:
            pstmt.setString(1, "abc");
            pstmt.setString(2, "1234");
            pstmt.setString(3, "旺旺");
            pstmt.setInt(4, 23);
            pstmt.setInt(5, 6);
            // 执行SQL:
            int num = pstmt.executeUpdate();
            if(num > 0){
                System.out.println("修改成功!");
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            JDBCUtils.release(pstmt, conn);
        }
    }

删除

@Test
    /**
     * 删除操作
     */
    public void demo3(){
        Connection conn = null;
        PreparedStatement pstmt  = null;
        try{
            // 获得连接:
            conn = JDBCUtils.getConnection();
            // 编写SQL语句:
            String sql = "delete from user where id = ?";
            // 预编译SQL
            pstmt = conn.prepareStatement(sql);
            // 设置参数:
            pstmt.setInt(1, 4);
            // 执行SQL:
            int num = pstmt.executeUpdate();
            if(num > 0){
                System.out.println("删除成功!");
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            JDBCUtils.release(pstmt, conn);
        }
    }

查询

@Test
    /**
     * 查询操作
     */
    public void demo4(){
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try{
            // 获得连接:
            conn = JDBCUtils.getConnection();
            // 编写SQL:
            String sql = "select * from user";
            // 预编译SQL:
            pstmt = conn.prepareStatement(sql);
            // 设置参数:
            // 执行SQL:
            rs = pstmt.executeQuery();
            // 遍历结果集:
            while(rs.next()){
                System.out.println(rs.getInt("id")+" "+rs.getString("username")+" "+rs.getString("password")+" "+rs.getString("nickname"));
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            JDBCUtils.release(rs, pstmt, conn);
        }
    }

十、批处理

1.什么是批处理

之前进行JDBC的操作的时候,都是一条SQL语句执行。现在如果使用批处理,可以将一批SQL一起执行。

2.批处理基本使用

@Test
    /**
     * 批处理基本操作
     */
    public void demo1(){
        Connection conn = null;
        Statement stmt = null;
        try{
            // 获得连接:
            conn = JDBCUtils.getConnection();
            // 创建执行批处理对象:
            stmt = conn.createStatement();
            // 编写一批SQL语句:
            String sql1 = "create database test1";
            String sql2 = "use test1";
            String sql3 = "create table user(id int primary key auto_increment,name varchar(20))";
            String sql4 = "insert into user values (null,'aaa')";
            String sql5 = "insert into user values (null,'bbb')";
            String sql6 = "insert into user values (null,'ccc')";
            String sql7 = "update user set name = 'mmm' where id = 2";
            String sql8 = "delete from user where id = 1";
            // 添加到批处理
            stmt.addBatch(sql1);
            stmt.addBatch(sql2);
            stmt.addBatch(sql3);
            stmt.addBatch(sql4);
            stmt.addBatch(sql5);
            stmt.addBatch(sql6);
            stmt.addBatch(sql7);
            stmt.addBatch(sql8);
            // 执行批处理:
            stmt.executeBatch();
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            JDBCUtils.release(stmt, conn);
        }
    }

3.批量插入(使用PreparedStatement)

@Test
    /**
     * 批量插入记录:
     * * 默认情况下MySQL批处理没有开启的,需要在url后面拼接一个参数即可。
     */
    public void demo2(){
        // 记录开始时间:
        long begin = System.currentTimeMillis();
        Connection conn = null;
        PreparedStatement pstmt = null;
        try{
            // 获得连接:
            conn = JDBCUtils.getConnection();
            // 编写SQL语句:
            String sql = "insert into user values (null,?)";
            // 预编译SQL:
            pstmt = conn.prepareStatement(sql);
            for(int i=1;i<=10000;i++){
                pstmt.setString(1, "name"+i);
                // 添加到批处理
                pstmt.addBatch();
                // 注意问题:
                // 执行批处理
                if(i % 1000 == 0){
                    // 执行批处理:
                    pstmt.executeBatch();
                    // 清空批处理:
                    pstmt.clearBatch();
                }
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            JDBCUtils.release(pstmt, conn);
        }
        long end = System.currentTimeMillis();
        System.out.println((end-begin));
    }

十一、连接池

  • 连接池是创建和管理一个连接的缓冲池的技术,这些连接准备被任何需要他们的线程使用。
  • 连接对象创建和销毁是需要耗费时间的,在服务器初始化的时候就初始化一些连接。把这些连接放入到内存中,使用的时候可以从内存中获取,使用完成之后将连接放入连接池中。从内存中获取和归还的效率要远远高于创建和销毁的效率。(提升性能)。

1.连接池原理

jdbcljc.png

2.自定义连接池

  1. 编写一个类实现DataSource接口
  2. 重写getConnection方法
  3. 初始化多个连接在内存中
  4. 编写归还连接的方法
  5. 自定义连接池的代码实现

代码实现

public class MyDataSource implements DataSource {
    //将一些连接存入到内存中,可以定义一个集合,用于存储连接对象
    private List<Connection> connList = new ArrayList<Connection>();
    
    //在初始化的时候提供一些连接
    public MyDataSource() {
        //初始化连接
        for(int i = 1; i < 4; i++) {
            //向集合中存入连接
            connList.add(JDBCUtils.getConnection());
        }
    }
    
    // 从连接池中获得连接的方法
    @Override
    public Connection getConnection() throws SQLException {
        Connection conn = connList.remove(0);
        return conn;
    }
    
    //编写一个归还连接的方法
    public void addBack(Connection conn){
        connList.add(conn);
    }
}

使用装饰者模式增强Connection中的close方法

为了简化编程,提供一个模板类(模板类原封不动的将接口中的所有方法都实现,但是都没有增强)。编写一个装饰类继承模板类。在装饰类中只需要增强某一个方法即可。

代码实现

/**
 * 使用装饰者增强Connection中的close方法
 */
public class MyConnectionWrapper extends ConnectionWrpper {
    private Connection conn;
    private List<Connection> connList;
    
    public MyConnectionWrapper(Connection conn,                  List<Connection> connList) {
        super(conn);
        this.conn = conn;
        this.connList = connList;
    }

// 增强某个方法:
    @Override
    public void close() throws SQLException {
//      super.close();
    //归还连接:
    connList.add(conn);
    }
}
//改写连接池
public class MyDataSource implements DataSource {
    // 将一些连接存入到内存中,可以定义一个集合,用于存储连接对象。
    private List<Connection> connList = new ArrayList<Connection>();
    
    // 在初始化的时候提供一些连接
    public MyDataSource() {
        // 初始化连接:
        for(int i = 1;i<=3;i++){
            // 向集合中存入连接:
            connList.add(JDBCUtils.getConnection());
        }
    }
    
    // 从连接池中获得连接的方法
    @Override
    public Connection getConnection() throws SQLException {
        Connection conn = connList.remove(0);
        // 增强连接:
        MyConnectionWrapper connWrapper = new MyConnectionWrapper(conn, connList);
        return connWrapper;
    }
    
    // 编写一个归还连接的方法:
    /*public void addBack(Connection conn){
        connList.add(conn);
    }*/
}

3.Druid开源连接池的使用

Druid的概述

Druid阿里旗下开源连接池产品,使用非常简单,可以与Spring框架进行快速整合。

Druid的使用

@Test
    /**
     * Druid的使用:
     * * 手动设置参数的方式
     */
    public void demo1(){
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try{
            // 使用连接池:
            DruidDataSource dataSource = new DruidDataSource();
            // 手动设置数据库连接的参数:
            dataSource.setDriverClassName("com.mysql.jdbc.Driver");
            dataSource.setUrl("jdbc:mysql:///web_test4");
            dataSource.setUsername("root");
            dataSource.setPassword("abc");
            // 获得连接:
//          conn = JDBCUtils.getConnection();
            conn = dataSource.getConnection();
            // 编写SQL:
            String sql = "select * from account";
            // 预编译SQL:
            pstmt = conn.prepareStatement(sql);
            // 设置参数:
            // 执行SQL:
            rs = pstmt.executeQuery();
            while(rs.next()){
                System.out.println(rs.getInt("id")+" "+rs.getString("name")+" "+rs.getDouble("money"));
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            JDBCUtils.release(rs, pstmt, conn);
        }
    }
@Test
    /**
     * Druid的使用:
     * * 配置方式设置参数
     * Druid配置方式可以使用属性文件配置的。
     * * 文件名称没有规定但是属性文件中的key要一定的。
     */
    public void demo2(){
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try{
            // 使用连接池:
            // 从属性文件中获取:
            Properties properties = new Properties();
            properties.load(new FileInputStream("src/druid.properties"));
            DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
            // 获得连接:
//          conn = JDBCUtils.getConnection();
            conn = dataSource.getConnection();
            // 编写SQL:
            String sql = "select * from account";
            // 预编译SQL:
            pstmt = conn.prepareStatement(sql);
            // 设置参数:
            // 执行SQL:
            rs = pstmt.executeQuery();
            while(rs.next()){
                System.out.println(rs.getInt("id")+" "+rs.getString("name")+" "+rs.getDouble("money"));
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            JDBCUtils.release(rs, pstmt, conn);
        }
    }

4.C3P0开源连接池的使用

C3P0的连接池的概述

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

C3P0的连接池的使用

@Test
    /**
     * 手动设置参数的方式:
     */
    public void demo1(){
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try{
            // 获得连接:从连接池中获取:
            // 创建连接池:
            ComboPooledDataSource dataSource = new ComboPooledDataSource();
            // 设置连接参数:
            dataSource.setDriverClass("com.mysql.jdbc.Driver");
            dataSource.setJdbcUrl("jdbc:mysql:///web_test4");
            dataSource.setUser("root");
            dataSource.setPassword("abc");
            // 从连接池中获得连接:
            conn = dataSource.getConnection();
            // 编写SQL:
            String sql = "select * from account";
            // 预编译SQL:
            pstmt = conn.prepareStatement(sql);
            // 执行SQL:
            rs = pstmt.executeQuery();
            while(rs.next()){
                System.out.println(rs.getInt("id")+" "+rs.getString("name")+" "+rs.getDouble("money"));
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            JDBCUtils.release(rs, pstmt, conn);
        }
    }

采用配置文件的方式:

  • 配置连接池
c3p0.png
  • 使用连接池
@Test
    /**
     * 采用配置文件的方式:
     */
    public void demo2(){
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try{
            // 获得连接:从连接池中获取:
            // 创建连接池://创建连接池默认去类路径下查找c3p0-config.xml
            ComboPooledDataSource dataSource = new ComboPooledDataSource();
            // 从连接池中获得连接:
            conn = dataSource.getConnection();
            // 编写SQL:
            String sql = "select * from account";
            // 预编译SQL:
            pstmt = conn.prepareStatement(sql);
            // 执行SQL:
            rs = pstmt.executeQuery();
            while(rs.next()){
                System.out.println(rs.getInt("id")+" "+rs.getString("name")+" "+rs.getDouble("money"));
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            JDBCUtils.release(rs, pstmt, conn);
        }
    }

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容

  • Mybatis-9.28 环境: JDK1.8 Mysql 5.7 maven 3.6.1 IDEA 回顾: JD...
    友人Ay阅读 339评论 0 1
  • Mysql sql分类: DDL: 对象:数据库和表 关键词:create 、alter 、drop 、trunc...
    ROC_XU的日记本阅读 289评论 0 0
  • MySql连接MySql驱动包加载数据库操作的一般过程连接MySql创建Statement对象执行SQL语句处理R...
    小石头呢阅读 1,130评论 0 8
  • JDBC基础知识 一、采用JDBC访问数据库的基本步骤: A.载入JDBC驱动程序 B.定义连接URL ...
    java日记阅读 3,832评论 0 20
  • JDBC概述 在Java中,数据库存取技术可分为如下几类:JDBC直接访问数据库、JDO技术、第三方O/R工具,如...
    usopp阅读 3,526评论 3 75