JDBC面试知识点整理(温习用)

要面试,因此把以前的笔记整理一遍,嘻嘻,加油java

JDBC编程mysql

使用JDBC,java程序能够轻松地操做各类主流数据库,Oracle,MySQL,等,使用JDBC编写的程序不只能够实现跨数据库,还具备跨平台性和可移植性。

JDBC(Java Database Connectiovity,Java数据库链接)是一种执行SQL语句的JavaAPI,程序能够经过JDBC API链接数据库,并使用SQL结构化查询语言完成对数据库的操做,程序员使用JDBC编程时只须要掌握标准的JDBC API 便可,当须要在不一样的数据库之间切换时,只须要更换不一样的数据库驱动类,是面向接口编程的典例应用。ios

JDBC访问数据库时主要完成三个操做:程序员

  • 创建与数据库的链接
  • 执行SQL语句
  • 获取执行结果

JDBC驱动 数据库驱动程序是JDBC程序和数据库之间的转换层,数据库驱动程序负责将JDBC调用映射成特定的数据库调用,有4种类型:JDBC-ODBC桥(最先),本地API驱动,网络协议驱动,本地协议驱动(建议使用,纯java编写)。面试

JDBC API:提供一组用于与数据库进行通讯的接口和类,都定义在java.sql包下。sql

Java.sql包经常使用接口和类数据库

  • DriverManager
    •   用于管理JDBC驱动的服务类,该类的主要功能是加载和卸载各类驱动程序,创建数据库链接并获取链接对象
  • Connection
    •   该接口表明数据库的链接,要访问数据库必须先得到数据库的链接
  • Statement
    •   用于执行SQL语句的工具接口,当执行查询语句时返回一个查询到的结果集
  • PreparedStatement
    •   该接口用于执行预编译的SQL语句,这些SQL语句带有参数,避免数据库每次都须要编译SQL语句,执行时传参
  • CallableStatement
    •   该接口用于调用SQl储存过程
  • ResultSet
    •   该接口表示结果集,包含访问查询的各类方法

使用JDBC API中的类或者接口访问数据库时,容易引起SQLException异常,属于检查性异常。须要放在try……catch语句里,对于DriverManager来说,要用到ClassNotFoundException异常。编程

 

DriverManager类:是数据库驱动管理类,用于管理一组JDBC驱动程序的基本服务,应用程序和数据库之间能够经过DriverManager创建链接,网络

DriverManager经常使用静态方法并发

  • static connection getConnection(String url,String user,String password)
    •   获取指定的URL的数据库链接,其中url为提供了一种标识数据库位置的方法,user用户名,password密码
  • static Driver getDriver(String url)
    •   返回可以打开url所指定的数据库的驱动程序

Connection接口:用于链接数据,每一个Connection表明一个数据库链接会话,一个应用程序能够与单个或者多个数据库链接,经过DriverManager类的getConnection()方法能够返回同一个Connection对象,该对象提供建立SQL的语法,完成基本SQL操做

Connection的经常使用方法

  • void close()
    •   断开链接,释放此Connection对象的数据库和JDBC资源
  • Statement createStatement()
    •   建立一个Statement对象来将SQL语句发送到数据库
  • void commit()
    •   用于提交SQL语句,确认从上一次提交/回滚以来进行的全部更改
  • boolean isClosed()
    •   用于判断Connection对象是否已经被关闭
  • CallableStatement prepareCall(String sql)
    •   建立一个CallableStatement对象来调用数据库储存过程
  • PrepareStatement(String sql)
    •   建立一个PreparedStatement对象来将参数化的SQL语句发送到数据库
  • void rollback()
    •   用于取消SQL语句,取消在当前事务中进行的全部更改

Statement接口:通常用于执行SQL语句,在JDBC中要执行SQL查询语句的方式有

  • 通常查询(Statement),
  • 参数查询(PrepareStatement)
  • 储存查询(CallableStatement )

三种方式。Statement和PreparedStatement和CallableStatement三个接口具备依次继承关系。

  • Statement接口的主要功能是将SQL语句传送给数据库,并返回SQL语句的执行结果,
  • Statement提交的SQL语句是静态的,不须要接受任何参数,SQL语句能够包含三种类型语句:SELECT查询语句,DML语句,DDL语句。

