JavaWeb基础—JDBC入门

一、什么是JDBC

  JDBC全称为:Java Data Base Connectivity(java数据库连接),它主要由接口组成

二、JDBC原理概述

  JDBC原理:其实就是一组规范(就是对类的规范,也就是接口),各大数据库厂商对其实现
    这些所说的驱动类也就是JDBC的实现
    但是官方的实现并不是特别完整(毕竟免费),存在第三方的实现

    查看连接的几句代码,似乎并没有什么紧密联系。第一句的Class.forName() 注册驱动
    看下面的另外的相同效果的代码
    com.mysql.jdbc.Driver driver = new com.mysql.jdbc.Driver()
    DriverManager.registerDriver(driver);

    看源码可以清晰发现原理再去源码里面的静态块(在类加载的时候执行)
    JDBC4.0之后DriverManager.getCoonection()会自动加载驱动类,
    但为了兼容老版本,建议写Class.forName();

三、一个初级的连接小例子

对于连接JDBC我也只是略懂而已,以下是我写的代码,顺便告诉你一个小窍门:

  “贾琏欲执事”,

  意思就是加载驱动,连接数据库,创建需要的SQL语句,执行语句,释放链接。

package com.mysql.test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import org.junit.Test;

public class Demo01 {
    @Test
    public void test1() throws SQLException, ClassNotFoundException{
        //加载驱动类,新特性已经免去此特性
        //Class.forName("com.mysql.jdbc.Driver");严重不建议使用registerDriver
        String url = "jdbc:mysql://localhost:3306/mydb";
        String username = "root";
        String password = "root";
        Connection con =  DriverManager.getConnection(url,username,password);
        
        Statement stmt =con.createStatement();
        String sql = "INSERT INTO ab VALUES(6,'测试JDBC')";//语句不要加分号
        int i =stmt.executeUpdate(sql);//完成DML,即增删改操作
        System.out.println(i);
    }
    @Test
    public void test2() throws SQLException, ClassNotFoundException{
        //加载驱动类,新特性已经免去此特性,当然不建议省略
        //Class.forName("com.mysql.jdbc.Driver");
        String url = "jdbc:mysql://localhost:3306/mydb";
        String username = "root";
        String password = "root";
        Connection con =  DriverManager.getConnection(url,username,password);
        
        Statement stmt =con.createStatement();
        String sql = "SELECT * FROM stu";//语句不要加分号
        ResultSet rs = stmt.executeQuery(sql);
        int count = rs.getMetaData().getColumnCount();
        while(rs.next()){
            for(int i=1;i<=count;i++){
                System.out.print(rs.getString(i));
            }
            System.out.println();
        }
        //不关各种软病(时好时坏)
        rs.close();
        stmt.close();
        con.close();
    }
}

结果集的操作:
  默认的结果集是不可滚动的,不能执行上一行,下N行等操作,即forward_only(小卒只能向前拱)
  光标有第0行和结果集最后一行后一行的位置。
  【!】默认返回的结果集的光标在beforeFirst上,需要用next()方法来进行移动
  相关滚动的方法查看SE的ResultSet()里的滚动方法
  获取结果集元数据
  re.getMetaData(),返回ResultMetaData(),使用相关get方法,得到多少行,多少列等
  int count = rs.getMetaData().getColumnCount();
  while(rs.next()){
  for(int i = 1;i<=count;i++){
  syso(rs.getString(i));//都可以转为String ,当然这里写getObject()也是可以得
  }
  }

  ResultSet还提供了对结果集进行滚动的方法:(更详尽的方法请查阅API)

  • next():移动到下一行
  • Previous():移动到前一行
  • absolute(int row):移动到指定行
  • beforeFirst():移动resultSet的最前面。
  • afterLast() :移动到resultSet的最后面

结果集的特性:【了解】 平时用的多的都是类似于照片,拿完就走
  *是否可滚动
  *是否敏感[一般不敏感]
  *是否可更新

  在createStatement得到Statement的时候就已经决定
  默认空参数(整型参数)时三特性为否,详细看SE文档,
  !当然【MySQL特性有可滚动】,正常都是forward_only

最后,我们提取出一个工具类 JdbcUtils:

  前提工具是驱动包以及配置文件:

    

配置文件信息较简单:

  

然后就可以提取出这个类:

package com.jdbc.utils;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;

/**
 * 连接数据库工具类
 * 考虑到换别的数据库,使用四大参数进行传递
 * 注意在配置文件中更改参数再加载即可连接其它数据库
 * @author jiangbei01
 *
 */
