jdbc的成长过程

JDBC的成长过程


概要
  • 1,原生JDBC的6个过程

  • 2,自定义的JDBCUtils工具类(初级形态)

    1)解决原生JDBC存在的重复操作--封装数据库连接对象  
    2)存在的缺点:
    
    3)进行改进: 读取配置文件方式
    
  • 3,Dbutils工具类—封装了常用的crud操作

    常用3个类:

       1)QueryRunner,实现增删改查操作
       2)ResultHandler,专门用于处理结果集的
             主要分8个类:
       3)DbUtils,封装了各种关流的方法
    
  • 4,连接池技术: DBCP, c3p0

    两者比较
    
  • 5,Dbutils结合连接池技术
  • 6,JDBC在以上存在的5个问题–引入Mybatis框架
  • 7,Mybatis的简单实现步骤,优势

正文

1,原生JDBC的6个过程

    1)注册驱动
      因为sun公司定义了具体连接数据库的接口(即规范),各大数据库厂商具体根据自己的数据库特性编写实现类,来实现该接口,因为程序开发者无需关注具体的实现,只需要了解sun公司定义的这些的接口以及这些接口中的方法的作用,在进行数据库连接操作时,通过接口调用的这些方法就可以执行数据库的操作(多态原理,父类调用方法,实现动态绑定),因而在连接时,需要指明是要连接到哪个数据库,就需要注册驱动(需要导入数据库的驱动包)
      在这里以mysql为例
            mysql-connector-java-5.1.39-bin.jar
      * 注册驱动用2种方式:
          1)DriverManager.registerDriver(new Driver());
         //查看源代码,Driver类中默认有一个静态代码块,会调用相同方法注册驱动一次,则注册2次驱动程序, 浪费资源 ,不推荐使用
          2)Class.forName("com.mysql.jdbc.Driver");
         //既然静态代码中会注册,于是直接利用反射技术,加载驱动类字节码文件到内存,静态代码块自动实现注册驱动


    2)获取连接对象
       Connection con= DriverManager.getConnection(url, user, password);
        这里 url:以mysql为例,连接本地主机localhost或127.0.0.1, 
           规则 url: jdbc:mysql://主机IP:端口号/数据库名
        user,password分别为要连接的数据库账号和密码

    3)获取SQL语句的执行者对象
       这里也称SQl的容器对象,主要有3种(都是接口):
         a,Statement
         b,PreparedStatement
         c,CallableStatement
      其中Statement有Sql注入危险,而且执行效率较低, PreparedStatement因为有预编译的功能,可以防止sql注入,且因有缓存,执行效率较高,
         CallableStatement主要是对存储过程和函数的操作
   Statement,PreparedStatement,CallableStatement    三者是爷,子,孙关系
    4)执行者对象调用方法发送SQL语句到数据库
        主要是两类方法 
        executeUpdate:执行增删改操作,返回int,指数据库中受影响的行数
        executeQuery: 执行查询操作,返回结果集
    5)处理结果集(针对查操作,增删改不用)
       ResultSet:处理结果集接口 
    6)关流操作
       一般是后开先关原则,节约资源.