Statement接口经常使用方法

  • void close()
    •   关闭Statement对象
  • boolean execute(String sql)
    •   执行给定的SQL语句,能够返回多个结果
  • ResultSet executeQuery(String sql)
    •   执行给定SQL语句,返回单个ResultSet对象
  • int executeUpdate(String sql)
    •   执行给定的SQl语句,能够为DML语句或者DDL语句,返回影响行数
  • Connection getConnection()
    •   获取生成此Statement对象的Connection对象
  • int getFetchSize()
    •   获取结果集合的行数,该数是根据此Statement对象生成的ResultSet对象的默认获取大小
  • int  getMaxRows()
    •   获取由此Statement对象生成的ResultSet对象能够包含的最大行数
  • ResultSet getResultSet()
    •   获取由此Statement执行查询语句返回的的ResultSet对象
  • int getUpdateCount()
    •   获取此Statement执行DML语句所影响的记录个数
  • void cioseOnComplection()
    •   当全部依赖Statement对象的ResultSet结果集关闭时,该Statement会自动关闭
  • boolean isCloseOnCompletion()
    •   判断是否打开closeOnCompletion()
  • long executeLargeUpdate(String sql)
    •   加强版读完executeUpdate()方法,记录数超过Integer时使用,为long

ResultSet接口:用于封装结果集对象,该对象包含访问查询结果的方法,使用Statement中的executeQuery()方法能够返回一个ResultSet结果集对象(f封装了全部查询条件的记录),ResultSet具备指向当前数据行的游标,并提供了许多方法来操做结果集中的游标,提供getXXX()方法对结果集进行访问。调用next()方法游标会向下移动,      

ResultSet接口经常使用方法

  • boolean absolute(int row)
    •   将游标移动到row条记录
  • boolean relative(int rows)
    •   按相对行数(正或负)移动游标
  • void beforeFirst()
    •   将游标移动到结果集的开头(第一行前)
  • boolean first()
    •   将游标移动到结果集的第一行
  • boolean previous()
    •   将游标移动到结果集的上一行
  • boolean next()
    •   将游标移动到结果集中当前位置的下一行
  • boolean last()
    •   将游标移动到结果集的最后一行
  • void afterlast()
    •   将游标移动到结果集的末尾(最后一行后)
  • boolean isAfterLast()
    •   判断游标是否位于结果集的末尾(最后一行后)
  • boolean isBeforeFirst()
    •   判断游标是否位于结果集的开头(第一行前)
  • boolean isFirst()
    •   判断游标是否位于结果集的第一行
  • boolean isLast()
    •   判断游标是否位于结果集的最后一行
  • int getRow()
    •   检索当前行编号
  • String getString(int x)
    •   返回当前行第X列的列值,类型为String
  • int getInt(int x)
    •   返回当前行第X列的列值,类型为int
  • Statement getStatement()
    •   获取生成结果集的Statement对象
  • void close()
    •   释放此ResultSet对象的数据库和JDBC资源
  • ResultSetMetaData getMetaData()
    •   获取结果集的列的编号,类型,和属性

数据库环境搭建

  • 1,建立数据库表。
  • 2设置Oracle驱动类路径(Oracledatabase所提供的JDBC驱动程序(jre文件)导入到工程中)。

数据库访问:使用JDBC访问数据库步骤:

  • 加载数据库驱动
    •   Class.forName("数据库驱动类名");
      • mysql:com.mysql.jdbc.Driver;
      • oracle:oracle.jdbc.driver.OracleDriver;
  • 创建数据链接
    Connection conn = DriverManager.getConnection(String url,String user,String pass);                        
    mysql:DriverManager.getConnection("jdbc:mysql://localhost:3306/shop", "root","mysql");
    oracle:DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl","sys as sysdba","oracle");
  • 建立Statement对象:经过Connection对象获取Statement的方法;                                                                                             
    •    createStatement()//建立一个基本的Statement对象。
    •   prepareStatement(String sql)//根据参数化的SQL语句建立一个预编译的PreparedStatement对象。
    •   PrepareCall(String sql)//根据SQL语句建立一个CallableStatement对象,用于调用储存过程。   
  • 执行SQl语句:
    •   获取Statement对象后,能够调用该对象的不一样方法来执行SQL语句,有三种执行SQl语句的方法
      • executeQuery():只能执行查询语句,用于产生单个结果集。
      • executeUpdate()和executeLargeUpdate():用于执行DML和DDL语句,返回对应的行数和0;
      • execute():能够执行任何SQL语句返回值为布尔型。Statement对象将结果集分装为ResultSet对象并返回
  •  访问结果集:
    •   SQL的查询结果使用ResultSet封装,ResultSet结果集中包含了知足SQL查询条件的全部的行,使用getXXX()方法对结果集进行数据访问,经过列索引和列名获取游标所指的列数据,经过next()和循环控制游标。
  • 关闭对象
    •   关闭结果集,Statement对象,链接对象
  • 操做数据库:

 

Statement接口

