JDBC

# JDBC介绍

  • (java数据基础连接,java Database Connectivity )是标准的java访问数据库的API。
  • sun公司为了简化,统一对数据库的操作,定义了一套java操作数据库的规范,称为JDBC
  • 驱动:两个设备要进行通信,满足一定通信数据格式,数据格式由设备提供商规定,设备提供商为设备提供驱动软件,通过软件可以与该设备进行通信。
  • 如果没有JDBC,java开发人员需要面向各个数据库驱动接口编程,开发复杂;Sun公司提供一套统一jdbc接口规范,java程序只需要使用JDBC就可以操作任何数据库,JDBC实现类由各个数据库厂商提供。

涉及到的包

  • java.sql
    • 类:DriverManger
    • 接口:Connection ResultSet Statement PreparedStatement
    • CallableStatement (用于调用存储过程)
  • javax.sql
    • 接口:DateSource

这里写图片描述

快速入门

Jdbc入门代码,完成对数据库操作

--编程从User表中读取数据,并打印在命令行窗口中
create table user(
id int primary key auto_increment,
username varchar(20) unique not null,
password varchar(20) not null,
email varchar(40) not null
);
import com.mysql.jdbc.Driver;
import java.sql.*;
import java.sql.Connection;
import java.sql.Statement;
/**
 * Created by zst on 2018/6/2.
 */
public class Mysql1 {
    public static void main(String[] args) throws SQLException {
        DriverManager.registerDriver(new Driver());

        Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/zst_db1", "root", "root");

        //System.out.println(con);
        Statement statement = con.createStatement();
        //因为主键设置了自增模式,所以插入数据时 主键用null 表示,不能手动写主键值
        String sql1="insert into user values (null,'xiaofu1','8709','678')";
        String sql2="select * from user";

        int i = statement.executeUpdate(sql1);
        ResultSet resultSet = statement.executeQuery(sql2);

        while(resultSet.next()){
            int anInt = resultSet.getInt("id");
            System.out.println(anInt);
        }
    //释放资源
    re.close();
    st.close();
    con.close();
    }
}

jdbc api 详解

DriverManager

JDBC程序中的DriverManger用于加载驱动,并创建与数据库的链接
该API常用的方法:

  • DriverManager.registerDriver(new Driver())
    • registerDriver方法分析
      • public static synchronized void registerDriver(java.sql.Driver driver)
  • DriverManager.getConnction(url,user,password)

注意:在实际开发中并不推荐采用registerDriver方法注册驱动。原因如下:

  • 查看Driver的源代码可以知道,如果采用此种方式,会导致驱动程序注册两次
    //com.mysql.jdbc.Driver类中的一段静态代码块
    static {
    try{
    java.sql.DriverManager.registerDriver(new Driver());
    }catch (SQLException E){
    throw new RuntimeException("Can not register driver!");
    }
    }
  • 程序依赖MySQL的API。脱离MySQL的jar包,程序将无法编译,将来程序切换底层数据库将会非常麻烦。
  • 推荐方式:Class.forName(“com.mysql.jdbc.Driver”);
    • 只加载一次,装入一个驱动对象。
    • 降低耦合,不依赖与驱动
    • 采用此种方式不会导致驱动对象在内存中重复出现,并且采用此种方式,程序仅仅只需要一个字符串,不需要依赖具体的驱动,使程序的灵活性更高。

通过DriverManager来获取连接对象

  • Connection con = DriverManager.getConection(String url,String user,String password);
    • url的作用用于确定使用哪一个驱动
    • MySQL url:jdbc:mysql://localhost:3306/数据库名
    • Oracle url:jdbc:oracle:thin:@localhost:1521:sid

DriverManager 的作用

  • 注册驱动
  • 获取连接 Connection

url

  • url格式
    • 主协议 子协议 主机 端口 数据库
    • jdbc:mysql:://localhost:3306/ 数据库名
  • MySQL的url可以简写
    • 前提:主机是localhost 端口号是3306
    • 简写:jdbc:mysql:///数据库名
  • 在url后面可以带参数
    • useUnicode = true&characterEncoding=UTF-8

Connection

java.sql.Connection 代表一个连接对象,即程序与数据库的连接

Connection作用

  • 通过Connection 获取操作SQL的Statement对象
    • Statement createStatement() throws SQLException
    • 示例:Statement st = con.createStatement();
    • 了解:
      • 可以获取执行预处理的PreparedStatement对象
        • PreparedStatement prepareStatement(String sql)throws SQLException
      • 可以获取执行存储过程的 CallableStatement
        • CallableStatement prepareCall(String sql )throws SQLException
  • 操作事务
    • setAutoCommit(boolean flag);开启事务
    • rollback();事务回滚
    • commit();事务提交

Statement

java.sql.Statement 用于执行SQL语句

  • Statement 作用
    • 执行SQL
      • DML:insert update delete
        • int executeUpdate(String sql)
        • 利用返回值判断非0来确定SQL语句是否执行成功
      • DQL:select
        • ResultSet executeQuery(String sql)
      • 可以通过execute方法来执行任何SQL语句
        • execute(String sql):用于向数据库发送任意sql语句
    • 批处理操作(多条SQL语句一起执行)
      • addBatch(String sql);将SQL语句添加到批处理
      • executeBatch();批量执行
      • clearBatch();清空批处理

