JDBC API解析

Posted 执久呀

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JDBC API解析相关的知识,希望对你有一定的参考价值。

目录

一、DriverManager

1、注册驱动:

二、Connection

1、获取执sql对象

2、事务管理

    mysql事务管理

演示jdbc的事务

三、Statement

1、执行sql语句

四、ResultSet

 ResultSet案例

五、PreparedStatement

PreparedStatement作用:

SQL注入

演示普通登录:

 sql注入演示:

 PreparedStatement解决SQL注入

 PrepareStatement原理


一、DriverManager

DriverManager(驱动管理类)作用:

1、注册驱动

2、获取数据库连接

1、注册驱动:

Class.forName("com.mysql.jdbc.Driver");

注册驱动的书写方法,表面上没有使用  DriverManager类,选中Driver,ctrl+b看源码可知


package com.mysql.jdbc;

import java.sql.DriverManager;
import java.sql.SQLException;

public class Driver extends NonRegisteringDriver implements java.sql.Driver 
    public Driver() throws SQLException 
    

    static 
        try 
            DriverManager.registerDriver(new Driver());
         catch (SQLException var1) 
            throw new RuntimeException("Can't register driver!");
        
    

它使用了 DriverManager.registerDriver()的方法

在MySQL5之后的驱动包,可以省略注册驱动的步骤

自动加载jar包中的META-INF/services/java.sql.Driver文件的驱动类

 2、获取连接

static Connection         getConnection(String url,String user,String password)

参数

  1、url:连接路径

        语法:jdbc:mysql://ip地址(域名):端口号/数据库名称?参数键值对1&参数键值对2....

        举例:jdbc:mysql://127.0.0.1:3306/db1(本机127.0.0.1,本机域名:localhost)

   细节: 如果连接的是本机mysql服务器,并且mysql默认端口号是3306  ,则url可以简写为:jdbc:mysql://数据库名称?参数键值对如:jdbc:mysql:///db1

配置userSSL=false参数,禁用安全连接方式,解决警告提示

2、user:用户名

3、password:密码

解决警告提示:

?userSSL=false

String url="jdbc:mysql://127.0.0.1:3306/db1?useSSL=false";

二、Connection

Connection(数据库连接对象)作用:

        1、获取执行SQL的对象

        2、管理事务

1、获取执sql对象

  • 普通执行SQL对象

Statement   createStatement()

  • 预编译SQL的执行SQL对象:防止SQL注入

PrepareStatement    prepareStatement(sql)

  • 执行存储过程对象

CallableStatement   prepareCall(sql)

2、事务管理

    mysql事务管理

开启事务:BEGIN;/START  TRANSACTION(start transaction)

提交事务:COMMIT;

回滚事务:ROLLBACK;

(MySQL默认自动提交事务)

JDBC事务管理: 

     Connection接口中定义了3个对应的方法

开启事务:setAutoCommit(boolean autoCommit);true为自动提交事务,false为手动提交事务(开启事务)

提交事务:commit()

回滚事务:rollback()

演示jdbc的事务

复制前面弄过的类到包下

package com.jdbc;

import com.mysql.jdbc.Connection;

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

public class JDBCConnectionDemo 
    public static void main(String[] args) throws Exception 
        //1、注册驱动
        Class.forName("com.mysql.jdbc.Driver");
       //2、获取连接
         //url的格式是:"jdbc:mysql://mysql的ip:端口号/操作的数据库"
        String url="jdbc:mysql://127.0.0.1:3306/kc_db01";
        //username是你的mysql用户名
        String username="root";
        //password是你的mysql密码
        String password="123456";
        Connection conn= (Connection) DriverManager.getConnection(url, username, password);
        //3、定义sql
        String sql1="update emp set salary=6666 where ename='zhangsan'";
        String sql2="update emp set salary=6666 where ename='lisi'";
        //4、获取执行sql的Statement对象
        Statement stat=conn.createStatement();
         
      //选中要处理的异常部分,ctrl+alt+t快捷键生成
        try 
            //开启事务
           conn.setAutoCommit(false);
           //执行sql
            int count1=stat.executeUpdate(sql1);
            //处理结果
            System.out.println("影响的行数:"+count1);

            //执行时sql
            int count2=stat.executeUpdate(sql2);
            //处理结果
            System.out.println("影响的行数:"+count2);

            //提交事务
            conn.commit();
         catch (Exception e) 
            e.printStackTrace();
            //回滚事务(回到开启事务之前,即什么也没处理前)
             conn.rollback();
        finally 
            //7、释放资源(先开后释放)

            stat.close();
            conn.close();
        

    

运行之前数据库emp表:

 运行结果:

 运行之后数据库emp表:

try之中的发生了异常 ,就会 被catch捕获,发生回滚,回滚到还没有开启事务之前,就是数据没有修改之前,若是没有用事务,就会导致可能一个成功一个失败,这是我们不愿意看到的。 启用了事务,用了回滚事务,可以保证多个事务要么同时成功,要么同时失败。

三、Statement

