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和数据库来回切换了

感兴趣的自行去摸索一下

最新文章

  1. mvc4 分离Controller 出现 未找到路径“/”的控制器或该控制器未实现 IController
  2. NYOJ题目75日期计算
  3. C#操作Json(转)
  4. [D3] 14. Line and Area Charts with D3
  5. Linux Shell(初识)
  6. at java.util.concurrent.ConcurrentHashMap.hash(ConcurrentHashMap.java:333)
  7. C语言选择法排序
  8. Sql server2014 内存优化表 本地编译存储过程
  9. huffman编码【代码】
  10. 解决spring-boot启动中碰到的问题:Cannot determine embedded database driver class for database type NONE
  11. MATLAB cftool工具数据拟合结果好坏判断
  12. error $GOPATH: no library found in $GOPATH: rdkafka
  13. debug调试命令
  14. c——动态数组
  15. 20155330 2016-2017-2 《Java程序设计》第六周学习总结
  16. table 奇行偶行
  17. maven项目打包时生成dependency-reduced-pom.xml
  18. 找了一个api管理工具
  19. Java对象在虚拟机中的创建、内存分布、访问定位以及死亡判定
  20. 在进行vue的学习,项目中需要引入bootstrap、jquery的步骤。

热门文章

  1. Python大数据应用
  2. 算法:N-gram语法
  3. 使用spire.doc导出支持编辑Latex公式的标准格式word
  4. 斐波那契数列 牛客网 剑指Offer
  5. Ubuntu Python2 和 Python3 共存 切换
  6. 让Visual Studio x64 支持 __asm内联汇编
  7. Go语言核心36讲(Go语言进阶技术十三)--学习笔记
  8. gitbook热更新时报错operation not permitted
  9. 四种 AI 技术方案,教你拥有自己的 Avatar 形象
  10. Qt Creator 常用快捷键 详细总结