JDBC学习笔记

JDBC基础知识

什么是JDBC

  • JDBC是一种用于执行SQL语句的Java API,它是由一组用Java语言编写的类和接口组成。它提供了一种操作数据库的标准。
  • JDBC的目标是使Java程序员使用JDBC可以连接任何提供了JDBC驱动程序的数据库系统

JDBC的机制:通过驱动包连接数据库,使用JDBC的API操作驱动包从而操作具体数据库

  • JDBC里面包含了数据库操作的规范类,接口,方法,但是JDBC自己并没有具体实现这些规范。而是通过驱动包来实现。各大数据库厂商根据JDBC规范,自己去实现JDBC的API的具体细节,而这些实现的API称为驱动包,要连接那个数据库,就将该数据库的JDBC驱动包导入,然后通过JDBC的API去操控驱动包,从而去操控具体的特定的数据库。

  • JDBC的API是java.sql包,使用JDBC时,只需要导入这个包到程序里就行。

    图示:![](http://ww1.sinaimg.cn/large/006dQ9gUgy1g1f6d4roo9j30fb0503yh.jpg)
    

连接MySQL

  • 添加驱动:就是从Java程序连通到驱动包
    **在项目中创建lib并将MySQL的驱动包复制进来

    **builder path 编译路径
    
  • 创建连接:就是从驱动包连接到数据库

    • A.加载驱动:把com.mysql.jdbc.Driver这份字节码加载进JVM,当该字节码加载进JVM时,就会执 行该字节码的静态代码块,该字节码的静态代码块会注册该驱动(看源码)
      ​ Class.forName(“com.mysql.jdbc.Driver”); //com.mysql.jdbc.Driver是驱动的名称

    • B.获取连接对象:即连接上数据库

      **获取连接对象需要数据库的地址URL,数据库的用户名和密码,url的格式是jdbc:mysql://主机名:端口/数据库名**
          String url="jdbc:mysql://localhost:3306/mytest"; 
          String user="root";
          String password="1234";
          Connection c=DriverManager.getConnection(url,user,password);
      
    • 用Java程序操作MySQL创建表

      • A.加载驱动:Class.forName(“com.mysql.jdbc.Driver”);
      • B.连接到数据库:Connection conn=DriverManager.getConnection(url,user,password);
      • C.创建要执行的SQL语句
        • 使用连接对象获取Statement对象,Statement接口是用来执行静态的SQL语句的。
        • 用Statement对象把SQL语句对象发送到数据库中执行,并返回执行结果:对于DQL语句返回查询结果集,对于DML语句返回受影响的行数,对于DDL返回0。
          例:
              String sql="create table stu(id int,name varchar(25),age int)";
              Statement st=conn.createStatement();
          
      • D.执行SQL语句

        DDL语句,DML语句使用Statement对象的:int execuUpdate(String sql) 方法
        DQL语句使用Statement对象的:ResultSet executeQuery(String sql)
                例:
                    int row=st.executeUpdate(sql);
        
      • E.释放数据资源
        为什么要释放资源?
        其实Connection连接就相当于Java到MySQL之间建立了管道,而Statement就是连接到MySQL的

        执行引擎来执行sql语句。
        **要关闭那些资源?**
                        res.close();  //先关闭结果集,如果有的话
                        st.close();   //再关闭的是数据库到mysql.exe的管道
                        conn.close(); //最后关闭的是Java程序到Mysql服务器的管道                
        
    • 异常处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
try {
Class.forName("com.mysql.jdbc.Driver");
conn=DriverManager.getConnection(url,user,password);
//执行DML语句
String sql="insert into stu values(2,'李四',20)";
st=conn.createStatement();
int row=st.executeUpdate(sql);
System.out.print(row);
}catch(Exception e) {
e.printStackTrace();
}finally {
if(st!=null)
{try { st.close(); } catch (SQLException e) {e.printStackTrace();}}
if(conn!=null)
{try { conn.close(); } catch (SQLException e) {e.printStackTrace();}}
}

JDBC执行SQL语句

  • 执行DDL语句,DML语句:使用Statement对象的:int execuUpdate(String sql) 方法
    该方法执行DML返回受影响的行数,执行DDL返回0;

  • 执行DQL语句:使用Statement对象的:ResultSet executeQuery(String sql) 方法,该方法会返回结果集对象。

    • JDBC的结果集ResultSet类对象:代表从数据库查询的结果,该类的方法:

      • boolean next() :判断是否有下一行数据,若有则自动移动到下一行,用于遍历结果集

      • getXxxx(Sting 列名):获取当前行的 指定列名 的数据,其中Xxxx代表该列的数据类型

      • getXxxx(int 列号):获取当前行的第几列(从1开始)的数据,其中Xxxx代表该列的数据类型
        当该列数据类型是 varchar/char/text类型时,Xxx代表String,当该列的类型是int/integer时,Xxx代表Int。

        例:
        
1
2
3
4
5
6
7
8
9
String sql="select * from emp";
ResultSet res=st.executeQuery(sql);
while(res.next())
{
int empno=res.getInt("empno");
String ename=res.getString("ename");
String job=res.getString("job");
System.out.println("empno = "+empno+" ename = "+ename+" job = "+job);
}

DAO(Data Access Object,数据存取对象)设计结束

  • 没有使用DAO存在的问题:当一个程序要去数据库例里查询数据,必须都得自己去加载驱动,连接对象,创建语句,执行语句,释放资源这五个步骤,每个Java程序都这样做,重复代码太多。
  • 什么是DAO
    DAO是位于业务逻辑层(java程序)和持久层(数据库)之间的一个抽像层,它是实现对持久层数据的访问。业务逻辑层只需要告诉DAO要对数据做什么,由DAO层来进行具体操作。DAO层自己实现加载驱动,连接对象,创建语句,执行语句,释放资源。然后向业务逻辑层提供增删改查的操作接口和方法,业务逻辑层只需要简单的调用方法即可访问数据库。大大简化了程序编写。降低耦合。

    ORM(Object Relation Mapping,对象关系映射)介绍

  • 什么是ORM
    ORM是一种模型,是一种程序设计技术思想,它将关系数据库中的表的记录映射成对象,将表中每一条记录都变成一个对象,目的是方便开发人员以面向对象的思想来实现对数据库的操作。
    
  • 表和对象的对应关系
       类            表
       对象         记录(行)
       属性         字段(列)
    例:
        一个表为:Person(name varchar(25),age int,gender varchar(5))
        则表对应的类为:
            class person{        //类名跟表名一样
                String name;    //属性名和属性类型跟表的字段名和字段属性都得一样。
                int age;
                String gender;
            }
        表中一条记录对应为一个对象:Person p=new Person();
    

    domain介绍

  • 什么是domain
    domain就是一个类,人们习惯成为这个名字,该类符合JavaBean的规范。它的作用是作为Java程序和数据库的核心中转站。这个类一般是 ORM 中的类,它其实就是表对应的类,它将数据库中数据,进行封装,并提供get/set供DAO和Java程序进行获取和设置数据。简单说:domain就是将记录中的列设计成属性,并给每个属性设计get/set方法。
    

面向接口编程

  • 为什么要定义接口

    根据客户需求先定义接口,业务具体实现通过实现类来完成,当客户提出新需求,只需要编写该业务逻辑的新实现类即可。
    例:
        假设客户要求写一个数据库DAO组件,先定义好接口(,连接接口,增删改查方法接口等),突然根据需要,程序要
        连接Oracle数据库,而之前只写MySQL数据库,这时只需要多写一个继承同一套接口的实现类即可。
    
  • 面向接口编程的好处

    **业务逻辑更加清晰
    **增强代码的扩展性
    **接口与实现相分离,适合团队协作。例如负责界面和后台开发,后台提供一套接口给界面人员使用,具体实现
      后台去做,界面只管用即可。这样界面开发人员就不用等后台人员写好实现类再去开发界面了。
    **降低耦合度,便于以后升级扩展
    

    DAO组件开发:基于上面三个概念DAO,ORM,domain来设计DAO组件。

    思想:先根据ORM模型写好domain类,再写好DAO组件

DAO设计规范

  • 定义DAO接口
  • 编写对应DAO接口的实现类
  • 包名规范:包名使用:域名倒写.模块名.组件名
    DAO包规范:
        edu.scnu.jdbc.domian     //该包存储所有domian类
        edu.scnu.jdbc.dao        //该包存储所有dao接口
        edu.scnu.jdbc.dao.impl   //该包存储所有dao接口的实现类
        edu.scnu.jdbc.dao.test   //该包存储所有DAO组件的测试类
    
  • 类名规范
    • domain类:类名跟表名一样,且见名知。存储在domain包中,用于描述一个对象,是一个JavaBean。
    • dao接口:I+domain类名+Dao,如:IStudentsDao。存储在dao包中,用于表示某一对象的CRUD声明。
    • dao实现类:domain类名+Dao+Impl,如:StudentsDaoImpl。存储在dao.impl包中,表示实现DAO接口的实现类

开发步骤

  • (1).创建表
  • (2).建立domain包和根据ORM模型编写domain类
  • (3).建立dao包和根据面向接口编程思想编写dao接口
  • (4).建立dao.impl包和dao实现类
  • (5).根据dao接口创建dao测试类
  • (6).编写实现类当中dao声明的方法体
  • (7).每编写一个dao方法,进行单元测试,测试功能是否正确

    • 先写好上面的代码,再重构,这些代码,提高精简性,扩展性。

    • 重构代码原则:

      • 同一个类中:在一个类里有多个方法中有较多重复代码时,就把它们抽到一个方法里,这些代码不同的地方通过参数传递进去。
      • 不同类中:不同类中有较多共同代码时,就抽取到一个新类里,大家再共享该类的内容。
    • 抽取DML语句方法:

      • 设计一个方法,要求传入两个参数,一个是预编译的sql语句,一个是预编译语句的参数,该参数为可变参数。返回受影响行数

        1
        2
        int execuUpdate(String sql,Object...params){.....}
        this.execuUpdate("select * from stu where id=? and name=?",13,"张三");
    • 抽取DQL语句方法:跟DML类似,不过是返回类型和里面的逻辑有差异而已。

    • 抽取DQL语句时对结果集的处理
      还会用到内省进制:内省就是用于查看和操作JavaBean中的属性。即方便获取JavaBean类的get/set方法。
      怎么使用内省

      使用Java API的几个个类:Introspector类  BeanInfo类
      步骤:
      A.使用Introspector类的一个静态方法 BeanInfo getBeanInfo(Class A,Class B) 获取一个JavaBean类的信息.其中A代表要获取的该类和其父类的信息,B表示如果它是A的父类,就忽略这个父类的信息。
      B.用得到的BeanInfo对象的方法PropertyDescriptor[] getPropertyDescriptors()获取该类的所有属性的属性描述器.
      C.遍历得到的属性描述器数组,并使用属性描述器对象的方法获取该属性的信息;
              String getName()              //获取该属性的属性名
              Method getReadMethod()        //获取该属性的get方法
              Method getWriteMethod()        //获取该属性的set方法
      D.在使用该javaBean类的字节码创建一个该类的对象:类名 obj=类名.class.newInstance();
      E.再用获取到的Method对象和用字节码创建的对象,使用该对象调用该Method代表的方法:Method对象名.invoke(用字节码创建的对象,该方法的实参列)
      例:
      
1
2
3
4
BeanInfo bean=Introspector.getBeanInfo(User.class,Object.class);
PropertyDescriptor[] pds=bean.getPropertyDescriptors();
User u=User.class.newInstance();
pds[0].getReadMethod().invoke(u,"zhangsan");

3.Statement接口:

  • (1).用于进行Java程序和数据库之间的数据传输。即负责把SQL语句发给数据库的执行程序mysql.exe执行,并获取结果
  • (2).该接口有三个具体的子类:
    • Statement:用于对数据库进行通用访问,使用的是静态sql
    • PreparedStatement:用于预编译sql模板语句,在运行是接受sql语句参数构成完整的sql语句。
    • CallableStatement:使用JDBC调用存储过程。
  • (3).Statement类执行静态sql语句

    • 先拼接好sql语句
    • 获取Statement对象,使用连接对象的createConnection()方法
    • 用Statement对象将语句发送给数据库

      例1:执行DML语句
          String sql = "insert into student(name,age) values('" +stu.getName + "'," + stu.getAge +")";
          Stetament st=conn.createStatement();
          st.execuUpdate(sql);   //记住要传参
      
      例2:执行DQL预编译语句
          Stetament st = conn.createStatement();
          String sql = "select * from student";
          ResultSet res = st.executeQuery(sql);
      
  • (4).使用PreparedStatement类执行预编译语句

    • 没有预编译语句时,所有sql语句都是静态的,即sql都要拼接,且执行前就要确定。
    • 有预编译语句,在性能和代码灵活性上有显著提高
    • 预编译语句更安全,如防止sql注入(就是通过把SQL语句插入到 web表单提交或输入域名或页面请求得查询字符串,最终达到欺骗服务器执行恶意的SQL语句,原理是:使用单引号截断静态sql语句,从而改变语义)。使用预编译语句会将传入的单引号转义,变成 \’ ,这样就无法截断sql语句,进而无法拼接sql语句,从而防止sql注入。
    • JDBC执行SQL语句的机制:Java程序通过DriverManager对象注册Connection对象,从而使Java程序连接上数据库系统,之后用连接对象创建Statement对象将sql语句发送给数据库系统,数据库系统拿到sql语句,先进行安全性分析和语法分析(因为DBMS获取的使字符串,要转为sql语句),然后到预编译语句池里查找该sql语句是否已经存在了,若是,直接执行。若没有就进行编译并保留在预编译池,再给mysql.exe执行。而如果使用预编译语句,PreparedStatement会把该预编译语句和参数一起发送给DBMS,预编译池编译第一次该预编译语句,然后将传来的参数填上,之后再发送该预编译语句,就直接拿存在预编译池的加上新参数即可。而静态sql语句,由于每一次参数不一样,因此每次都得编译。(mysql没有预编译池,故性能上体会不高)。
    • 预编译语句书写:先写好预编译模板SQL语句,其中的参数使用 ?作为占位符,表名该位置可以传参。然后使用setXxx(index,value)方法将实参输入第index位置的占位符中,index从 1 开始。Xxx根据value的类型而定,如value是varchar,Xxx为String。然后使用PreparedStatement对象进行封装,之后使用PreparedStatement类的方法,根据sql语句调用对应方法。

      例1:执行DML预编译语句
          String sql="select * from student where id=? and name=?";
          PerparedStatement ps=conn.prepareStatement(sql);
          ps.setInt(1,10);
          ps.setString(2,"张三");                
          ResultSet res=ps.execuQuery();   //记住execuQuery()跟执行静态sql语句不一样,它不需要参数。
      
      例2:执行DQL预编译语句    
          String sql="insert into student values(?,?)";
          ps.setInt(1,10);
          ps.setString(2,"张三");    
          PerparedStatement ps=conn.prepareStatement(sql);
          ps.execuUpdate();
      
  • (5).CallableStatement类:使用JDBC调用存储过程。
    步骤:

    • 在数据库当中定义一个存储过程
    • 使用连接对象的方法prepareCall(String sql)获取CallableStatement对象,这里的sql语句也可以使用预编译
    • 使用得到的CallableStatement对象设置参数
    • 使用得到的CallableStatement对象的方法executeQuery()方法执行调用存储过程的sql语句,返回一个结果集对象
    • 从结果集对象获取数据
      注:这里调用存储过程的sql语句有点不一样,调用存储过程格式:{ call 存储过程名(占位符) }对占位符赋值也有所不同,对于in型参数,使用setXxx(Xxx)方法,而对out型参数,则得这样:

      使用CallableStatement对象的registerOutParameter(index,out型参数的sql类型),
      
      例1:JDBC调用一个参数的存储过程
          Connection conn = JDBCUtil.getConn();
          CallableStatement prepareCall = conn.prepareCall(" { call getStu(?) } ");  //sql语句有点特殊
          prepareCall.setString(1, "王五");
          ResultSet res = prepareCall.executeQuery();
          if(res.next()) {
              Student stu=new Student();
              stu.setId(res.getInt("id"));
              stu.setName(res.getString("name"));
              stu.setAge(res.getInt("age"));
              System.out.println(stu);
          }
      
      例2:JDBC调用含输入输出参数的存储过程
          Connection conn = JDBCUtil.getConn();
          CallableStatement prepareCall = conn.prepareCall("{call getName(?,?)}");
          prepareCall.setInt(1, 6);
      
          prepareCall.registerOutParameter(2,Types.VARCHAR);  //不一样的地方
          prepareCall.execute();    //不一样的地方
      
          String name=prepareCall.getString(2);
          System.out.println(name);
      

4.JDBC处理事务:在Java程序中有些操作要当成一个事务来执行才不会出错。

  • 默认情况下,事务是自动提交的,因此为了执行自己写事务,要先设置为手动提交。
  • MySQL的InnoDB才支持外键和事务,MyISAM不支持外键和事务在写Java代码(或写SQL)时,只要进行 增,删,改才需要设置事务,查询不必设置事务
  • JDBC处理事务过程

    • 关闭事务自动提交:使用连接对象关闭:conn.setAutoCommit(false);
      写上必须当作一个事务来执行的Java代码片段
    • 该Java代码片段没有异常时,使用连接对象提交事务:conn.commit()
    • 该Java代码片段有异常时,使用连接对象进行回滚:conn.rollback()。回滚之后,事务结束,释放资源。事务的回滚是写在异常处理里面的,当该Java代码片段异常时,若不进行回滚,虽然不会更新数据库,但会占用资源所有出现异常时,要进行回滚。
      例:

      try
      {
          //开启事务手动提交
          conn.setAutoCommit(false);
      
          //zs账号减少1000
          sql="update account set money = money-? where name=?";
          ps=conn.prepareStatement(sql);
          ps.setDouble(1, 1000);
          ps.setString(2, "zs");
          ps.executeUpdate();
      
          3/0;   //这里出现异常,但由于没有执行到 conn.commit(); ,即事务没提交,之前的数据库操作
                 //并没有执行,因此解决了zs账号少钱了,ls却没增加的情况。
          //ls账号加1000
          sql="update account set money = money+? where name=?";
          ps=conn.prepareStatement(sql);
          ps.setDouble(1, 1000);
          ps.setString(2, "ls");
          ps.executeUpdate();
      
          //提交事务
          conn.commit();   //只要事务提交,数据库才执行Java的Statement接口发送过来的sql语句。否则就是Java代码执行了
                          //只要出现异常,没执行到这行代码,对数据库进行的操作就没用。
      }catch(Exception e){
          conn.rollback();  //若不回滚事务,会占用着资源。
      }
      

5.批处理:

  • (1).什么是批处理:一次性执行多条sql语句,允许多条语句一次性提交给数据库批量处理,比单独提交处理效率更高。

  • (2).怎么使用批处理:

    • A.将需要批处理的sql语句添加在一起:使用Statement接口的方法:addBatch(String sql)
    • B.:使用Statement接口的方法将批处理提交执行:executeBatch()

      例:
          Connection conn = JDBCUtil.getConn();
          String sql="insert into student (name,age) values (?,?)";
          PreparedStatement ps = conn.prepareStatement(sql);
      
          for(int i=0;i<1000;i++)
          {
              ps.setString(1,"zhangsan"+i);
              ps.setInt(2, 18);
              //如果不用批处理,每循环一次就发送一条sql语句给数据库执行,效率低
              //ps.executeUpdate();
              //使用批处理,先加到批处理里,再在循环外一次性提交
              ps.addBatch();
          }
          ps.executeBatch();
      
  • (3).注意事项:默认情况下,MySQL是不支持批处理的,从5.1开始,可以在数据库的url里添加一个参数:rewriteBatchedStatements=true来开启批处理。
    例:

    1
    String url = "jdbc:mysql://localhost:3306/数据库名?rewriteBatchedStatements=true";

6.池

  • (1).没有连接池的情况
    • 每次CRUD操作要使用数据库时,都要创建一个新的连接对象。普通的JDBC数据库连接使用DriverManager来获取而DriverManager每次都要将Connection加载到内存中,并且验证数据库的用户名和密码,而每次CRUD操作执行时,都获得一个连接对象,执行完后又释放断开连接,这样会大大消耗资源和时间。连接对象资源没得到很好的重复利用。
  • (2).池的介绍
    • 什么是池:池就是保存对象的容器,保存的对象叫什么该池就叫什么池
    • 连接池就是保存数据库连接对象的容器
    • 连接池的作用:系统启动初始化时,先创建一定数量的对象,需要时直接从池中取出一个空闲对象(没有就等待或新建),用完后并不直接销毁,而是放回对象池中以便重复利用。
    • 池的优势就是可以消除对象创建的所带来的延迟,从而提高系统性能。并且可以设置池的大小,控制访问量,还可以通过池的管理机制监视系统的访问数量,使用情况,为系统开发,测试及性能调整提供依据。
  • (3).池的属性:合理设置池的属性,会提高池的性能
    • 初始化连接数:初始化时,池中创建的对象数
    • 最大连接数:池中最多存储的对象数
    • 最小连接数:池中最少存储的对象数
    • 最大空闲时间:应用获取一个池中的对象后,在指定时间内没有任何动作,就会自动释放该对象
    • 最大等待时间:在指定时间内,一直尝试获取池中对象,超出该时间,就会提示获取失败。

7.连接池的使用

  • (1).在Java中提供了一个javax.sql.DataSource接口来表示连接池,DataSource跟JDBC一样,是一个规范,只提供一个接口,具体实现由第三方根据需要实现,只需遵循规范即可。
    • 常见的连接池实现
      • DBCP:Spring推荐,Tomcat的数据源就是使用DBCP
      • C3P0:它是一个开源代码的JDBC连接池,它和Hibernate一起发表,2007年后就不更新了,性能较差
      • Druid:阿里巴巴提供的连接池,除了连接池的功能外,还有更多的功能。国内常用
      • DataSource(数据源)和连接池Connection Pool是同一个东西,只是叫法不一样而已。
    • 使用连接池与不使用连接池的区别:
      • 获取连接对象方式不同:
      • 传统:Connection conn=DriverManager.getConnection(url,user,pwd);
      • 连接池:先用第三方的包获取数据源DataSource对象,在用DataSource对象获取池中的对象:Connection conn=DataSource对象.getConnection();
      • 释放资源方式不同:
      • 传统:直接和数据库断开连接,销毁连接对象。使用连接对象的close()方法。
      • 连接池:把连接对象还给连接池,下一个用户还可以继续使用
  • (2).连接池的操作

    • 主要学习如何创建DataSource对象,再从DataSource对象中获取Connection对象获取连接对象后,其余CRUD等操作跟以前一样(获取Statement对象/PreparedStatement对象,执行SQL语句等),不同的数据库连接池,在创建DataSource上不一样这些都是第三方提供好的,直接使用即可。
  • (3)DBCP连接池的使用:

    • 获取DataSource对象:(即创建连接池并设置该池的参数,如最大连接数)

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      //url的格式是jdbc:mysql://主机名:端口/数据库名
      String url="jdbc:mysql://localhost:3306/my_test";
      String user="root";
      String password="1234";
      String driverName="com.mysql.jdbc.Driver";
      //创建连接池
      BasicDataSource ds=new BasicDataSource();
      //初始化池
      ds.setDriverClassName(driverName);
      ds.setUsername(user);
      ds.setPassword(password);
      ds.setUrl(url);
  • 获取池中的连接对象

    1
    2
    3
    4
    5
    6
    Connection conn=ds.getConnection();				
    //之后的操作跟之前一样
    String sql="select * from student where name='李四'";
    Statement st = conn.createStatement();
    ResultSet res = st.executeQuery(sql);
    conn.close(); //这时并没有销毁该对象,只是还回池中而已。
  • 使用配置文件对连接池进行设置

  • 配置文件:是一种资源文件,以.properties为扩展名。配置信息以 键=值 形式存在。在上面使用数据库过程中,我们把数据库的连接地址,用户名,密码都写在代码里,不便于后期维护。因为我们的项目是部署到别人服务器里,别人的数据库连接信息肯定不一样,那部署人员部署项目时要连接数据库只能去该你写的Java代码,到他们不一定知道你怎么写的,因此为了安全和便利,专门提供一个配置文件,部署人员只需在配置文件上改就可以了。

  • 读取配置文件(先创建一个 source folder文件夹,然后创建一个.properties文件并输入信息)

    1
    2
    3
    4
    5
    6
    7
    8
    //创建配置文件对象
    Properties p=new Properties();
    //读取文件
    InputStream in=new FileInputStream("src/db.properties");
    //加载配置文件
    p.load(in);
    //根据键名获取配置信息
    p.getProperty("键名");
  • 连接池读取配置文件来设置数据源(连接池)
    例:
1
2
3
4
5
6
Properties properties=new Properties();
InputStream in = new FileInputStream("resource/db.properties");
properties.load(in);
DataSource ds=null;
//直接将配置文件给数据源即可,它会自动读取并设置
ds=BasicDataSourceFactory.createDataSource(properties);
**注:使用DBCP来加载配置文件,配置文件的键名就有了规定,要按要求。不按要求会出错.**
  • (4).Druid(德鲁伊)连接池的使用

    • Druid是一个JDBC组件库,不仅包含数据库连接池,还有SQLParser等组件。DruidDataSource是最好的数据库连接池,DruidDataSource的配置是兼容DBCP的,因此从DBCP迁移到DruidDataSource,只需需改数据库实现类即可。只需要将DBCP的代码中的 BasicDataSourceFactory 改为 DruidDataSourceFactory 即可。这样就迁移了。
    • DruidDataSource的使用
      例:

      1
      2
      3
      4
      5
      Properties properties=new Properties();
      InputStream in = new FileInputStream("resource/db.properties");
      properties.load(in); //直接将配置文件传给数据源就可以,它会自动读取并设置
      //DBCP和Druid就这句不一样而已
      DataSource ds=DruidDataSourceFactory.createDataSource(properties);

三.其他

1.存储图片

  • (1).数据库中可以直接存储图片的,将图片转为二进制即可。使用数据库中的数据类型:BLOB类型。它将图片,音频,视频转为二进制流之后就可以直接存储到数据库里了。
    • BLOB类型:
      • TINYBLOB:255字节
      • BLOB:65535zijie
      • MEDIUMBLOB:16M
      • LONGBLOB:4G
        实际上,真正的开发中,不会直接将多媒体存放到数据库里的,而是把多媒体文件的路径保存到数据库里,以后再取出该路径,根据该路径到那里拿。
  • (2).存储图片的操作

    • 在表里添加一个字段,该字段类型为BOLB类型

    • 通过Java代码存入一张图片:setBlob(index,InputStream)

    • 从数据库里取出图片: InputStream in = res.getBlob(“image”).getBinaryStream();
      例1:存入一张图片到数据库

      1
      2
      3
      4
      5
      Connection conn = JDBCUtil.getConn();
      String sql="insert into media (image) values (?)";
      PreparedStatement ps = conn.prepareStatement(sql);
      ps.setBlob(1,new FileInputStream("d://1.jpg")); //直接将图片路径
      ps.execuUpdate();

      例2:从数据库里取出图片

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      String sql="select * from media where name=?";
      PreparedStatement ps = conn.prepareStatement(sql);
      ps.setString(1, "美女");
      ResultSet res=ps.executeQuery();
      if(res.next()) {
      //获取图片
      Blob blob=res.getBlob("image");
      //获取图片的二进制流
      InputStream input=blob.getBinaryStream();
      Files.copy(input, Paths.get("d:/美女复件")); //将文件复制一份
      }

2.获取自动生成主键

在我们设置表时,会设置主键并设置自动增长,但我们用JDBC插入数据时,要想知道我们生成的主键是多少。
需求场景:用户注册时,添加用户名,密码后,点击注册,这时服务器后台将注册信息插入数据库,并跳转到完善个人信息的页面,用户填完这个后,提交到服务器里,这时服务器后台要将这些数据更新到刚刚插入的那条记录里,因此要获取刚刚插入的那条记录的主键,再根据主键更新数据。

  • (1).获取方法

    • 设置可以获取主键
      ​静态语句:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      Connection conn = JDBCUtil.getConn();
      String sql="insert into student (name,age) values ('zs',29)";
      Statement st = conn.createStatement();
      //设置可以获取主键
      st.executeUpdate(sql, Statement.RETURN_GENERATED_KEYS);
      //获取主键
      ResultSet res=st.getGeneratedKeys();
      if(res.next()) {
      int id=res.getInt(1);
      System.out.println(id);
      }

      预编译语句:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      Connection conn = JDBCUtil.getConn();
      String sql="insert into student (name,age) values (?,?)";
      //预编译语句设置可以获取主键
      PreparedStatement ps = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
      ps.setString(1, "lisi");
      ps.setInt(2, 99);
      ps.executeUpdate();
      //获取主键
      ResultSet res=st.getGeneratedKeys();
      if(res.next()) {
      int id=res.getInt(1);
      System.out.println(id);
      }
    • 获取主键
      无论是静态sql语句,还是预编译语句。都使用Statement对象的方法:ResultSet getGenerateKeys()
      ​例:

      1
      2
      3
      ResultSet res=st.getGenerateKeys();
      if(res.next())
      int id=res.getInt(1);

3.DBUtils的使用:DBUtils是一个Apache开发的一个框架,它封装JDBC的一些常用操作,可以很方便的操作数据库

  • 使用步骤:

    • (1).获取QueryRunner对象,传一个数据源给该对象,它会自动从连接池里获取对象,并提供一些简便操作

      1
      QueryRunner qr=new QueryRunner(DataSource ds);
    • (2).写好预编译语句或静态语句。

      1
      String sql="select * from stu where id=?";
    • (3).使用QueryRunner对象执行sql语句

      • DML/DDL语句:update(String sql,Object…params)
        ​例:

        1
        qr.update(sql,"张三",18,"男");
      • DQL语句:query(String sql,ResultSetHandler rs,Object…params),其中ResultSetHandler是结果集处理器,ResultSetHandler类根据内省来从结果集里取出值封装到对象里。ResultSetHandler类有BeanHandler(Class c),BeanListHandler(Class c),MapListHandler(Class c),等子类。例:

        1
        2
        3
        qr.query(sql, new BeanHandler<person>(person.class), "张三",18,"男");
        //将查询结果封装成一个指定对象的列表
        qr.query(sql, new BeanListHandler<person>(person.class), 4);
-------------本文结束感谢您的阅读-------------