xiegongzi

1、简单认识一下JDBC

  • 1)、JDBC是什么?
    • java database connection       java数据库连接
    • 作用:就是为了java连接mysql数据库嘛
    • 要详细的,就面向百度编程吧

 

  • 2)、JDBC是一种驱动,那么它位于哪个地方?

 

  • 3)、JDBC的实现  ———— 五步骤
    • 加载驱动
    • 获取连接   driverManager
    • 获取执行sql的对象  statement / PreparedStatement
    • 获取结果集  resultSet
    • 释放资源

 

 

 

        • 再来数据库创建一个数据库 和 表
          • CREATE DATABASE IF NOT EXISTS jdbc;
            
            USE jdbc;
            
            CREATE TABLE IF NOT EXISTS person(
                id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
                `name` VARCHAR(20) NOT NULL,
                sex CHAR(2) NOT NULL,
                age INT NOT NULL
            )ENGINE = INNODB DEFAULT CHARSET = utf8;
            
            
            INSERT INTO person
            VALUES( NULL , \'紫邪情\' , \'\' , \'18\' ),
                  ( NULL , \'君莫邪\' , \'\' , \'19\' ),
                  ( NULL , \'张雪\' , \'\' , \'19\' ),
                  ( NULL , \'韩非\' , \'\' , \'19\' );

 

        • 然后把下载的JDBC弄到java项目中去 
          •  标记文件类型

            •  

               标记成功之后jar包前面有一个 > 符号

 

      • (2)、利用五步骤。开始测试
        • package cn.xieGongZi.test;
          
          import java.sql.*;
          
          public class PlayJDBC {
          
              public static void main(String[] args) throws ClassNotFoundException, SQLException {
          
                  // 1、加载驱动 利用了反射
                  Class.forName("com.mysql.jdbc.Driver");    // 这个是死的   这里为了看逻辑,所以把异常抛出
          
                  /*
                   * jdbc:mysql:   是指协议  这是固定写法
                   * localhost     是主机地址  这里使用127.0.0.1也可以,要是想连接别人电脑上的数据库,这里把ip地址换了就可以了
                   * 3306          指:sql的端口号
                   * jdbc          就是要链接的数据库
                   * ?            表示要跟参数  即:? 后面的就是参数
                   * characterEncoding     指:设置字符编码    其他的参数都可以少,这个最好别少
                   * useUnicode    使用Unicode编码格式
                   * useSSL        使用安全套接层协议  即:安全连接
                   *
                   * 因此:这个url的写法就出来了:
                   *       协议 : // 主机地址 : 端口号 / 数据库名 ? 参数
                   * */
                  String url = "jdbc:mysql://localhost:3306/jdbc? characterEncoding = utf-8 && useUnicode = true && useSSL = true";
                  String username = "root";    // 这是数据库的用户名
                  String password = "072413";     // 这是数据库的密码     要操作数据库肯定要登进去涩,所以:路径是什么?用户名和密码时什么肯定需要告知嘛
          
                  // 2、获取连接 使用DriverManager 这是java.sql包下的
                  Connection con = DriverManager.getConnection(url, username, password);
                  // 发现这个getConnection需要三个参数 url 、 username 、 password,所以建一下,需要处理异常,为了好看逻辑,照样跑出去
          
                  // 3、通过链接对象 去 获取执行sql的对象
                  Statement st = con.createStatement();
          
                  String sql = "select * from person";        // 在这个地方有些人可能会出现 表名 识别不了  那就用 库名.表名 如:jdbc.person
          // 这里进行查询操作     注:在java中, 增删改 是executeUpdate( String sql )方法   查询是executeQuery( String sql )方法
                  // 4、执行sql,获取结果集
                  ResultSet rs = st.executeQuery(sql);   // 发现这个方法需要一个sql , 那么编写一句
          
                  // sql语句弄好了,结果集resultSet也得到了,但是看名字就知道ResultSet肯定是一个容器嘛,所以得把结果拿出来涩
                  // 使用一个方法 next()  这是看下一行是否有数据    怎么理解呢?
                  // 就是去读写数据时,有一个指针,这个指针是指向数据库表的表头的,即:列字段哪一行 什么name、age、sex....这一行
                  // 所以:去一行一行读写时,是看下一行是否有数据
                  while ( rs.next() ){    // 当然:要是数据只有一行的话 用个if就可以了
                      System.out.print( rs.getInt("id") + " " );
                      System.out.print( rs.getString("name") + " " );
                      System.out.print( rs.getString("sex") + " " );
                      System.out.println( rs.getInt("age") + " " );
                  }
          
                  // 5、释放资源 ———— 倒着关闭
                  if ( rs != null ){      // 在这里这个if不要都行,为了后续代码的健壮性,严谨,所以这里加了一个判断罢了
                      rs.close();
                  }
          
                  if ( st != null ){
                      st.close();
                  }
          
                  if ( con != null ){
                      con.close();
                  }
          
          
              }
          }

           

 

效果如下( 成功从数据库中拿到数据了 ):

 

  • 对JDBC的总结和补充
    • JDBC的步骤
      • 加载驱动   Class.forName("com.mysql.jdbc.Driver");
      • 获取连接   Connection con = DriverManager.getConnection( String url , String username , String password );
      • 获取执行sql的对象   Statement st = con.CreateStatement();
      • 获取结果集 / 获取受影响的行数( 这个是增删改的时候的结果 )    ResultSet rs = st.executeQuery( String sql );    增删改就是executeUpdate( String sql )
      • 释放资源     close()

 

    • 对一些方法的补充:
      • Connection中常用的方法
        • 这就是一个连接对象嘛,它代表的就是数据库。所以它可以设置数据库中的任何东西
          • rollback   回滚
          • autocommit   自动提交
          • commit          提交事务
          • createStatement     创建执行sql的对象     —— 提前讲一下:这个对象不安全
          • preparedStatement    这个也是创建执行sql的对象           ———— 这个更安全,后续会说明
          • close                         关闭连接
          • 其他的方法      直接通过 Connection.  之后就可以看到它所有的方法了

 

      • Statement中常用方法
        • executeQuery          执行sql查询语句         返回的是一个结果集 ResultSet
        • executeUpdate        执行sql增 / 删 / 改 语句     返回的是受影响的行数
        • execute                    执行任何的sql语句
        • close                        关闭资源

 

      • ResultSet中常用方法
        • getObject                在不知道数据库中字段的类型时采用,获取任意类型嘛
        • 获取对应类型
          • getString
          • getInt
          • getDouble
          • ........
        • 移动指针
          • beforeFirst     移动到最前面   即:表头的位置
          • afterLast         移动到最后面   即:数据的最后一行
          • next                 移动到下一行数据
          • previous         移动到前一行数据
          • absolute( int row )      移动到指定行
        • 关闭资源
          • close

 

  • 4)、JDBC的封装
    • 为什么需要封装?
      • 前面那个JDBC五步骤是固定的,那么每有一个类需要进行操作数据库时不得都要写一次吗,那里面有很多共同的代码,只有个别不同而已,所以:不就可以提取成一个工具类吗

 

    • (1)、自己进行的封装
      • ①、简单封装
        • 加入实体类 —— 即:sql中的一张表对应java中的一个实体类    实体类的包名为 pojo / vo / entity 都可以

        • package cn.xieGongZi.pojo;
          
          // 加入对应数据库中的列字段 成为 属性
          // 加入get 和 set 方法
          // 加入toString方法
          
          public class Person {
          
              private int id;
              private String name;
              private String sex;
              private int age;
          
              @Override
              public String toString() {
                  return "Person{" +
                          "id=" + id +
                          ", name=\'" + name + \'\\'\' +
                          ", sex=\'" + sex + \'\\'\' +
                          ", age=" + age +
                          \'}\';
              }
          
              public Person() {
              }
          
              public Person(int id, String name, String sex, int age) {
                  this.id = id;
                  this.name = name;
                  this.sex = sex;
                  this.age = age;
              }
          
              public int getId() {
                  return id;
              }
          
              public void setId(int id) {
                  this.id = id;
              }
          
              public String getName() {
                  return name;
              }
          
              public void setName(String name) {
                  this.name = name;
              }
          
              public String getSex() {
                  return sex;
              }
          
              public void setSex(String sex) {
                  this.sex = sex;
              }
          
              public int getAge() {
                  return age;
              }
          
              public void setAge(int age) {
                  this.age = age;
              }
              
          }

           

          实体类完毕!

 

        • 封装JDBC
          • 建一个utils包

 

          • 开始封装JDBC
            • package cn.xieGongZi.utils;
              
              import java.sql.*;
              
              public class JDBCUtils {
              
                  private static String url;
                  private static String username;
                  private static String password;
              
                  static {
              
                      try {
                          // 加载驱动
                          Class.forName("com.mysql.jdbc.Driver");
              
                          // 编写url、username、password
                          url = "jdbc:mysql://localhost:3306/jdbc?characterEncoding = utf-8 && useUnicode = true && useSSL = true ";
                          username = "root";
                          password = "072413";
                      } catch (ClassNotFoundException e) {
                          e.printStackTrace();
                      }
              
                  }
              
                  // 1、设置获取链接方法
                  public static Connection getConnection() throws SQLException {
                      return DriverManager.getConnection( url , username , password );
                  }
              
                  // 2、封装释放资源方法
                  public static void release(Connection con , Statement st , ResultSet rs ){
                      if ( rs != null ){
                          try {
                              rs.close();
                          } catch (SQLException e) {
                              e.printStackTrace();
                          }
                      }
              
                      if ( st != null ){
                          try {
                              st.close();
                          } catch (SQLException e) {
                              e.printStackTrace();
                          }
                      }
              
                      if ( con != null ){
                          try {
                              con.close();
                          } catch (SQLException e) {
                              e.printStackTrace();
                          }
                      }
                  }
                  
                  // 3、在这里 再把增删改 和 查询方法封装起来也行  目前不演示了
              }

               

 

          • 通过加入实体类,测试封装的JDBC
            • 编写数据操作层

 

            • package cn.xieGongZi.dao;
              
              import cn.xieGongZi.pojo.Person;
              import cn.xieGongZi.utils.JDBCUtils;
              
              import java.sql.Connection;
              import java.sql.ResultSet;
              import java.sql.SQLException;
              import java.sql.Statement;
              import java.util.ArrayList;
              import java.util.List;
              
              public class PersonDao {
              
                  public List<Person> getAllPerson(){
              
                      // 创建一个集合 用来装查询的结果   从情况来看:ArrayList集合更适合  因为:有可能查出来的数据有重复的、而且最好有序
                      ArrayList<Person> list = new ArrayList<>();
              
              
                      // 1、加载驱动、获取链接已经在工具类中封装了  所以:直接拿来用
              Connection con = null; // 提示作用域 因为:放在try里面的话,在后面释放资源哪里拿不到这三个参数
              Statement st = null;
              ResultSet rs = null; try { con = JDBCUtils.getConnection(); // 2、获取操作执行sql的对象 st = con.createStatement(); // 编写sql语句 String sql = "select id , `name` , sex , age from person"; // 3、执行sql语句 , 获得结果集 rs = st.executeQuery(sql); // 加入了实体类 所以:需要把结果集中的数据 弄到 实体类中去 // 所以:还得有个实体类诶 Person people = new Person(); while ( rs.next() ){ // 遍历结果集 准备把数据 放到 实体类中 people.setId( rs.getInt("id") ); people.setName( rs.getString("name") ); people.setSex( rs.getString("sex") ); people.setAge( rs.getInt("age") ); // 最后:把people 装到 list集合中去 一开始玩这一步不要都行 // 只是:这里是为了给后面的三层架构打基础 list.add( people ); } } catch (SQLException e) { e.printStackTrace(); }finally{
              JDBCUtils.release( con , st , rs ); // 释放资源 有null的,在JDBCUtils中会自行判断
              }
              return list; // 这里返回,然后在其他地方也就可以拿到这个结果了 } }
              测试一下:

 

 

          • ②、上面的封装还是麻烦,不太满意,那就再来封装
            • 一样的,先建好对应的包 写好对应的东西:实体类  当然:不用我这么建也可以,根据自己想法来
              •  

                 

            • 在玩javaSE的集合时,不是弄过一个hashtable的儿子 —— Properties吗,来用一下它
              •  

                 

            • 继续封装JDBC
              • package cn.xieGongZi.utils;
                
                import java.io.IOException;
                import java.io.InputStream;
                import java.sql.*;
                import java.util.Properties;
                
                public class JDBCUtil {
                
                    // 把driver、url、username、password放到了properties中了,那么就加载出来
                    private static String driver;
                    private static String url;
                    private static String username;
                    private static String password;
                
                    static {
                        // 通过类加载器加载出db.properties  —— 输入流嘛
                        InputStream in = JDBCUtil.class.getClassLoader().getResourceAsStream("cn/xieGongZi/resources/db.properties");
                
                        // 创建一个properties对象
                        Properties ppt = new Properties();
                
                        // 把流管道中的东西加载到properties中来
                        try {
                            ppt.load(in);
                
                            // 把装到properties中的东西 获取出来
                            driver = ppt.getProperty("driver");
                            url = ppt.getProperty("url");
                            username = ppt.getProperty("username");
                            password = ppt.getProperty("password");
                
                            // 顺便做一件事情:加载驱动
                            Class.forName( driver );
                        } catch (IOException | ClassNotFoundException e) {
                            e.printStackTrace();
                        }
                    }
                
                
                    // 1、封装获取数据库链接对象的方法 这样别人只需要用我提供的其他方法即可
                    private static Connection getConnection() throws SQLException {
                        return DriverManager.getConnection( url , username , password );
                    }
                
                
                    // 2、提供释放资源的方法
                    public static void release(Connection con , Statement st , ResultSet rs ){
                        if ( rs != null ){
                            try {
                                rs.close();
                            } catch (SQLException e) {
                                e.printStackTrace();
                            }
                        }
                
                        if ( st != null ){
                            try {
                                st.close();
                            } catch (SQLException e) {
                                e.printStackTrace();
                            }
                        }
                
                        if ( con != null ){
                            try {
                                con.close();
                            } catch (SQLException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                
                
                
                    // 3、把增删改的方法也封装了
                    public static int update( String sql ) throws SQLException {
                
                        // 原生的JDBC在增删改语句执行之前做了什么?
                
                        // 1、加载驱动 —— 前面已经做了
                
                        // 2、获取数据库链接对象  —— 前面封装了 所以直接拿来用
                        Connection con = getConnection();// 异常抛出去
                
                        // 3、通过数据库链接对象 获取 执行sql的对象
                        Statement st = con.createStatement();
                
                        // 4、执行sql  得到受影响的行数
                        int rowCounts = st.executeUpdate(sql);
                
                        return rowCounts;       // 这里可以一步到位:return st.executeUpdate( sql ) ;
                    }
                
                
                    // 4、继续封装  把查询方法也封装了
                    public static ResultSet query( String sql ) throws SQLException {
                
                        // 前面都是一样的涩 复制过来
                        // 原生的JDBC在增删改语句执行之前做了什么?
                
                        // 1、加载驱动 —— 前面已经做了
                
                        // 2、获取数据库链接对象  —— 前面封装了 所以直接拿来用
                        Connection con = getConnection();// 异常抛出去
                
                        // 3、通过数据库链接对象 获取 执行sql的对象
                        Statement st = con.createStatement();
                
                        // 4、执行sql 返回结果集
                        return st.executeQuery(sql);
                
                    }
                
                }

 

            • 封装好了,那来测试一下
              • 编写数据操作层 即:dao层
                • package cn.xieGongZi.dao;
                  
                  import cn.xieGongZi.pojo.Person;
                  import cn.xieGongZi.utils.JDBCUtil;
                  
                  import java.sql.Connection;
                  import java.sql.ResultSet;
                  import java.sql.SQLException;
                  import java.sql.Statement;
                  import java.util.ArrayList;
                  import java.util.List;
                  
                  public class Persondao {
                  
                      public List<Person> getAllPerson() {
                  
                          ArrayList<Person> list = new ArrayList<>();
                  
                          // 原生JDBC前面做了什么?
                  
                          // 1、加载驱动 —— 在JDBC工具类中已经封装了
                  
                          // 2、获取数据库链接对象 ———— 还是在JDBC中封装了 这里可用可不用 —— 看封装增删查改方法的过程
                          // 我在增删查改中是直接调用了 getConnection() 不是当参数传进去了,所以:这里直接不用调,因为:增删改查中调用了
                  
                          // 编写sql语句
                          String sql = " select id , `name` , sex , age from person";
                          // 3、获取执行sql的对象 返回结果集 —— 封装了 直接调用
                          ResultSet rs = null;
                          Statement st = null;
                          Connection con = null;
                          try {
                              rs = JDBCUtil.query(sql);
                  
                              // 拿到结果集了 那么把结果集中的数据放到list集合中
                              // 还是需要一个Person实体类对象
                              Person person = new Person();
                              while ( rs.next() ){
                                  person.setId( rs.getInt("id") );
                                  person.setName( rs.getString("name") );
                                  person.setSex( rs.getString("sex") );
                                  person.setAge( rs.getInt("age") );
                  
                                  // 把person放到list中 这样就可以在其他地方也拿到了
                                  list.add( person );
                              }
                          } catch (SQLException e) {
                              e.printStackTrace();
                          }finally {
                              // 最后释放资源
                              JDBCUtil.release( con , st , rs );   // 发现这里拿不到ResultSet 那么提升作用域
                              // 发现需要Connection 、 Statement对象,那就创建一下,让它等于null 这样在JDBCUtil中会自行判断
                          }
                  
                          return list;
                      }
                  }
                  效果如下:

                • 最后:这你妹嘞个巴子滴,和前面的封装不是一样的吗?
                  • 不一样,这种是建议用的一种( 是抛开后面用的连接池啊 ),因为这种速度更快一点,以及分工更明确一点( 更像编程思维嘛 )

 

 

          • ③、前面都是用的Statement这个执行sql的对象,但是:一开始我便提过一点 这个对象不安全,因为:它不能防止SQL注入
            • SQL注入是什么意思?
              • 简单理解就是:这是SQL的一个漏洞,别人在攻击数据库时,可以通过逻辑正确,但非法的方式进入到数据库中,从而导致:数据泄露

 

 

            • 来体验一下
              • 一样的,把对应的包创建好

 

              • 简单模仿一下登录业务流程
                • 建一个用户表
                  • CREATE TABLE IF NOT EXISTS `user`(
                    
                        username VARCHAR(20) NOT NULL,
                        `password` VARCHAR(10) NOT NULL
                    )ENGINE = INNODB DEFAULT CHARSET = utf8;
                    
                    
                    INSERT INTO `user` VALUES( \'紫邪情\' , \'072413\' ),
                                             ( \'君莫邪\' , \'123456\' ),
                                             ( \'韩非\' , \'774931\' );

 

                • package cn.xieGongZi.test;
                  
                  import cn.xieGongZi.utils.JDBCUtil;
                  
                  import java.sql.Connection;
                  import java.sql.ResultSet;
                  import java.sql.SQLException;
                  import java.sql.Statement;
                  
                  public class Demo {
                  
                      public static void login( String username , String password ){
                  
                          // 编写sql
                          String sql = " select * from `user` where username = \' "+username+" \' and password = \' "+password+" \' ";
                          // 因为转义字符的关系 所以:这里的\' "+usernmae+" \' 在外面加了一个 `` 飘字符
                  
                          // 执行sql 获得结果集
                          Connection con = null;       // 提升作用域
                          Statement st = null;
                          ResultSet rs = null;
                          try {
                              rs = JDBCUtil.query(sql);
                  
                              while ( rs.next() ){
                  
                                  System.out.println( rs.getString("username") );
                                  System.out.println( rs.getString("password") );
                              }
                          } catch (SQLException e) {
                              e.printStackTrace();
                          }finally {
                              JDBCUtil.release( con , st , rs );
                          }
                      }
                  
                      // 测试一下
                      public static void main(String[] args) {
                  
                          // 模仿一下登录业务流程
                          // 前面第二种封装就是使用的Statement对象
                          login( " \'or\' 1=1 " , " \'or\' 1=1 ");     // 这里使用逻辑正确,但是:违法的技巧
                      }
                  }
                  效果如下:
                  • 成功达到目的,因此:Statement不建议使用,不安全,最好使用我接下来要说明的这个对象 PreparedStatement。
                  • 当然:要是有人整 —— 我前面用的db.properties中有数据库用户名 和 密码,所以可以做到,那就别扯了,这是两码事儿。
                  • 因此:要是有人说用statement这个执行sql语句的对象的话,那他就是个草包,听都别听他鬼扯。

 

 

            • PreparedStatement对象  —— 预编译对象
              • 前面的流程都一样 使用 添加实体类 、 db.properties  所以不演示了,主要从封装JDBC开始,把Statement对象换了

 

              • JDBC的封装
              • package cn.xieGongZi.utils;
                
                import java.io.IOException;
                import java.io.InputStream;
                import java.sql.*;
                import java.util.Properties;
                
                public class JDBCUtil {
                
                    private static String driver;
                    private static String url;
                    private static String username;
                    private static String password;
                
                    static {
                
                        InputStream ins = JDBCUtil.class.getClassLoader().getResourceAsStream("cn/xieGongZi/resources/db.properties");
                
                        Properties ppt = new Properties();
                        try {
                            ppt.load( ins );
                
                            driver = ppt.getProperty("driver");
                            url = ppt.getProperty("url");
                            username = ppt.getProperty("username");
                            password = ppt.getProperty("password");
                
                            Class.forName(driver);
                        } catch (IOException | ClassNotFoundException e) {
                            e.printStackTrace();
                        }
                    }
                
                
                    // 封装获取数据库链接对象
                    public static Connection getConnection() throws SQLException {
                        return DriverManager.getConnection(url, username, password);
                    }
                
                
                    // 提供释放资源的方法
                    public static void release(ResultSet rs , PreparedStatement ps , Connection con ) { // 注意:这里是用的PreparedStatement对象
                
                        if ( rs != null ){
                            try {
                                rs.close();
                            } catch (SQLException e) {
                                e.printStackTrace();
                            }
                        }
                
                        if ( ps != null ){
                            try {
                                ps.close();
                            } catch (SQLException e) {
                                e.printStackTrace();
                            }
                        }
                
                        if ( con != null ){
                            try {
                                con.close();
                            } catch (SQLException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                
                }

                 

            • 数据操作层
              • package cn.xieGongZi.dao;
                
                import cn.xieGongZi.pojo.Person;
                import cn.xieGongZi.utils.JDBCUtil;
                
                import java.sql.Connection;
                import java.sql.PreparedStatement;
                import java.sql.ResultSet;
                import java.sql.SQLException;
                import java.util.ArrayList;
                import java.util.List;
                
                public class PersonDao {
                
                    public List<Person> getAllPerson() {
                
                        ArrayList<Person> list = new ArrayList<>();
                
                        // 提升作用域
                        Connection con = null;
                        PreparedStatement ps = null;        // 使用preparedStatement对象
                        ResultSet rs = null;
                
                        // 还是一样 获取链接
                        try {
                            con = JDBCUtil.getConnection();
                
                            // 编写sql语句
                            // 因为:使用的是preparedStatement对象,所以这里有点区别
                            String sql = " select * from person where `name` = ? ";    // 使用占位符 ? 来代替要赋的值   在后面再给它赋值
                
                            // 执行sql
                            ps = con.prepareStatement(sql);
                            // 对占位符进行赋值
                            ps.setString(1,"紫邪情");     // 这表示给第一个参数( 即:? ),有多个的话,数值依次往后,跟着赋值即可
                
                            // 现在再开始执行sql  得到结果集
                            rs = ps.executeQuery();
                
                            Person people = new Person();
                
                            while ( rs.next() ){
                                people.setId( rs.getInt("id"));
                                people.setName( rs.getString("name"));
                                people.setSex( rs.getString("sex"));
                                people.setAge( rs.getInt("age"));
                
                                list.add( people );
                            }
                
                        } catch (SQLException e) {
                            e.printStackTrace();
                        }finally{
                JDBCUtil.release( rs , ps , con );
                }
                return list; } }
                效果如下:

 

 

    • (2)、使用别人封装好的  ———— 连接池
      • ①、什么是连接池?
        • 在javaSE的多线程中说过一个线程池,对照起来看
          • 池,就是池化技术嘛,一个容器咯,而这个容器的作用就是:控制连接数据库的个数、设置url、username、password、连接数量不够进行扩容之类的容器嘛
          • 数据库连接 -------> 执行完毕 ---------> 释放资源       整个过程是很消耗资源的。因此:连接池的真正作用就是  预先准备一些资源,这样一过来就可以进行连接操作了

 

        • 怎么编写连接池?
          • 很简单,只需要实现一个类就可以了  DataSource  去看一下这个类的源码( 是java.sql包下的 )
            •  

               但是啊:有别人写好的东西,我们不用手写,因此:拿别人写好的东西来用一下咯

 

      • ②、别人写好的连接池有哪些?
        • 最流行的就是:c3p0 、 dbcp 、 阿里巴巴的druid

 

        • 简单聊一下这三个的理论知识
          • druid 是淘宝 和 支付宝的必用数据库连接池  这玩意儿主要就是可以做到监控的功能,详细点就是如下:
            • 对Oracle 和 MySQL做了特别的优化 如:Oracle 的 PS Cache 内存占用优化,MySql 的 ping 检测优化
            • 使得分析 SQL 的抽象语法树很方便
            • 简单 SQL 语句用时 10 微秒以内,复杂 SQL 用时 30 微秒
            • 通过 Druid 提供的 Parser 可以在 JDBC 层拦截 SQL 做相应处理 ( 比如:分库分表,审计等 )
            • 上面这些更细的知识点不懂没关系,只需要知道主要是搞监控机制的就行

 

          • DBCP
            • 是一个依赖 jakarta commons-pool 对象池机制的数据库连接池,DBCP,也是 Tomcat 使用的连接池组件

 

          • c3p0
            • 是一个开放源代码的 JDBC 连接池,它在 lib 目录中与 Hibernate 一起发布,,包括了实现 jdbc3 和 jdbc2 扩展规范说明的 Connection 和 Statement 池的 DataSources 对象

 

            • 多说一嘴:DBCP和c3p0的区别
              • ①、dbcp 没有自动回收空闲连接功能,c3p0 有自动回收空闲连接功能
                ②、两者对数据连接处理方式不同:c3p0 提供最大空闲时间,dbcp 提供最大连接数
                ③、c3p0 连接超过最大连接时间时,当前连接会断掉。dbcp 当连接数数超过最大连接数时,所有连接都会被断开
                ④、dbcp 它的原理是维护多个连接对象 Connection。在 web 项目要连接数据库时直接使用它维护对象进行连接,省去每次都要创建对象的麻烦,提高平效率和减少内存使用
                ⑤、c3p0 可以自动回收连接,dbcp 需要自己手动释放资源返回,不过 dbcp 效率比较高

 

          • 壹、一法通、万法通,先来玩一下DBCP
            • ①、需要两个jar包
              • 一个commons-dbcp  一个 commons-pool    想要什么版本自己去找,我的版本如下:
                • commons-dbcp-1.4
                • commons-pool-1.6
              • 老规矩:把对应的jar包放到项目中去

 

            • ②、需要设置配置文件
              • 玩儿DBCP需要使用Properties进行编写配置
                • # 连接设置
                  # 注意:这个driverClassName必须用这个名字,别用什么driver就完了 因为:底层中找的就是这个名字 driverClassName = com.mysql.jdbc.Driver url = jdbc:mysql://localhost:3306/jdbc?characterEncoding = utf-8 & userUnicode = true & useSSL = true username = root password = 072413 # 初始化连接数量 initialSize = 10 # 最大连接数量 maxActive = 50 # 最大空闲连接数 maxIdle = 20 # 最小空闲连接数 minIdle = 5 # 超时等待时间 , 以毫秒为单位 maxWait = 60000 # 下面的设置要不要都无所谓 ## JDBC驱动建立连接时附带的连接属性的格式必须为这样 ———— 属性名 = property ## 另外:user 和 password两个属性会被明确地传递,因此:这里不需要包含他们 #connectionProperties = useUnicode = true ; characterEncoding = utf-8 # ## 指定有连接池所创建的连接的自动提交 auto-commit状态 #defaultAutoCommit = true # ## driver default 指定由连接池所创建的连接的只读 read-only状态 ## 但是:如果没有设置该值,则:setReadOnly方法不被调用 ## 另外:某些驱动并不支持只读模式 如:informix ## 因此:这个不设置也行 ## defaultReadOnly = ...... # ## driver default 指定有连接池所创建的连接的事务级别 transactionIsolation ## 可用值为下列之一: ## NONE , READ_UNCOMMITTED , READ_COMMITTED , REPEATABLE_READ #defalutTransactionIsolation = READ_UNCOMMITTED # # ## 有需要的配置,没需要的就不配置这中间的东西,我嫌麻烦,不配置了,直接注释掉

                   

                  配置好了,那得用一下咯

 

              • 实体类还是用的person、util 和 dao需要做一下调整
                • 封装DBCP工具类
                  • package cn.xieGongZi.utils;
                    
                    import org.apache.commons.dbcp.BasicDataSourceFactory;
                    
                    import javax.sql.DataSource;
                    import java.io.InputStream;
                    import java.sql.*;
                    import java.util.Properties;
                    
                    public class JDBCUtil {
                    
                    //    private static String driver;   // 相应的这些也不要了
                    //    private static String url;
                    //    private static String username;
                    //    private static String password;
                    
                        private static DataSource dataSource = null;        // 提升作用域  为了获取链接嘛
                    
                        static {
                    
                            // 这里就是去加载 DBCP_pool.properties 了
                            InputStream ins = JDBCUtil.class.getClassLoader().getResourceAsStream("cn/xieGongZi/resources/DBCP_pool.properties");
                    
                            Properties ppt = new Properties();
                            try {
                                ppt.load( ins );
                    
                    //            driver = ppt.getProperty("driver");    // 这一部分就不需要了,因为:在配置文件中配置了
                    //            url = ppt.getProperty("url");
                    //            username = ppt.getProperty("username");
                    //            password = ppt.getProperty("password");
                    
                    //            Class.forName(driver);
                    
                                // 这里需要借助一个类来获取数据源   这是一个工厂模式  这个是用来创建对象的 它需要一个Properties对象,所以直接扔给它
                                dataSource = BasicDataSourceFactory.createDataSource(ppt);// 处理异常   这个东西获取的是一个Datasource数据源
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    
                    
                        // 封装获取数据库链接对象
                        public static Connection getConnection() throws SQLException {
                    //        return DriverManager.getConnection(url, username, password);
                    
                            // 前面看源码不是看过datasource中自带获取连接吗,所以:这里直接通过DataSource获取连接
                            return dataSource.getConnection();      // 这样就把DBCP的工具类封装好了
                        }
                    
                    
                        // 释放资源方法还是一样需要
                        // 提供释放资源的方法
                        public static void release(ResultSet rs , PreparedStatement ps , Connection con ) { // 注意:这里是用的PreparedStatement对象
                    
                            if ( rs != null ){
                                try {
                                    rs.close();
                                } catch (SQLException e) {
                                    e.printStackTrace();
                                }
                            }
                    
                            if ( ps != null ){
                                try {
                                    ps.close();
                                } catch (SQLException e) {
                                    e.printStackTrace();
                                }
                            }
                    
                            if ( con != null ){
                                try {
                                    con.close();
                                } catch (SQLException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    
                    }
                    延伸一下:不是有一个BasicDataSourceFactory吗,看一下它的源码:

 

                • 修改dao层  其实就改两个地方 使用工具类调用那里
                  •  

 

                • 测试:

 

 

          • 贰、再来玩一下C3P0  其实玩法都一样,就是jar包不一样,然后获取数据源哪里不一样而已
            • ①、需要的两个jar包
              • c3p0         我的是:c3p0-0.9.5.2
              • mchange-commons-java        我的是:mchange-commons-java-0.2.15

 

            • 老规矩  —— 编写实体类、放jar包

 

            • ②、编写配置文件   C3P0使用的是xml配置
              • <?xml version="1.0" encoding="UTF-8"?>
                <c3p0-config>
                <!-- 数据库连接池 --> <named-config name="mysql"> <!-- 这个named-config名字很重要,后面获取数据源需要它 -->
                <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/blog</property> <property name="user">root</property> <property name="password">072413</property> <!--当数据连接池不够的时候,每次增长的个数--> <property name="acquireIncrement">5</property> <!--初始的连接池个数--> <property name="initialPoolSize">10</property> <property name="minPoolSize">5</property> <property name="maxPoolSize">15</property> <!--后面这两个可要可不要--> <!--jdbc的标准参数 用于控制数据源里面的preparedStatement的数量--> <property name="maxStatements">0</property> <!--连接池内单个链接所拥有的最大的缓存statement数--> <property name="maxStatementsPerConnoection">5</property>
                </named-config>
                </c3p0-config>

 

            • ③、编写工具类、获取数据源
              • package cn.xieGongZi.utils;
                
                import com.mchange.v2.c3p0.ComboPooledDataSource;
                
                import java.sql.Connection;
                import java.sql.PreparedStatement;
                import java.sql.ResultSet;
                import java.sql.SQLException;
                
                public class JDBCUtil {
                
                    // 这里需要一个东西 ComboPooledDataSource   后面要通过这个去获取数据源
                    private static ComboPooledDataSource dataSource = null;
                
                
                    static {
                
                        // 获取数据源
                        dataSource = new ComboPooledDataSource("mysql");   // 这里的参数名字就是前面配置文件中提到的named-config名字
                    }
                
                    // 只需要改以上部分就完了
                
                
                    // 这里和DBCP一样的
                    // 封装获取数据库链接对象
                    public static Connection getConnection() throws SQLException {
                        return dataSource.getConnection();
                    }
                
                
                    // 释放资源方法还也是一样
                    // 提供释放资源的方法
                    public static void release(ResultSet rs , PreparedStatement ps , Connection con ) { // 注意:这里是用的PreparedStatement对象
                
                        if ( rs != null ){
                            try {
                                rs.close();
                            } catch (SQLException e) {
                                e.printStackTrace();
                            }
                        }
                
                        if ( ps != null ){
                            try {
                                ps.close();
                            } catch (SQLException e) {
                                e.printStackTrace();
                            }
                        }
                
                        if ( con != null ){
                            try {
                                con.close();
                            } catch (SQLException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                
                }

                结果就不展示了

 

 

至此:JDBC的相关知识完毕,还有深层次的封装,就是使用preparedStatement对象时

将 增删改 和 释放资源 及 查 都进行封装了( 注:完美的查可以使用两种方法:一是接口回调、二是反射 )

 

另外一个就是ThreadLocal这个小东西,这个没什么好说的,就是一个看源码就懂的东西

附:ThreadLocal就是为了处理事务的( ThreadLocal支持泛型 ),所以就是为了保证Connection对象是同一个

这个ThreadLocal的核心方法就三个:get()、set()、remove()

 

另外:

IDEA连接数据库( 即:集成过去 )在右上角Database中
这样集成过去之后,就不用把IDEA和数据库来回切换了

感兴趣的自行去摸索一下

 

 

 

 

 

 

 

 

 

分类:

技术点:

相关文章: