数据库:【第二章】JDBC接口

1 JDBC本质

  1. JDBC:Java DataBase Connective
    • 本质是一个sun公司制定的一套接口:java和数据库连接的接口
  2. 数据库厂家面对接口,编写了很多实现类,这些类就是驱动

以下是模拟JDBC本质的代码:一套连接java和数据库的接口

//接口指定者:sum公司 编写JDBC接口
interface JDBC{
    //抽象方法:连接 返回类型 + 方法名();
   void getConnection();    
}
------------------------------------------------------------------
//实现者:MySQL厂家
public class MySQL implements JDBC{
    //具体实现方法
    public void getConnection(){
        //MySQL底层原理
        //...
        System.out.println("MySQL");
    }
    
}
------------------------------------------------------------------
//调用者1: 程序员 面向JDBC接口编程
public class JavaProgrammer1{    
    public static void main(String[] args){
        //接口是抽象的,无法new出对象
        //JDBC jdbc = new JDBC();
        //但是java中存在多态机制,即父类型引用可以指向子类型
        //父类型[接口]:JDBC, 子类[实现接口的类]:MySQL
        JDBC jdbc = new MySQL();
        
        //调用子类中的方法
        jdbc.getConnection();
        
    }        
}
------------------------------------------------------------------
//调用者2:采用反射机制,创建对象
public class JavaProgrammer2{
    public static void main(String[] args) throws Exception{   
        //配置文件源
        ResourceBundle bundle = new ResourceBundle("jdbc");
        //根据key获取value值
        String className = budle.getString("className");
        Class c = Class.forName(className);
        //实例化对象
        JDBC jdbc = (JDBC)c.newInstance();
        jdbc.getConnection();             
    }
}

------------------------------------------------------------------
//配置文件:jdbc.properties
className=MySQL

2 JDBC编程(六步)

  1. 注册驱动
    • 告诉Java程序,即将连接哪种品牌的数据库
  2. 获取连接
    • 打开JVM和数据库的进程通道。注:使用完,需要关闭通道
  3. 获取操作对象
    • 专门执行SQL语句的对象
  4. 执行SQL语句
    • DQL、DML…
  5. 处理查询结果
    • 只有当第四步由select语句,才有这一步查询结果集
  6. 释放资源
    • 使用完资源,一定要关闭

3 JDBC编程时出现的问题:SQL注入

  1. 什么是SQL注入?

    • 注入了不安全的信息
  2. 什么是不安全的信息?

    • 所谓不安全的信息,指的是输入了带有SQL语句的关键字,使得原本SQL语句的意思发生改变,这样造成数据库的不安全
  3. 如何防止SQL注入?

    • 在SQL语句注入前,对其进行预处理

      • 所谓预处理,就是先制定SQL语句的框架。SQL语句中的那些从外部输入的信息,用占位符?替代
      • 再调用PreparedStatement**,获取预准备操作对象**
      • 通过PreparedStatement,调用setObject(1,userName)传入指定下标的参数,JDBC下标是从1开始
      • 通过ps.executeQuery(),执行SQL语句,返回ResultSet结果集合

4 详细JDBC操作流程:防止SQL注入

  1. 注册驱动

    • 告诉java程序,获取什么品牌的驱动

      Class.forName("com.mysql.cj.jdbc.Driver");
      
  2. 获取连接

    • 通过驱动管理(DriverManager),连接java和数据库进程通道

      Connection conn = DriverManager.getConnection(url,user,password);
      

      注意:在获取连接的时候,可能会出现以下异常

      java.sql.SQLException: The server time zone value '�й���׼ʱ��' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support.
      

      原因:mysql的时区问题

      方法一:【推荐】

      在dos窗口,连接完数据库后,修改mysql的时区

      set global time_zone = '+8:00';//修改Myqsl全局时区为北京时间,即我们的东8区
      set time_zone = '+8:00';//修改当前会话时区
      

      方法二:修改url

      String url = "jdbc:mysql://localhost:3306/aa?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC";
      
  3. 编写SQL语句框架

    • 利用占位符?表示后面传入的参数

      String sql = "select * from tb_user where loginName = ? and loginPws = ?";
      
    • 目的:防止SQL注入,因为输入的信息,可能含有SQL语句的关键字,从而可能会修改了本地SQL语句,造成本地数据库不安全。

    • 在MySQL中,如果SQL语句一致,则只会编译一次,下一次执行,不会编译,直接输出结果。因而,设置了SQL语句框架,只会执行一次,后续修改,只要修改?占位符就行。提高执行效率

  4. 获取数据库预准备操作对象

    • 通过JDBC通道,调用预准备操作对象(PrepareStatement)

      PreparedStatement ps = conn.prepareStatement(sql);
      
  5. 输入占位符?形参 : JDBC下标从1开始

    • 通过预准备操纵对象的setObject,传入SQL框架中的形参

      ps.setObject(1,userName);
      
  6. 执行SQL语句,返回ResultSet结果集

    ResultSet res = ps.executeQuery();
    
  7. 处理结果集查询结果

    if(res.next()){ 
    	loginStatus = true;// 在之前打一个标记:loginStatus = false;
    }
    
  8. 释放资源

    • 关闭JDBC连接通道: conn
    • 释放预处理操作对象: ps
    • 释放结果资源:res

5 执行SQL语句中:executeUpdate()和executeQuery()

executeUpdate()

  • 发生在SQL语句的insert、delete、update
  • 返回值:影响数据库的记录的条数

executeQuery():

  • 发生在SQL语句的select语句中,查询语句
  • 返回值:ResultSet结果集

6 悲观锁 和 乐观锁

  1. 悲观锁:
    • 顾名思义,它总是假设最坏的情况,每次取数据时,其他线程会对数据进行修改,因而加锁(读锁,写锁,行锁)
    • 缺点:会造成阻塞,其他线程会进行排队状态
  2. 乐观锁:
    • 顾名思义,它总是假设最好的情况,数据不会发生并发问题,每次取数据时,其他线程不会对数据进行修改,因此不会上锁。但是,在更新时**,会判断其他线程在这之前有没有对数据进行修改**,一般通过版本号CAS操作实现
  3. 写入操作频繁的时候,使用悲观锁不希望别的线程修改
  4. 读取操作频繁的时候,使用乐观锁不影响其他线程的查询

1、version方式:

一般是在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值会加一。当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若刚才读取到的version值为当前数据库中的version值相等时才更新,否则重试更新操作,直到更新成功。

核心SQL代码:

update table set x=x+1, version=version+1 where id=#{id} and version=#{version};  

2、CAS(定义见后)操作方式:

即compare and swap 或者 compare and set,涉及到三个操作数,数据所在的内存值,预期值,新值。当需要更新时,判断当前内存值与之前取到的值是否相等,若相等,则用新值更新,若失败则重试,一般情况下是一个自旋操作,即不断的重试。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值