execute()方法能够执行任何SQL语句,返回值为布尔型表示是否返回了ResultSet对象,true时使用Statement的getResultSet()方法来获取execute()方法执行SQL语句返回的ResultSet对象;false时使用getUpdateCount()方法获取受影响得行数。

executeUpdate()和executeLargeUpdate():用于执行DML和DDL语句,返回对应的行数和0;当DML语句影响的记录超过Integer.MAX_VALUE时,使用executeLargeUpdate(),类型为long;

PreparedStatement接口

 PreparedStatement对象包含的SQL语句进行预编译,须要屡次执行相同的SQL语句时,编译好的语句比Statement对象快。能够执行动态的SQL语句,即在SQL 语句中提供参数,动态SQL语句中用?做为动态参数的占位符。用setXXX()的方法经过占位符的索引完成对参数的赋值。

         例:String insterSql = "INSERT INTO LIRUILONG.my_tests VALUES(?,?)";   

         PreparedStatement ps = conn.prepareStatement(insterSql);

         ps.setInt(1,4);

         ps.setString(2, "李瑞龙");      

CallableStatement接口:

JDBC提供CallableStatement接口,用于执行数据库的储存过程,该接口能够处理通常的SQL 语句,也能够处理以三种带参数(IN ,OUT,IN OUT)的SQL储存过程,使用Connection类的prepareCall(String sql)方法能够建立一个CallableStatement对象,方法的参数能够是一个调用存储过程的字符串,cast = conn.prepareCall("{call LIRUILONG.addSub(?,?)");对CallableStatement的SQL语句执行通常用execute().

调用存储过程的SQL:“{call 存储过程名[(参数占位符?)]}”、、有返回值的:“{参数占位符?=call 存储过程名[(参数占位符?)]}”

CallableStatement接口经过setXXX()方法对IN参数进行赋值,

经过registerOutParameter(1, sql.Types.)方法对OUT参数进行类型注册,第二个参数一般使用java.sql.Types静态常量指定。

检索结果的获取经过getXXX()方法获取OUT和IN OUT参数的值,

对于IN OUT 参数的值来说须要先使用setXXX()方法对参数进行设置,而后使用registerOutParameter()进行类型注册,最后使用getXXX()方法来获取检索结果

数据库访问优化

即编写一个数据库访问工具类DBUtil,用于提供访问数据库时所用到的链接,查询等

编写属性文件:存放链接数据库的参数信息,在项目的更目录下建立一个config子目录。并添加一个属性文件oracle.properties,该文件以键-值对的形式保存链接Oracle的配置信息。在读取配置文件的配置信息时,须要编写一个Config配置类,在给类中经过java.util.Properrties类的get()方法来获取指定的“键”所对应的值。

编写DBUtil工具类。将SQL语句与参数包装传递

使用DBUtil工具类。

集元数据

集元数据(Meta Data)是有关数据库和表结构的信息,JDBC提供了获取这些信息的DatabaseMetaData和ResultSetMetaData接口。

DatabaseMetaData接口:DatabaseMetaData接口主要用于获取数据库相关信息,如数据库的全部表的列表,系统函数,关键字,数据库产品名以及驱动类型。DatabaseMetaData对象经过getMetaData()方法进行获取。DatabaseMetaData接口提供大量获取信息的方法,这些方法可分为两大类:

  • 返回值为boolean型,多用于检查数据库或驱动器是否支持某项功能,
  • 获取数据库或驱动的参数特征值。

DatabaseMetaData

  • boolean supportsOuterJolns()
    •   检查数据库是否支持外部链接
  • boolean supportsStoredProcedures()
    •   检查数据库是否支持储存过程
  • String getURL()
    •   返回用于链接数据库的URL地址
  • String getUserName()
    •   获取当前的用户名
  • String getDatabaseProductName()
    •   获取使用的数据库产品名
  • String getDatabaseProductVersion()
    •   获取使用的数据库版本号
  • String getDriverName()
    •   获取用于链接的驱动类型名称
  • String getProductVerslon()
    •   获取用于链接的驱动器版本号
  • ResultSet getTypeInfo()
    •   获取数据库中可能取得的全部数据类型的描述

ResultSetMetaData接口:用于获取结果集的结构信息,经过ResultSet的getMetaData()方法来获取对应的ResultSetMetaData对象

