Jdbc

Posted by Wh0ami-hy on June 26, 2021

1. JDBC简介

Java Database Connectivity 提供了访问数据库的API,它由一些Java类和接口组成。使用JDBC的应用程序一旦和数据库建立连接,就可以使用JDBC提供的API操作数据库

JDBC兼容的数据库,包括Oracle、MySQL、Derby、PostgreSQL、SQL Server、H2等

jdbc

2. JDBC功能

与一个数据库建立连接
向已连接的数据库发送SQL语句
处理SQL语句返回的结果
连接数据库方式:使用纯Java数据库驱动程序

3. JDBC使用(以MySQL为例)

步骤

加载驱动
连接数据库DriverManager
获得执行sq|的对象Statement
获得返回的结果集
释放连接

import java.sql.*;

public class work {
    

    public static void main(String[] args){
  
        try {// 注册驱动:不同数据库使用不同驱动串
            Class.forName("com.mysql.cj.jdbc.Driver");
        }
        catch(ClassNotFoundException e){
            System.out.println(""+e);
        }
        try{// 与数据库建立连接
            Connection con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/cj?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8", "root", "root");
            Statement sql = con.createStatement();
            // 向已连接的数据库发送SQL语句
            ResultSet rs = sql.executeQuery("SELECT * FROM cjb");// cjb为数据表名
			// 处理SQL语句返回的结果
            while(rs.next()){
                String xm = rs.getString(1);
                String pjf=rs.getString(4);
                String yx=rs.getString(6);  
                System.out.println("姓名:" + xm + "平均分" + pjf + "院系:" + yx);

            }
            // 释放连接
            rs.close();
            sql.close();
            con.close();
        }
        catch(SQLException e){
            System.out.println(e);
        }
    }
}

注意

com.mysql.jdbc.Driver 是 mysql-connector-java 5中的

com.mysql.cj.jdbc.Driver 是 mysql-connector-java 6中的

com.mysql.cj.jdbc.Driver, 需要指定时区serverTimezone

serverTimezone=UTC

在设定时区的时候,如果设定serverTimezone=UTC,会比中国时间早8个小时,如果在中国,可以选择Asia/Shanghai或者Asia/Hongkong

如果不需要使用SSL连接,需要通过设置useSSL=false来显式禁用SSL连接

useSSL=false

3.1. DriverManager

Connection con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/cj?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8", "root", "root");

connection 代表数据库,可实现:数据库设置自动提交、事务提交、事务滚回

3.2. Statement对象

用于向数据库发送SQL语句,完成对数据库的增删改查

try{ 
    Statement statement=con.createStatement();
}
catch(SQLException e){ 
    System.out.println(e);
}

实现 CRUD

statement.executeQuery('sql'); // 查询操作,返回ResultSet
statement.execute('sql'); // 可执行任何SQL
statement.executeupdate('sql'); // 更新、插入、删除。都是用这个,返回一个受影响的行数

3.3. ResultSet结果集

封装了所有的查询结果

ResultSet rs = sql.executeQuery("select * from 表名");

3.4. 游标

游标是一段内存区域,用于暂时存放受某条SQL语句影响后的数据(如查询后的结果集、DML影响后的记录)。通俗理解就是将这些数据暂时放到了一个内存区域的虚表中,而这个虚表就是游标。

ResultSet对象使用 next() 方法移动游标,定位某条记录。

            while(rs.next()){
                String xm = rs.getString(1); 
                String pjf=rs.getString(4);  
                String yx=rs.getString(6); 
                System.out.println("姓名:" + xm + "平均分" + pjf + "院系:" + yx);
            }

3.5. 释放资源

rs.close();
sql.close();
con.close();

4. CachedRowSetImpl 类

程序在使用ResultSet对象中的数据时,必须连接数据库,而CachedRowSetImpl对象不依赖Connnection对象,即把ResultSet对象中的数据保存到CachedRowSetImpl对象中后,就可以关闭和数据库的连接

CachedRowSetImpl对象可以保存ResultSet对象中的数据

CachedRowSetImpl对象继承了ResultSet对象的所有方法

import java.net.*; 
import java.sql.*;
import com.sun.rowset.*; 
public class Example12_5{
    public static void main(String args[]){
         Connection con;
         Statement sql; 
         ResultSet rs;
         CachedRowSetImpl rowSet;			
         try { Class.forName("com.mysql.cj.jdbc.Driver");  
         }
         catch(ClassNotFoundException e){
               System.out.println(""+e);
         }
         try{   
con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/cj?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8", "root", "root");
	sql = con.createStatement();
     	 rs = sql.executeQuery("SELECT * FROM cjb");
            rowSet = new CachedRowSetImpl();		//创建一个CachedRowSetImpl对象
            rowSet.populate(rs);				//
            con.close(); 			//现在就可以关闭连接了
            while(rowSet.next()){
                  String number=rowSet.getString(1);
                  String name=rowSet.getString(2);
                  Date birth=rowSet.getDate(3);
                  double height=rowSet.getDouble(4);
 System.out.println(number+","+name+","+birth+","+height);
               }
	}
         catch(SQLException e){
               System.out.println(e);
         }
    }
}