Statemen作用:

1、执行sql语句

int  executeUpdate(sql): 执行DML(对数据的增删改)DDL(对表和库的增删改)语句

返回值:(1)DML语句影响的行数(2)DDL语句执行后,执行成功也可能返回0

ResultSet   executeQuery(sql):执行DQL(对数据的查询操作)语句

返回值:ResultSet结果对象

四、ResultSet

ResultSet(结果集对象)作用:

1.封装了DQL查询语句的结果

ResultSet  stmt.executeQuery(sql):执行DQL语句,返回ResultSet对象

获取查询结果

boolean   next():(1)将光标从当前位置向前移动一行(2)判断当前行是否是有效行

    返回值:当前行有数据返回true,当前没数据返回false。

xxx     getXxx(参数):获取数据

    解释:xxx表示数据类型;如int  getInt(参数);String getString(参数);

    参数:对于int是列的编号,从1开始,对于String是列的名称。

使用步骤:

1、游标向下移动一行,并判断该行是否有数据:next()

2、获取数据:getXxx(参数)

示例:

while(rs.next())
    rs.getXxx(参数);

实例:

package com.jdbc;

import com.mysql.jdbc.Connection;

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

public class JDBCDemo3_ResultSet 
    public static void main(String[] args) throws Exception 
        //1、注册驱动
        Class.forName("com.mysql.jdbc.Driver");
       //2、获取连接
         //url的格式是:"jdbc:mysql://mysql的ip:端口号/操作的数据库"
        String url="jdbc:mysql://127.0.0.1:3306/kc_db01";
        //username是你的mysql用户名
        String username="root";
        //password是你的mysql密码
        String password="123456";
        Connection conn= (Connection) DriverManager.getConnection(url, username, password);
        //3、定义sql
        String sql="select *from emp";
        //4、获取执行sql的Statement对象
        Statement stmt=conn.createStatement();
        //5、执行sql语句
        ResultSet rs=stmt.executeQuery(sql);
        //6处理结果
      while(rs.next())
          //获取数据 getXxx();括号中可以写所在行,也可以写列名
          int id=rs.getInt(1);
          String ename=rs.getString(2);
          int salary=rs.getInt(3);
          //另一种写法:写行的名称
//          int id=rs.getInt("id");
//          String ename=rs.getString("ename");
//          int salary=rs.getInt("salary");
          System.out.println(id);
          System.out.println(ename);
          System.out.println(salary);
          System.out.println("-----------");
      
        //7、释放资源(先开后释放)
        rs.close();
        stmt.close();
        conn.close();

    

数据库中emp表

 运行之后:

 ResultSet案例

需求:查询account账户数据,封装为Account对象中,并且存储到ArrayList集合中

 创建一个pojo包,用来存放对象的。

 创建了一个类,提供getSet方法

package com.pojo;

public class Account 
    private int id;
    private String ename;
    private int salary;

    public int getId() 
        return id;
    

    public void setId(int id) 
        this.id = id;
    

    public String getEname() 
        return ename;
    

    public void setEname(String ename) 
        this.ename = ename;
    

    public int getSalary() 
        return salary;
    

    public void setSalary(int salary) 
        this.salary = salary;
    
    //为了更好的显示,重写toString()方法

    @Override
    public String toString() 
        return "Account" +
                "id=" + id +
                ", ename='" + ename + '\\'' +
                ", salary=" + salary +
                ''+"\\n";
    

jdbc包下创建的类中

package com.jdbc;

import com.mysql.jdbc.Connection;
import com.pojo.Account;

import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

public class JDBCDemo4_ResultSet 
    public static void main(String[] args) throws Exception 
        //1、注册驱动
        Class.forName("com.mysql.jdbc.Driver");
       //2、获取连接
         //url的格式是:"jdbc:mysql://mysql的ip:端口号/操作的数据库"
        String url="jdbc:mysql://127.0.0.1:3306/kc_db01";
        //username是你的mysql用户名
        String username="root";
        //password是你的mysql密码
        String password="123456";
        Connection conn= (Connection) DriverManager.getConnection(url, username, password);
        //3、定义sql
        String sql="select *from emp";
        //4、获取执行sql的Statement对象
        Statement stmt=conn.createStatement();
        //5、执行sql语句
        ResultSet rs=stmt.executeQuery(sql);
        //6处理结果
        //创建集合对象
        List<Account> list=new ArrayList<>();
      while(rs.next())
          //创建Account对象
          Account account=new Account();
          //获取数据 getXxx();括号中可以写所在行,也可以写列名
          int id=rs.getInt(1);
          String ename=rs.getString(2);
          int salary=rs.getInt(3);
          //赋值数据
          account.setId(id);
          account.setEname(ename);
          account.setSalary(salary);
          list.add(account);
      
        System.out.println(list);
        //7、释放资源(先开后释放)
        rs.close();
        stmt.close();
        conn.close();

    

运行结果:

五、PreparedStatement

PreparedStatement作用:

1、预编译SQL语句并执行:预防SQL注入问题

SQL注入