1,代码部分 –以查询示例
      import java.sql.Connection;
      import java.sql.DriverManager;
      import java.sql.ResultSet;
      import java.sql.SQLException;
      import java.sql.Statement;

 public class Demo_Select {

public static void main(String[] args) throws ClassNotFoundException, SQLException {
    //1注册驱动
     Class.forName("com.mysql.jdbc.Driver"); //驱动类
     //2 连接准备
     String url="jdbc:mysql://localhost:3306/mybase";
      String user="root"; //我的数据库账号
      String password="root"; //我的数据库密码
           //获取连接对象
      Connection con= DriverManager.getConnection(url, user, password);
      //3 获取sql执行者对象
       Statement  state=con.createStatement();
       //拼写SQL语句
       String sql="select * from sort";
       //4  ResultSet executeQuery(String sql) 执行SQl语句中的select 
       // 返回ResultSet 接口的实现类对象,也在mysql程序里
          ResultSet rs= state.executeQuery(sql); 
         //5处理结果集
          //ResultSet接口方法  boolean next() 返回true,有结果,返回false,无结果 
          //该光标位于第一行(数据行) 之前, 调用一次向下移动一行
         while(rs.next()) {
             //获取每列数据 ,使用的是ResultSet接口中的方法  getXx 该方法也有两个参数,一个是写int coumIndex,(获取的是数据库表中的第几列) 一个是String 类名 (推荐使用)
             //通用方法是  getString 或者getObject 都可以接收
            System.out.println(rs.getInt("sid")+"  "
             + rs.getString("sname")+ "  "
             +rs.getDouble("sprice")+"  "
             +rs.getString("sdesc"));
         }
         //6,标准关流方式,放在finally中,确保一定能关流
        try {
            if (rs != null) rs.close();
            if (stat != null) stat.close();
            if (con != null) con.close();
        } catch (SQLException e) {
        }

  }
}

2,自定义的JDBCUtils工具类(初级形态)

 1) 解决原生JDBC存在的重复操作--封装数据库连接对象
    在原生JDBC存在每个需要连接的数据库的操作,都需要重复执行获取连接对象的操作,且关闭资源流的操作也重复
    这时就需要把重复操作部分封装起来,每次调用方法,直接就能获取连接对象和关流,所有就定义了一个工具类
 2)存在缺点
    在每个类中定义url,和user,password,写入具体的值,这样在开发中,如果需要换数据库,或者连接其他主机ip,代码固化,一旦修改就会大动干戈,修改很多,没有实现修改一处实现多处修改,实际开发中,则采用读取配置文件的方式进行改进.
     步骤:a,首先在src下创建一个db.properties (数据库的配置文件) 
            //在src下的配置文件会在创建的时候,自动拷贝到bin目录下 ,在src下对配置文件的修改,会重新拷贝到bin下,覆盖原来的文件,
         b,获得类的字节码对象,调用方法获得类加载器, 获得指定资源输入流(读取配置文件中的键值对信息)

2.1,代码部分 –封装JDBCUtils工具类
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;

    public class JdbcUtils {

//定义静态方法,返回数据库的连接对象,要把构造私有,不让别人创建对象
 private static final String URL="jdbc:mysql://localhost:3306/mybase";
 private static final String USER="root";
 private static final String PASSWORD="root";
 //将这些全部定义为静态的,私有常量,最好的方式是通过配置文件来读取这几个参数,在需要修改时,不用修改源代码
 private JdbcUtils() {}; //将构造私有,不让其他类创建对象,对外只提供静态的方法,调用即可
 private static Connection con=null;

static {
    try {
         Class.forName("com.mysql.jdbc.Driver"); //驱动类
         con= DriverManager.getConnection(URL, USER, PASSWORD);
    } catch (Exception e) {
        throw new RuntimeException("数据库连接失败!");
    }
}
//获取连接对象的方法
public static Connection getConnetion() {
    return con;
}
//关闭流方法,释放资源
//在这里因为Statement接口 是PreparedStatement的父接口, 父类可传参
public static void close(Connection con,Statement stat,ResultSet rs) {
    if (rs != null) {
        try {
            rs.close();
        } catch (SQLException e) {
        }
    }
    if (stat != null) {
        try {
            stat.close();
        } catch (SQLException e) {
        }
    }
    if (con != null) {
        try {
            con.close();
        } catch (SQLException e) {
        }
    }
 }
}
2.2,代码部分 – 读取配置文件的方式
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;