5. PreparedStatement 类

执行sql语句时,数据库中的sql解释器把sql语句生成底层的内部命令,然后执行该命令。当执行的sql语句较多时,会增加sql解释器的负担,影响速度。同时Statement对象执行sql存在SQL注入问题

使用Connection连接对象con调用方法,返回一个生成数据库底层内部命令的预处理对象pre,通过对sql语句进行预编译处理,提前生成数据库底层的内部命令,加快速度,防止SQL注入

PreparedStatement pre=con.prepareStatement("sql语句")

手动给参数赋值

预处理对象调用方法

  ResultSet executeQuery()
  int executeUpdate()
  boolean execute()

package Test;

import java.sql.*;
public class work{
    public static void main(String[] args) throws SQLException {
        Connection con;
        PreparedStatement pre;
        ResultSet rs;
        try { Class.forName("com.mysql.cj.jdbc.Driver");
        }
        catch(ClassNotFoundException e){
            System.out.println(""+e);
        }
        try {
            con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/cj?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8", "root", "root");
            // 使用 ? 占位符代替参数
            String sql = "insert into users(id,`name`) values(?,?)";
            // 预编译sql
            pre = con.prepareStatement(sql);
            // 手动给参数赋值
            pre.setInt(1,3);
            pre.setString(2,"laowang");
            // 执行
            rs = pre.executeUpdate();
            
            rs.close();
            sql.close();
            con.close();
        }
        catch(SQLException e){
            System.out.println(e);
        }
    }
}

使用预处理语句时可在语句中使用通配符?代替字段的值,但需要在预处理语句执行之前再设置通配符所表示的具体值

prepareStatement pre=con.prepareStatement
               ("SELECT * FROM message where height<?")
pre.setDouble(1,1.72);
rs=pre.executeQuery();

// 类似方法:setInt 、setLong 、setFloat 、setString 、setDate 

6. 事务

事务由一组SQL语句组成,指应用程序保证事务中的SQL语句要么全部都执行,要么一个都不执行。

将connection对象设置非自动提交。con产生的Statement对数据库提交的任何sql语句都是立即生效的,实际应用时,需要多条sql语句同时执行生效或同时不执行。这时用到如下方法,设置connection对象为非自动提交

con.setAutoCommit(false);

在SQL语句组后使用commit()方法

提交的多个sql语句不会被执行,这些sql语句构成了一个事务。直到调用commit()方法,让事务中的sql语句全部生效

con.commit()

提交失败(异常)使用rollback()方法回滚

         catch(SQLException e){
               try{ con.rollback();             
               }
               catch(SQLException exp){}
               System.out.println(e);
         }

package Test;

import java.sql.*;
public class work{
    public static void main(String args[]){
        Connection con=null;
        Statement sql;
        ResultSet rs;
        try { Class.forName("com.mysql.cj.jdbc.Driver");
        }
        catch(ClassNotFoundException e){
            System.out.println(""+e);
        }
        try{   double n=50;
            con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/cj?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8", "root", "root");
            con.setAutoCommit(false);
            sql=con.createStatement();
            rs=sql.executeQuery("SELECT * FROM user WHERE number='0001'");
            rs.next();
            double moneyOne=rs.getDouble("userMoney");
            moneyOne=moneyOne-n;
            rs=sql.executeQuery("SELECT * FROM user WHERE number='0002'");

            rs.next();
            double moneyTwo=rs.getDouble("userMoney");
            moneyTwo=moneyTwo+n;
            sql.executeUpdate("UPDATE user SET userMoney ="+moneyOne+" WHERE number='0001'");
            sql.executeUpdate("UPDATE user SET userMoney="+moneyTwo+"WHERE number='0002'");
            con.commit();
            con.close();
        }
        catch(SQLException e){
            try{ con.rollback();
            }
            catch(SQLException exp){}
            System.out.println(e);
        }
    }
}

7. 数据库连接池

池化技术:准备一些预先的资源,过来就使用预先准备好的,用完再放回池中

编写连接池,实现一个接口 DataSource

DBCP
C3P0
Druid 阿里巴巴
HikariCP springboot2.x默认

本站总访问量