ResultSetMetaData的经常使用方法

  • int getColumnCount()
    •   返回此ResultSst对象中的列数
  • String getColumnName(int column)
    •   获取指定列的名称
  • int getColumnType(int cloumn)
    •   检索指定列的SQL类型
  • String getTableName(int column)
    •   获取指定列的表名
  • int getColumnDisplaySize(int column)
    •   指示指定列的最大标准宽度,以字符为单位
  • boolean isAutoIncrement(int column)
    •   指示是否为自动为指定列中进行编号,这些列任然为只读
  • int isNullable(int column)
    •   指示指定列中的值是否能够为null
  • boolean isSearchable(int column)
    •   指示是否能够在where子句中使用指定的列
  • boolean isReadOnly(int column)
    •   指示指定法人列是否明确不可写入

事务处理:

事务是保证底层数据完整的重要手段由一步或几步数据库操做序列注组成的逻辑执行单元。事务具备ACID四个特性:

  • 原子性(Atomicity):事务是应用中的最小执行单位,具备不可在分的特性,所有完成或不执行。
  • 一致性(Consistency):事务执行先后数据库都必须是出于一致状态。
  • 隔离性(Isolation):各个事务互不干扰,及并发事务间互不影响。
  • 持久性(Durability):事务一旦提交,对数据库的的物理存储进行改变,不被丢失。

事务处理包括事务提交,终止和回滚,事务提交分显式提交(commit)和自动提交,事务终止指未能成功完成事务,执行中断,事务回滚有显式回滚(rollback)和自动回滚(系统错误或强行退出)

JDBC对事务操做由Connection提供:

开启事务,执行任意多条DML语句,执行成功提交事务,失败回滚事务,Connection在默认状况下会自动提交,及事务是关闭的,一条SQL语句执行后,系统调用commit()方法提交数据库,没法回滚,使用Connection的setAutoCommit()方法能够开启关闭自动提交模式(事务),该方法为布尔型,参数false为关闭自动提交,反之打开自动提交。

  • 开启事务:conn.setAutoCommit(false);
  • 提交事务:conn.commit();
  • 回滚事务:conn.rollback();

当程序遇到未处理的SQLException异常,都会自动回滚,当捕获该异常时,则须要在处理块中显示回滚。

保存点操做:

  • 使用Savepoint类声明一个保存点对象(Savepoint s1),在须要的位置设置保存点(s1= conn.setSavepoint();)在回滚操做中能够回滚到保存点位置(conn.rollback(s1));

批量更新:

  • 即多条SQL语句被做为一批操做同时收集,并同时提交,必须获得底层数据库的支持,调用DatabaseLargeBatch()方法查看底层数据库是否支持批量更新。建立一个Statement对象,使用Statement对象的addBatch()方法收集多条SQL语句,调用Statement的executeBatch()或者executeLargeBatch()方法同时提交全部的SQL语句。

---------------------

 JDBC工具类

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/project
jdbc.user=root
jdbc.password=123456
jdbc.datasource.size=10
package com.lirong.sparkproject.constant;
 
public interface Constants {
    /**
     * 数据库相关常量
     */
    String JDBC_DRIVER = "jdbc.driver";
    String JDBC_URL = "jdbc.url";
    String JDBC_USER = "jdbc.user";
    String JDBC_PASSWORD = "jdbc.password";
    String JDBC_DATASOURCE_SIZE="jdbc.datasource.size";
}
import java.io.InputStream;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
 
import com.lirong.sparkproject.constant.Constants;
 