public class TestProperties {

public static void main(String[] args) throws IOException, ClassNotFoundException, SQLException {

    //1首先获得类的字节码对象,调用方法获得类加载器(作用:加载字节码对象进内存)
    ClassLoader classLoader = TestProperties.class.getClassLoader();
    //2 获得指定资源输入流,资源路径相对于classPath路径,因在src下,会被自动加载到bin目录下
InputStream in=classLoader.getResourceAsStream("db.properties");

    Properties pro=new Properties();
//获得集合对象,Hashtable双列集合下的子类,主要用于读取配置文件,这也是Hashtable早已过时还存在的原因,有个有用的儿子
  pro.load(in);  //加载输入流

  String driverClass=pro.getProperty("driverClass"); //根据键获取对应值
  String url=pro.getProperty("url");
  String username=pro.getProperty("username");
  String password=pro.getProperty("password");
 //连接数据操作
  Class.forName(driverClass); 
  Connection con=DriverManager.getConnection(url,username,password);
}
 }  

配置文件 db.properties

(以键值对方式储存,一行一对键值对,后面不要加符号),在应用需求改变,只需修改该配置文件

driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybase
username=root
password=root

3,Dbutils工具类—封装了常用的crud操作

  Dbutils是JDBC的简化开发工具包,里面封装了对数据库的常用操作,使得对数据库的操作更加简单
 所需jar包 commons-dbutils-1.6.jar,当然也需数据库驱动包

 3大核心类:

       1)QueryRunner类,提供了实现增删改查操作的API
              主要方法有2个: 
                   a,query(1,2,3,4) 
        用于实现查询操作,其中第1个参数,是连接对象(在与连接池结合使用时,不需要传入此参数)
                           第2个参数,是sql语句
                           第3个参数,是处理结果集的实现类对象
                           第4个参数,是一个可变参数 Object...objs(即对sql语句的占位符位置赋值,传入具体的参数,可变参数可以有0-n个,底层是一个数组) 
                   b,update(1,2,3)
         用于增删改操作,返回int, 第1个参数,是连接对象(在与连接池结合使用时,不需要传入此参数)
                               第2个参数,是sql语句
                               第3个参数,可变参数,也是对sql占位符的赋值
       2)ResultSetHandler接口,专门用于处理结果集的
             主要分8个类(其实可归纳为6种): 常用前4个
                     1,BeanHandler
   针对查询结果只有一个时,将结果集中的第一行数据封装成一个JavaBean对象,需要传入接收的实体类字节码对象,该javaBean对象必须空参构造,因为其通过反射方式是创建空参对象
        如:new BeanHandler(类.class)
                     2,BeanListHandler
   有多个结果时,将结果集中每一行数据,封装成JavaBean对象,再放到List集合中
                     3,MapHandler
   针对查询结果只有一个,将结果集中的第一行数据封装到Map集合中,Map<键,值> 键为表的字段名,值为对应数据
         即: Map<String, Object> ,通过对Map集合中的键获取值 
                     4,MapListHandler
     针对查询结果有多个,先将每一行数据封装到Map结合中,再将Map集合存储到List集合中
          即: List<Map<String,Object>>                
                     5,ArrayHandler
       针对结果一个的情况,将结果集第一行存储到Object[] 数组中
                     6,ArrayListHandler
         同理可推 针对多个集合  List<Object[]>          
                     7,ColumnListHandler
           获取指定列的所有数据,存储到List集合中 
        List<Object> ColumnListHandler(列名)
                     8,ScalarHandler
           对应查询结果只有1个结果 如  count(*) 查询个数等
       3)DbUtils类,封装了各种关流和事务处理的方法
          如: close(), closeQuietly()--内部已经处理过异常