ResultSet

java.sql.resultSet 它是用于封装select语句执行后查询的结果

jdbc程序中的resultSet用于代表Sql语句的执行结果。ResultSet封装执行结果时,采用的类似于表格的方式,ResultSet对象维护一个指向表格数据行的游标cursor,初始的时候,游标在第一行之前,调用ResultSet.next()方法,可以使游标指向具体的数据行,进而调用方法获取该行的数据。

//遍历结果集
while(rs.next()){
    int id=rs.getInt("id");
    String username=rs.getString("usename");
    String password=re.getString("password");
    String email = rs.getString("email");
System.out.println(id+""+username+""+password+""+email);

}

常用API

  • next()方法
    • public boolean next();
    • 用于判断是否有下一条记录,如果有返回true,并且让游标向下移动一行。如果没有返回false。
  • 可以通过ResultSet提供的getXXX()方法来获取当前游标指向的这条记录中的列数据。
    • 常用:
      • getInt()
      • getString()
      • getDate()
      • getDouble()
      • 参数有两种
        • getInt(int columnIndex);
        • getInt(String columnName);
      • 如果列的类型不知道,可以通过下面的方法来操作
        • getObject(int columnIndex);
        • getObject(String columnName);

这里写图片描述

释放资源

  • jdbc程序运行完后,要释放程序在运行过程中,创建的那些与数据库进行交互的对象,这些对象通常是ResultSet,Statement和Connection对象
  • 特别是Connection对象,它是非常稀有的资源,用完后必须马上释放,如果Connection不能及时,正确的关闭,极易导致系统宕机。Connection 的使用原则是尽量晚创建,尽量早释放。
  • 为确保资源释放代码能运行,资源释放代码一定要放在finally语句中
public class MyException{
    public static void main(String[] args){
        Connection con = null;
        Statement st=null;
        ResultSet rs=null;
        try{
            Class.forName("com.mysql.jdbc.Driver");
            con=DriverManager.getConnection("jdbc:mysql:///zst_db1","root","root")

            st=con.createStatement();
            rs=st.executeQuery("select * from user");
            while(rs.next()){
                int id=rs.getInt("id");
                String username=rs.getString("usename");
                String password=re.getString("password");
                String email = rs.getString("email");
                System.out.println(id+""+username+""+password+""+email);

             }
        }catch(ClassNotFoundException e){
            e.printStackTrace();
        }catch(SQLException e){
            e.printStackTrace();
        }finally{

            try{
                if(rs != null){
                    re.close();
                }
            }catch(SQLException e){
                e.printStackTrace();
            }
            try{
                if(st != null){
                    st.close();
                }
            }catch(SQLException e){
                e.printStackTrace();
            }
            try{
                if(con != null){
                    con.close();
                }
            }catch(SQLException e){
                e.printStackTrace();
            }       
        }
    }
}

工具类

  • 抽取Connection,因为不能确定用哪个Statement对象
  • 局限性
    • 只能针对MySQL数据库
    • 每一次调用getConnection,都会注册一次驱动。
public class JdbcUtils{
    public static Connection getConnection() throws ClassNotFoundException,SQLException{
    Class.forName("com.mysql.jdbc.Driver");
    Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/zst_db1","root","root");
    return con;

     }
}

对JdbcUtils进行修改

  • 通过配置文件进行改进
//jdbc.properties
driverClass = com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/zst_db1
username=root
password=123
public class JdbcUtils{
    private static final String DRIVERCLASS;
    private static final String URL;
    private static final String USERNAME;
    private static final String PASSWORD;

    static{
        DRIVERCLASS=ResourceBundle.getBundle("jdbc").getString("driverClass");
        URL=ResourceBundle.getBundle("jdbc").getString("url");      

        USERNAME=ResourceBundle.getBundle("jdbc").getString("username");

        PASSWORD=ResourceBundle.getBundle("jdbc").getString("password");

    }
//静态代码块注册驱动,保证驱动只加载一次
    static{
            try{
                Class.forName(DRIVERCLASS);
            }catch(ClassNotFoundException e){
                e.printStackTrace();
            }   
    }


    public static Connection getConnection() throws SQLException{

    Connection con = DriverManager.getConnection(URL,USERNAME,PASSWORD);
    return con;

     }
}


//关闭操作
public static void closeConnection(Connection con ) throws SQLException{
    if(con != null){
        con.close();
    }
}

滚动结果集

默认得到的ResultSet只能向下遍历(next()),对于ResultSet 它可以设置成是滚动的,可以向上遍历,或者直接定位到一个指定的物理行号。

  • 如何得到一个滚动结果集
    • Statement st = con.createStatement();
    • ResultSet rs = st.executeQuery(sql);
    • 这是一个默认的结果集:只能向下执行,并且只能迭代一次。
  • 创建Statement对象时,不使用createStatement();,而使用带参数的createStatement(int,int)