public abstract class JDBCHelper {
    //配置对象
    private static Properties prop=new Properties();
    /*
     * jdbc变量
     */
    static String driver=null;
    static String url=null;
    static String user=null;
    static String password=null;
    //thread封装Connection对象
    static ThreadLocal<Connection> thread=new ThreadLocal<Connection>();
    //惟一空构造器私有化,不容许外部建立对象
    private JDBCHelper() {}
    /**
     *  静态代码块为jdbc变量赋值
     * 由于静态代码块最早执行,因此调用getConnection()方法时,
     * 该方法内部的jdbc变量就完成了赋值操做
     */
    static {    
        try {
            //动态获取配置文件的路径
            InputStream in=JDBCHelper.class.getClassLoader().getResourceAsStream("my.properties");
            prop.load(in);//加载键值对信息
            /*
             * Constants常量接口中保存了不少常量,这些常量的值就是配置文件k-v数据的键
             * 
             */
            driver=prop.getProperty(Constants.JDBC_DRIVER);
            url=prop.getProperty(Constants.JDBC_URL);
            user=prop.getProperty(Constants.JDBC_USER);
            password=prop.getProperty(Constants.JDBC_PASSWORD);
            /*
             * 加载驱动,静态代码块只执行一次,驱动只加载一次(加载驱动很耗性能的)
             */
            Class.forName(driver);//加载驱动            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 经过本方法客获取一个MySQL数据库的Connection对象
     * 
     * @return Connection对象
     */
    public static Connection getConnection() {
        Connection con = thread.get();
        if(con==null) {
            try {
                con = DriverManager.getConnection(url, user, password);
                thread.set(con);
            } catch (SQLException e) {
                e.printStackTrace();
            }        
        }
        return con;//返回jdbc链接
    }
    
    /**
     * 本方法中调用Date类型变量的setter方法时使用的是java.sql.Date,
     * 因此实体类在声明Date类型变量时必定声明成java.sql.Date
     * 至少Date类型变量对应的setter方法的形参必须是java.sql.Date,不然报错
     * 
     * 查询完毕后,使用者经过JDBCHelper.getConnection()获取链接对象,并关闭它
     * 外部获取的链接对象与本方法使用的链接对象,在同一线程类,是同一个对象
     * 
     * @param sql   要执行的查询语句
     * @param t      实体类对象
     * @param objs    SQL语句中的参数
     * @return       装有实体类对象的list集合
     */
    public static <T> List<T>  executeQuery(String sql,T t,Object...objs){
        //声明jdbc变量
        List<T> list=new ArrayList<>();
        Connection conn = null;
        PreparedStatement ps =null;
        ResultSet rs =null;
        try {
            conn = JDBCHelper.getConnection();
            ps = conn.prepareStatement(sql);
            //给占位符赋值
            if(objs!=null) {
                for(int i=0;i<objs.length;i++) {
                        ps.setObject((i+1), objs[i]);
                }
            }
            //执行sql语句
            rs = ps.executeQuery();
            //获取结果集中字段的全部信息
            ResultSetMetaData rm = rs.getMetaData();
            int columnCount = rm.getColumnCount();//获取字段数
            //遍历结果集
            while(rs.next()) {
                    Class<? extends Object> cla = t.getClass();//获取类对象
                    T newInstance=(T)cla.newInstance();//获取类的对象
                    //一个for循环封装一条记录的全部值
                    for(int i=1;i<=columnCount;i++) {
                         String columnName = rm.getColumnName(i);//获取字段名
                        //获取字段对应的setter方法
                         String methodName="set"+columnName.substring(0, 1).toUpperCase()+columnName.substring(1);
                         String columnClassName = rm.getColumnClassName(i);//获取字段java类型的彻底限定名    
                         //建立方法对象
                         Method method = cla.getDeclaredMethod(methodName, Class.forName(columnClassName));
                         method.invoke(newInstance,rs.getObject(columnName));//调用setter方法,执行对象属性赋值
                    }
                    list.add(newInstance);//将对象加入集合
            }
        } catch (Exception  e) {
            e.printStackTrace();
        }finally {
            //关流
            JDBCHelper.close(ps,rs);
        }
        return list;
        
    }
    
    
    /**
     * 该方法封装了MySQL数据库的DML操做
     * 若是要实现事务:
     *         事务的开启,关闭,回滚,及链接对象的关闭等操做
     *             使用者经过JDBCHelper.getConnection()获取链接对象,经过链接对象并在外部声明
     *             外部获取的链接对象与本方法使用的链接对象,在同一线程类,是同一个对象
     * 
     * @param sql   要执行的SQL语句
     * @param objs  SQL语句中的参数
     * @return   成功执行返回影响的记录条数,不然返回0
     * @throws SQLException 
     */
    public static Integer executeDML(String sql,Object...objs) {
        //声明jdbc变量
        Connection conn =null;
        PreparedStatement ps =null;
        Integer i =0;
        try{            
            conn = JDBCHelper.getConnection();
            ps = conn.prepareStatement(sql);
            //给占位符赋值
            if(objs!=null) {
                for(int j=0;j<objs.length;j++) {
                    ps.setObject((j+1), objs[j]);
                }
            }
            //执行SQL语句
            i = ps.executeUpdate();
        }catch(SQLException e) {
            e.printStackTrace();
        }finally {
            //关流
            JDBCHelper.close(ps);
        }            
        return i;        
    }    
    /**
     * 关流的方法,接收任意多个任意类型的流对象
     * 若是关闭的流对象有关闭的前后顺序
     * 请将要先关闭的流对象放在前方
     * 
     * 全部流对象的顶级父接口都是AutoCloseable
     * @param t    要关闭的流对象,能够是一个或多个(也能够是零个)
     *                         
     */
    private static <T>void close(T...t){
        //循环关流
        for(T tmp:t) {
            //关闭流对象
            if(tmp instanceof AutoCloseable) {            
                try {
                    ((AutoCloseable)tmp).close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }                                            
        }
    }
}
相关文章
相关标签/搜索