* 4,连接池技术: DBCP, c3p0

     1,为什么要引入连接池技术
       为了避免频繁地 获取连接 和 释放资源, 会消耗系统的资源,为了节约资源,提高性能,引入了连接池的技术实现
     2,DBCP连接池
       1)特点:开源,tomcat内置的连接池
       2)jar包:commons-dbcp.jar, commons-pool(依赖包) 
       3)获取步骤:dbcp.jar包中定义了一个BasicDataSource实现类去实现javax.sql.DataSource接口
             a,DataSource  dataSource=new  BasicDataSource()//获取连接池对象
             b,配置信息,连接池对象的几个方法

                 dataSource.setDriverClassName("com.mysql.jdbc.Driver");
                 dataSource.setUrl("jdbc:mysql://localhost:3306/mybase");
                 dataSource.setUsername("root"); //数据库账号
                 dataSource.setPassword("root"); //数据库密码
             c,获取一个连接对象
                Connection con=dataSource.getConnection();
   注:连接池中关流操作,只是把连接对象返还给连接池,不是真正的关闭
       4)其他方法:如配置连接池的初始信息
         setInitialSize(10);//连接池初始化时,创建多少个连接对象
         setMaxActive(8);   //设置最多可以有几个程序来获取连接对象
         setMaxIdle(5);     //设置最大可有几个空闲连接对象
         setMinIdle(2);     // 设置池中剩余最小空闲连接对象
     3,c3p0连接池,
       1)特点:开源,目前使用他的开源项目有hibernate,spring等
       2)配置: 2个jar包1个配置文件
          如: c3p0-0.9-1.2-jdk1.3.jar
              c3p0-0.9-1.2.jar  (请忽略版本)
          配置文件: c3p0-config.xml(引入相应的约束,里面配置数据库连接的基本信息,也可以定义连接池的配置)
       3)获取步骤:
                  1,获取连接池对象
                  2,通过连接池对象调用方法获取一个连接连接对象
     4,两个连接池的比较: 
         c3p0的连接数据库配置以及连接池的初始化配置全在c3p0-config.xml中配置,通过读取配置文件的方式避免把代码写死到Java程序中,比DBCP连接池更加灵活一些,DBCP的配置都是通过连接池对象的调用方法进行配置的,所以相对要局限一些(虽然一个项目中配置一个连接池的地方不多,有需求变化,需要改动代码的地方很少,所以也可忽略)