Statement createStatement(int resultSetType,int resultSetConcurrency)throws SQLException
  • resultSetType = 结果集类型,它可以是下列中的一个
    • ResultSet.TYPE_FORWARD_ONLY
      • 该常量指示光标只能向前移动的ResultSet对象的类型
    • ResultSet.TYPE_SCROLL_INSENSITIVE
      • 该常量指示可滚动,但ResultSet 对象的类型不受ResultSet底层数据更改的影响
    • ResultSet.TYPE_SCROLL_SENSITIVE
      • 该常量指示可滚动,但ResultSet 对象的类型受ResultSet底层数据更改的影响
  • resultsetConcurrency -并发类型,它可以是下列中的一个
    • ResultSet。CONCUR_READ_ONLY
      • 该常量指示不可更新的ResultSet对象的并发模式
    • ResultSet.CONCUR_UPDATABLE
      • 该常量指示不可更新的ResultSet对象的并发模式
  • 另外三种搭配模式
    • ResultSet.TYPE_FORWARD_ONLY —ResultSet。CONCUR_READ_ONLY
    • ResultSet.TYPE_SCROLL_INSENSITIVE —ResultSet。CONCUR_READ_ONLY
    • ResultSet.TYPE_SCROLL_SENSITIVE—ResultSet.CONCUR_UPDATABLE

//创建滚动结果集
Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSer.COMCUR_UPDATABLE);
ResultSet rs = stmt.executeQuery(sql);

对滚动结果集进行滚动和更新的方法

  • con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSer.COMCUR_UPDATABLE);
  • next();移动到下一行
  • previous();移动到前一行
  • absolute(int row)移动到制定行
  • beforeFirst();移动到ResultSet的最前面
  • afterLast(0;移动到ResultSet的最后面
  • updateRow();更新行数据

使用dao模式登录操作

  • DAO模式(Data Access Object 数据访问对象):在持久层通过DAO将数据源操作完全封装起来,业务层通过操作java对象,完成对数据源操作
    • 业务层无需知道数据源底层实现,通过java对象操作数据源

DAO模式结构

  • 数据源(MySQL数据库)
  • Business Object 业务层代码,调用DAO完成,对数据源操作
  • DataAccessObject 数据访问对象,持久层DAO程序,封装对数据源增删改查,提供方法参数都是java对象
  • TeansferObject 传输对象(值对象) 业务层通过向数据层传递 TO 对象,完成对数据源的增删改查

这里写图片描述

SQL注入

由于没有对用户输入进行充分检查,而SQL又是拼接而成,在用户输入参数时。在参数中添加一些SQL关键字,达到改变SQL运行结果的目的,也可以完成恶意攻击。

String sql = select* from user where username = ' '  and password = ' ';

String sql = select* from user where username = ' ' or '1'='1' and password = ' ';
-- 输入username;'老李' or '1'='1' password 随意

解决方案

  • PreparedStatement(重点)
  • 它是一个预处理的Statement,是java.sql.Statement接口的一个子接口
  • PreparedStatement的使用
    • 在SQL语句中,使用“?”占位
    • 得到PreparedStatement对象
      • PreparedStatement pst = con.PrepareStatement(String sql );
    • 对占位符赋值
      • pst.setXxx(int index,Xxx obj);
      • 举例:
        • setInt()
        • setString();
        • 参数index,代表的是”?”的序号,注意:从1开始
    • 执行SQL
      • DML:pst.executeUpdate();
      • DQL : pst.executeQuery();
      • 注意:这两个方法无参数
  • PreparedStatement优点
    • 解决SQL注入(具有预处理功能)
    • 不需要在拼SQL语句

jdbc处理数据块

MySQL中的数据块:

  • blob 大二进制
    • TINYBLOB(255)、BLOB(64kb)、MEDIUMBLOB(16m)和LONGBLOB(4g)
  • text(clob)大文本
    • TINYTEXT(255)、TEXT(64kb)、MEDIUMTEXT(16m)和LONGTEXT(4g)
  • 两种操作:insert select
//存储大文本
create table mytext(
        id int primary key auto_increment,
        content longtext
         );

//存储
File file = new File("D:\\java110\\workspace\\zst_db1\\a.txt");
FileReader fr = new FileReader(file);
pst.setCharacterStream(1,fr,(int)(file.length()));

//获取
Reader r = rs.getCharacterStream("content");

jdbc批处理

  • 一次可以执行多条SQL语句
  • 在jdbc中可以执行SQL语句的对象有Statement。PreparedStatement,它们都提供批处理
  • Statement执行批处理
    • addBatch(String sql);将SQL语句添加到批处理
    • executeBatch();执行批处理
    • clearBatch();
  • PreparedStatement 执行批处理
    • addBatch()
    • executeBatch()
    • clearBatch();
  • 以上两个对象执行批处理区别
    • Statement 更适合执行不同SQL的批处理,它没有提供预处理功能,性能比较低
    • PreparedStatement 适合执行相同SQL的批处理,它提供了预处理功能,性能比较高
  • 注意:
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值