public class JdbcUtils {
    //有错,待改进
    //改进后配置文件只加载一次
    private static Properties props = null;
    static {
        try{
            //加载配置文件中的四大参数
            InputStream in = JdbcUtils.class.getClassLoader()
                    .getResourceAsStream("dbconfig.properties");
            props = new Properties();
            props.load(in);
        }catch(IOException e){
            throw new RuntimeException(e);
            }
        try {
            //加载驱动类,通过键得到值得方式
            Class.forName(props.getProperty("driverClassName"));
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
    public static Connection getConnection() throws SQLException{
        /*
        String url = "jdbc:mysql://localhost:3306/mydb";
        String username = "root";
        String password = "root";*/
        //得到conn
        return DriverManager.getConnection(props.getProperty("url"),
                                           props.getProperty("username"),
                                           props.getProperty("password"));
    }
}

 四、引入PreparedStatement 

是Statement的子接口。
前提是都支持PreparedStatement:当然主流数据库都支持
使用方法:
  1.给出SQL模板(参数有?给出,?只能作为参数不参与SQL语句的构成)
  2.使用con的preparedStatement()方法

  3.使用pstmt.setXXX方法为参数幅值
更加强大:
  1.防SQL攻击
'  a' or 'a'='a'等SQL语句(打出来即可知道,可以知道)
  当然,这不是PreparedStatement的主要功能,可以简单简单校验等即可防止非法语句
  2.提高代码的可读性,可维护性
  3.效率更高
  (加``避开关键字)

原理:
  服务器的工作: 校验SQL语句的语法(工作量大!吃鱼的时候挑刺的时间多)
  编译:一个与函数相似的东西
  执行:类似调用函数

  每个pstmt都与一个SQL模板校验,先校验,把SQL模板给服务器,编译,执行时把参数给他
  二次执行时直接给参数就行

【注意】MySQL预编译默认是关闭的

给出一个链接的小例子:

package com.mysql.test;

import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.junit.Test;

import com.jdbc.utils.JdbcUtils;

/**
 * 测试PreparedStatement
 * @author jiangbei01
 *
 */
public class Demo02 {
    
    @Test
    public void fun1(){
        //准备四大参数
        String driverclassName = "com.mysql.jdbc.Driver";
        String url = "jdbc:mysql://localhost:3306/mydb";
        String username = "root";
        String password = "root";
        
        Connection con = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        
        try {
            //加载驱动,(可以省略,但是不建议省略)
            Class.forName(driverclassName);
            //得到连接
            con = DriverManager.getConnection(url, username, password);
            //给出SQL模板,获得preparedStatement
            String sql = "SELECT * FROM ab WHERE aid=?";
            pstmt = con.prepareStatement(sql);
            //调用方法,执行查询语句
            pstmt.setInt(1, 1);
            rs = pstmt.executeQuery();//方法都无参,前面都给过了
            System.out.println(sql);
            if(rs.next()){
            System.out.println(rs.getString(2));}
            
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        finally{
            //关闭资源
            if(rs != null)
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            if(pstmt != null)
                try {
                    pstmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            if(con != null)
                try {
                    con.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
        }
        
    }
    
    /**
     * 测试自己写的工具类JdbcUtils
     * @throws SQLException 
     * @throws IOException 
     * @throws ClassNotFoundException 
     */
    @Test
    public void fun2() throws SQLException{
        Connection con = JdbcUtils.getConnection();
        System.out.println(con);
    }
}

 五、处理大数据

大数据也称之为LOB(Large Objects),LOB又分为:clob和blob,clob用于存储大文本,blob用于存储二进制数据,例如图像、声音、二进制文等。

  在实际开发中,有时是需要用程序把大文本或二进制数据直接保存到数据库中进行储存的。

  对MySQL而言只有blob,而没有clob,mysql存储大文本采用的是Text,Text和blob分别又分为:
  TINYTEXT、TEXT、MEDIUMTEXT和LONGTEXT
  TINYBLOB、BLOB、MEDIUMBLOB和LONGBLOB

给出一个小例子:

package com.mysql.test;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.sql.rowset.serial.SerialBlob;

import org.apache.commons.io.IOUtils;
import org.junit.Test;

import com.jdbc.utils.JdbcUtils;

public class Demo03 {
    /**
     * 测试存储大数据
     * @throws SQLException 
     * @throws IOException 
     * @throws FileNotFoundException 
     */
    @Test
    public void fun1() throws Exception{
        //得到连接
        Connection con = JdbcUtils.getConnection();
        //准备模板
        String sql = "INSERT INTO file VALUES(?,?,?)";
        //得到pstmt
        PreparedStatement pstmt = con.prepareStatement(sql);
        //设置模板中的参数,进行执行
        pstmt.setInt(1, 1);
        pstmt.setString(2, "晴天.mp3");
        //问题是变blob,思路是文件变字节数组bytes[] 注意使用IO包
        byte[] bytes = IOUtils.toByteArray(new FileInputStream("F:/晴天.mp3"));
        Blob blob = new SerialBlob(bytes);
        pstmt.setBlob(3, blob);
        pstmt.executeUpdate();
        
    }
    /**
     * 从数据库中读取mp3
     * @throws Exception 
     */
    @Test
    public void fun2() throws Exception{
        //得到连接
        Connection con = JdbcUtils.getConnection();
        //给出模板
        String sql = "SELECT * FROM file";
        //得到pstmt
        PreparedStatement pstmt = con.prepareStatement(sql);
        //无参数,不设置
        ResultSet rs = pstmt.executeQuery();
        //移动光标,查询数据
        if(rs.next()){
            Blob blob = rs.getBlob(3);
            //转为输入流,再利用文件复制
            InputStream in = blob.getBinaryStream();
            OutputStream out = new FileOutputStream("F:/1.mp3");
            IOUtils.copy(in, out);
        }
    }
}
原文地址:https://www.cnblogs.com/jiangbei/p/6696707.html