SQL注入是通过操作输入来修改事先定义好的SQL语句,用以达到执行代码对服务器进行攻击的方法。

演示普通登录:

首先数据录kc_db1下的emp表为:

package com.jdbc;

import com.mysql.jdbc.Connection;

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


public class JDBCDemo5_UserLogin 
    public static void main(String[] args) throws Exception 

       //2、获取连接
         //url的格式是:"jdbc:mysql://mysql的ip:端口号/操作的数据库"
        String url="jdbc:mysql://127.0.0.1:3306/kc_db01";
        //username是你的mysql用户名
        String username="root";
        //password是你的mysql密码
        String password="123456";
        Connection conn= (Connection) DriverManager.getConnection(url, username, password);
           String name="zhangsan";
           String pwd="1233";
        //3、定义sql
        String sql="select *from emp where ename='"+name+"'and password='"+pwd+"'" ;
        System.out.println("这条SQL语句是:"+sql);
        //4、获取执行sql的Statement对象
        Statement stat=conn.createStatement();
        //5、执行sql语句
        ResultSet rs = stat.executeQuery(sql);
        //6处理结果,rs有值说明查找成功
      if(rs.next())
          System.out.println("登录成功");
      else
          System.out.println("登录失败");
      
        //7、释放资源(先开后释放)
        rs.close();
        stat.close();
        conn.close();

    

运行结果:

 输入其他(不成功的原因是数据库中没有账号密码为这个的):

 sql注入演示:

对于这条sql语句来说不点在于密码,账号任意

 String name="随便写的名";
 String pwd=" ' or '1'='1";

运行结果:

这条SQL语句是:select *from emp where ename='随便写的名'and password=' ' or  '1'='1'

 sql注入的本质就是改变原有的SQL语句,加入or之后1=1恒为真,所以这条语句就是true

 PreparedStatement解决SQL注入

①获取PreparedStatement对象

//sql语句中的参数,使用?占位符代替
String sql="select *from user where username=? and password=?";
//通过Connection对象获取,并传入对应的sql语句
PreparedStatement  pstmt=conn.prepareStatement(sql);

②设置参数

PreparedStatement对象:setXxx(参数1,参数2):表示给参数1(?的位置)赋值为参数2

Xxx:数据类型;任意setInt(参数1,参数2)

参数

  •    参数1:表示?的位置编号,从1开始
  •    参数2: ?的值

③执行sql

executeUpdate();/excuteQuery();括号内不需要传递sql。

创建类:

package com.jdbc;

import com.mysql.jdbc.Connection;

import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;

public class JDBCDemo5_UserLogin 
    public static void main(String[] args) throws Exception 

       //2、获取连接
         //url的格式是:"jdbc:mysql://mysql的ip:端口号/操作的数据库"
        String url="jdbc:mysql://127.0.0.1:3306/kc_db01";
        //username是你的mysql用户名
        String username="root";
        //password是你的mysql密码
        String password="123456";
        Connection conn= (Connection) DriverManager.getConnection(url, username, password);
           String name="随便写的名";
           String pwd=" ' or '1'='1";
        //3、定义sql
        String sql="select *from emp where ename=? and password=?" ;

        //4、获取的PreparedStatement对象
        PreparedStatement pstmt = conn.prepareStatement(sql);
        //设置参数
        pstmt.setString(1, name);
        pstmt.setString(2, pwd);

        //5、执行sql语句
        ResultSet rs =pstmt.executeQuery();
        System.out.println("这条SQL语句是:"+sql);
        //6处理结果,rs有值说明查找成功
      if(rs.next())
          System.out.println("登录成功");
      else
          System.out.println("登录失败");
      
        //7、释放资源(先开后释放)
        rs.close();
       pstmt.close();
        conn.close();

    

 运行结果:

 这样就防止了sql注入,setXxx会对传入的参数会进行转义,不会拼接成字符串而是\\' or\\ ' 1\\' = \\' 1\\'

 输入正确的:

 PrepareStatement原理

PrepareStatement好处:

1、预编译SQL,性能更高

2、防止sql注入。

my.ini配置文件可以看到日志


log-output=FILE 
general-log=1
general_log_file="D:\\mysql.log" 
slow-query-log=1
slow_query_log_file="D:\\mysql_slow.log" 
long_query_time=2

预编译功能默认关闭

①:PreparedStatement预编译功能开启:userServerPrepStmts=true

 在sql语句?之后书写参数

        String url="jdbc:mysql://127.0.0.1:3306/kc_db01"?userServerPrepStmts=true;

开启就会要prepare预编译: 

 关闭之后就没有Prepare阶段

以上是关于JDBC API解析的主要内容,如果未能解决你的问题,请参考以下文章

源码解析Sharding-Jdbc模块分析

怎么用百度地图API获得当前位置

Google maps api v2如何找到最近的位置

怎么用百度地图api自动获取当前位置(谷歌的也行)

位置 api 有时在 android 中使用 google fused api 不给出确切的当前位置

golang 命令行参数解析 hflag