4.1代码部分 – 通过c3p0连接池对象获取连接对象
    import java.sql.Connection;
    import java.sql.SQLException;

    import com.mchange.v2.c3p0.ComboPooledDataSource;

    public class C3p0Utils {
           private static ComboPooledDataSource comboPooledDataSource;
           static {
               //创建一个连接池对象,指明要连接的数据库类型
               comboPooledDataSource=new ComboPooledDataSource("mysql");
           }
            //对外只提供一个静态方法,获取连接对象 
           public static Connection getConneciton() {
                  Connection conn=null;
                  try {
                    conn=comboPooledDataSource.getConnection();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                  return conn;
           }

    }
4.2 c3p0-config.xml基本配置
 <?xml version="1.0" encoding="UTF-8"?>
 <c3p0-config>
<!-- This is default config! -->
<default-config>
    <property name="initialPoolSize">10</property>
    <property name="maxIdleTime">30</property>
    <property name="maxPoolSize">100</property>
    <property name="minPoolSize">10</property>
    <property name="maxStatements">200</property>
</default-config>

<!-- This is my config for mysql,这是针对mysql的配置,也可配置Oracle-->

<named-config name="mysql">
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/mybase?characterEncoding=utf-8</property>
    <property name="user">root</property>
    <property name="password">root</property>
    <property name="initialPoolSize">20</property>
    <property name="maxIdleTime">30</property>
    <property name="maxPoolSize">100</property>
    <property name="minPoolSize">10</property>
    <property name="maxStatements">200</property>
</named-config> 
</c3p0-config>

5,Dbutils结合连接池技术

  注:在Dbutils工具类结合连接池后(以DBCP连接池为例),封装一个获取连接池对象的类,对于需要连接对象的类,在QueryRunner对象中传入连接池对象即可,即可获的一个连接对象,
  在后续代码中执行query(),或者update()时无需传入Connction连接对象了

   //QueryRunner类构造方法,接收DataSource接口的实现类
  private static QueryRunner qr=
     new QueryRunner(new org.apache.commons.dbcp.BasicDataSource());

 //这里直接传入了DBCP的连接池对象,最好封装一个类,在类中获取连接池对象,当然要进行连接池对象数据库配置以及连接池的初始配置,如初始化连接对象(即一开始连接池对象创建多少个连接对象),最大空闲连接对象个数等等.
5.1代码部分 – 封装获取连接池对象
    import java.sql.Connection;
    import java.sql.SQLException;
    import java.util.List;

    import javax.sql.DataSource;

    import org.apache.commons.dbcp.BasicDataSource;
    import org.apache.commons.dbutils.QueryRunner;
    //连接池工具类
    public class JDBCUtils {
//1获取连接池对象
private static BasicDataSource dataSource=new BasicDataSource();

 static {
    //2 设置数据库连接必须的4个信息 ,放在静态代码块中
     dataSource.setDriverClassName("com.mysql.jdbc.Driver");
     dataSource.setUrl("jdbc:mysql://localhost:3306/mybase");
     dataSource.setUsername("root");
     dataSource.setPassword("root");
    //3 连接池的配置信息, 可选项
     dataSource.setInitialSize(10); //连接池初始化时,创建多少个连接对象
     dataSource.setMaxActive(8);     //设置最多可以有几个程序来获取连接对象
     dataSource.setMaxIdle(5);    //设置最大可有几个空闲连接对象
     dataSource.setMinIdle(2); // 设置池中剩余最小空闲连接对象
 }
//3对外提供公共方法连接接口实现类, 多态,返回连接池对象
 public static DataSource getDataSource() {
     return dataSource;
 }
    }

6,JDBC以上存在的5个问题–引入Mybatis框架

1、  数据库连接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库连接池可解决此问题。
解决:在SqlMapConfig.xml中配置数据连接池,使用连接池管理数据库链接。
2、  Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。
解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。
3、  向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。
解决:Mybatis自动将java对象映射至sql语句,通过statement中的parameterType定义输入参数的类型。
4、  对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。
解决:Mybatis自动将sql执行结果映射至java对象,通过statement中的resultType定义输出结果的类型。

7,Mybatis的简单实现步骤,优势

 在Mybatis中就把各种配置都是在配置文件中来实现,避免代码写死,更具有一处修改,多处修改的功能.
 在这里只是简单介绍

 简单步骤:

 1,首先要加载配置文件 ibatis.io包下的
    方式1: Resources.getResourceAsStream(“配置文件相对路径”) 
    方式2: 字节码文件对象.getClassLoader().getResourceAsStream("核心配置文件")
   相对于classPath的路径,其中获取配置文件的方式也可以有其他方式, 这是以字节流的方式,有配置文件方式,字符流方式等多种.
 2,在第一步的原材料准备完毕后,需要创建SqlSessionFactory工厂,
   其实现类 SqlSessionFactoryBulider调用方法build加载配置文件,这里是以字节流方式,
   SqlSessionFactory  sqlSessionFactory =new SqlSessionFactoryBuilder().bulid(inputStream);
 3,在创建了SqlSessionFactory对象后,就可以创建SqlSession对象了(其与数据库交互的对象)
    SqlSession  sqlSession =sqlSessionFactory.openSession(); 
 4, sqlSession 对象中有select( one, List), insert(1,2),update(1,2),delete(1,2)
 即增删改查操作, 一般选用2个参数的,第一参数是参入配置文件中映射的sql语句的id名,这样才可以在配置文件中找到具体唯一的要执行的sql语句,第二个参数是传入sql语句中的占位符需要传入的参数
 5,对于sqlSession对象执行完sql语句,查询不需要提交事务,其他的增改删都需要手动提交事务
 6,关流操作(底层封装的是连接池,将与数据库的连接对象还给连接池) 

猜你喜欢

转载自blog.csdn.net/qq_39494996/article/details/81474482