JDBC与MyBatis(二)

1、JDBC的核心API

Connection,  Statement, PreparedStatement 是三个核心接口,分别代表了与数据库的连接、执行SQL语句的基本方式、执行预编译SQL语句的方式。

1)Connection接口

代表一个数据库连接,是执行SQL语句和获取结果的起点。可以通过这个接口创建StatementPreparedStatement对象,还可以管理事务、设置数据库的只读模式等。

  • createStatement(): 创建一个新的Statement对象。
  • prepareStatement(String sql): 创建一个新的PreparedStatement对象,该对象包含预编译的SQL语句。
  • commit(): 提交当前事务。
  • rollback(): 回滚当前事务。
  • setAutoCommit(boolean autoCommit): 设置自动提交模式。

2)Statement接口

用于执行简单的SQL语句,每次执行时都需要将SQL语句发送给数据库进行编译和执行。Statement对象本身没有参数化的功能,所以直接执行SQL语句可能存在SQL注入的风险。

  • executeQuery(String sql): 执行SQL查询操作,并返回ResultSet对象。
  • executeUpdate(String sql): 执行SQL更新(INSERT、UPDATE或DELETE),并返回受影响的行数。
  • execute(String sql): 执行SQL语句,该语句可能返回多个结果。

3)PreparedStatement接口

继承自Statement接口,表示预编译的SQL语句,可以包含输入参数,并且可以被多次执行。PreparedStatement对象在执行时不需要重新编译SQL语句,因此性能通常优于Statement。此外,由于PreparedStatement使用参数化查询,所以它可以有效防止SQL注入攻击。

  • setXXX(int parameterIndex, XXX value): 设置指定参数的值,其中XXX是数据类型,如IntStringDate等。
  • executeQuery(): 执行查询,并返回ResultSet对象。
  • executeUpdate(): 执行更新,并返回受影响的行数。

预编译的SQL语句

指数据库在执行SQL语句之前先对其进行编译,并将编译后的结果存储起来。当相同的SQL语句再次被执行时,数据库可以直接使用之前编译的结果,而不必重新编译整个语句。这可以提高执行效率,特别是在需要多次执行相同或类似SQL语句的情况下。

参数化查询

参数化查询是预编译SQL语句的一种实现方式。它允许开发者在SQL语句中使用占位符(问号?)代替数据值,然后在执行SQL语句之前或执行时提供这些数据的实际值(使用set方法设置值)。优势:

  • 防止SQL注入:由于数据值被当作参数传递,而不是直接嵌入到SQL语句中,因此可以防止恶意用户通过输入特殊字符或语句来注入恶意代码。

  • 提高性能:预编译的SQL语句可以被数据库缓存,当再次执行相同的查询时,数据库可以直接使用之前编译好的查询计划,而不需要重新解析和编译SQL语句。

  • 类型安全:参数化查询通常要求开发者提供参数的数据类型,这有助于确保数据类型的正确性,并减少类型转换错误。

  • 减少网络流量:由于SQL语句本身不需要多次发送,只需要发送参数值,因此可以减少网络传输的数据量。​​​​​​​

Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydatabase", "username", "password");

PreparedStatement pstmt = conn.prepareStatement("INSERT INTO mytable (name, age) VALUES (?, ?)");

pstmt.setString(1, "Penny"); //第一个参数是字符串类型 
pstmt.setInt(2, 2);         //第二个参数值是整数类型  

2、建立连接后MySQL对SQL语句的操作步骤

在Java代码中,虽然不需要直接处理这些步骤,但是了解这些步骤有助于更好地理解和优化SQL语句的性能。例如,可以通过编写更有效的SQL语句、创建合适的索引、使用连接池等方式来提高数据库操作的性能。

在Java中使用JDBC与MySQL数据库建立连接后,对于发送到MySQL服务端的SQL语句,MySQL会执行一系列的操作:

  1. 接收SQL语句
    MySQL服务器通过网络接口(通常是TCP/IP或Unix套接字)接收来自客户端(在这个情况下是JDBC驱动)的SQL语句。

  2. 解析SQL语句
    MySQL的解析器会对接收到的SQL语句进行词法和语法分析,检查SQL语句的语法正确性,并将其转换成抽象语法树(AST)。

  3. 预处理
    在解析之后,MySQL会进行预处理,包括检查语句中的表名和列名是否存在,用户是否有执行该语句的权限等。

  4. 优化SQL语句
    MySQL的查询优化器会对SQL语句进行优化,选择最有效的执行计划。优化可能包括重写查询、选择不同的索引、决定连接表的顺序等。

  5. 执行SQL语句
    根据优化器选择的执行计划,MySQL开始执行SQL语句。对于查询(SELECT),MySQL会读取表中的数据,执行连接、过滤、排序等操作,并生成结果集。对于更新(INSERT、UPDATE、DELETE),MySQL会修改表中的数据。

  6. 返回结果
    对于查询语句,MySQL将结果集返回给客户端。对于更新语句,MySQL返回受影响的行数。

  7. 关闭游标和释放资源
    在客户端处理完结果集之后,应该关闭结果集和相关的游标,并释放服务器上的资源。这通常是通过客户端发送关闭命令来完成的。

此外,MySQL服务器还会处理并发控制、事务管理、错误处理等方面的工作,确保数据的一致性和完整性。这些方面的处理对于开发可靠的数据库应用程序至关重要。

3、数据库连接(Connection)池

1)JDBC的连接池功能

Connection池是一个集合,存储的是Connection对象,是依赖于数据库驱动程序来创建和管理数据库连接的。

主要是为了重用Connection对象,而不是每次需要数据库连接时都创建新的Connection对象。当程序需要使用数据库连接时,它会从连接池中获取一个已经存在的Connection对象。当使用完这个Connection后,它不会被关闭,而是被“归还”给连接池,以便其他程序可以重用。

这种方式显著地提高了数据库连接的使用效率,因为创建数据库连接通常需要消耗相对较大的资源,并且创建时间也可能较长。通过使用连接池,可以避免这种开销,从而提高程序的性能。

此外,连接池还可以管理Connection对象的生命周期,包括创建、使用和释放等。这样可以确保连接的正确使用和及时释放,有效地减少资源浪费,提高数据库连接的性能和稳定性。

2)Druid

Druid是一个高性能的Java数据库连接池,可以直接添加Druid的依赖并使用。

在JDBC的数据库连接池的基础上提供了更多高级功能,如用缓存提高连接获取的速度、连接状态监控、慢SQL日志记录、连接泄露检测、提供插件机制等,提高了性能和扩展性。

3)使用了工厂模式的设计思想

连接池使用工厂模式来创建和管理连接对象。工厂模式是一种创建型设计模式,它提供了一种创建对象的最佳方式。通过工厂方法代替new操作来创建实例化对象。工厂模式的主要目的是将对象的创建与使用分离,降低耦合度,提高系统的可扩展性和可维护性。

工厂模式常用于创建具有复杂初始化逻辑的对象,或者需要根据不同条件创建不同类型对象的场景。例如,创建数据库连接、线程池、缓存等对象。

使用工厂模式,可以将对象的创建过程封装起来,不需要知道具体是如何创建对象的,只需要调用工厂类的方法来获取所需的对象,可以减少重复代码,提高代码的可读性和可维护性。

同时,工厂模式也提供了更好的可扩展性,当需要添加新的产品对象时,只需要增加相应的工厂类和产品类,而不需要修改已有的代码。

4)在JDBC中使用Druild举例

public void testSelectAll() throws Exception {
    //1. 获取Connection
    //3. 加载配置文件
    Properties prop = new Properties();
    prop.load(new FileInputStream("jdbc-demo/src/druid.properties"));
    //4. 获取连接池对象
    DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);

    //5. 获取数据库连接 Connection
    Connection conn = dataSource.getConnection();
    //2. 定义SQL
    String sql = "select * from tb_brand;";
    //3. 获取pstmt对象
    PreparedStatement pstmt = conn.prepareStatement(sql);
    //4. 设置参数
    //5. 执行SQL
    ResultSet rs = pstmt.executeQuery();
    //6. 处理结果 List 封装Brand对象,装载List集合
    Brand brand = null;
    List brands = new ArrayList<>();
    while (rs.next()){
        //获取数据
        int id = rs.getInt("id");
        String brandName = rs.getString("brand_name");
        String companyName = rs.getString("company_name");
        int ordered = rs.getInt("ordered");
        String description = rs.getString("description");
        int status = rs.getInt("status");
        //封装Brand对象
        brand = new Brand();
        brand.setId(id);
        brand.setBrandName(brandName);
        brand.setCompanyName(companyName);
        brand.setOrdered(ordered);
        brand.setDescription(description);
        brand.setStatus(status);

        //装载集合
        brands.add(brand);
    }
    System.out.println(brands);
    //7. 释放资源
    rs.close();
    pstmt.close();
    conn.close();
}

4、MyBatis是一个ORM框架

ORM(Object-Relational Mapping)框架是一种在面向对象编程语言和关系型数据库之间充当“翻译”的框架。它允许开发者使用面向对象的思维来操作数据库,而无需关心底层的SQL语句和数据库结构。

ORM框架通过元数据(通常使用XML或注解形式)描述对象与关系映射的细节。这些元数据定义了如何将对象的状态映射到数据库表中,以及如何将数据库查询结果映射回对象。一旦提供了持久化类与表的映射关系,ORM框架在运行时就能参照映射文件的信息,把对象持久化到数据库中。

5、MyBatis对PreparedStatement的参数化查询的封装

当使用#{}占位符时,MyBatis 在执行 SQL 语句之前会进行预处理,将#{}占位符替换为JDBC的?占位符,并且会安全地设置参数值。这个过程是自动的,MyBatis 负责处理这些细节,以确保 SQL 语句的安全性和效率。

举例:MyBatis的映射文件:

当调用这个映射语句时,MyBatis 会做以下几步:

  1. 解析 SQL 语句,识别出 #{} 占位符。
  2. 为每一个 #{} 占位符生成一个对应的 JDBC?占位符。
  3. 使用PreparedStatement准备SQL语句,并将?占位符替换为实际的参数值。
  4. 执行SQL语句并处理结果。

这个过程在内部由 MyBatis 处理,不需要手动设置PreparedStatement的参数。MyBatis 会根据提供的参数值,按照正确的类型和顺序设置这些占位符的值。在运行时,MyBatis会创建一个PreparedStatement,类似于下面的 JDBC 代码:

String sql = "SELECT * FROM users WHERE id = ?";  
PreparedStatement ps = connection.prepareStatement(sql);  
ps.setInt(1, userId); // 假设 userId 是你要查询的用户的 ID  
ResultSet rs = ps.executeQuery();

在这个例子中,MyBatis会自动将#{userId}替换为?,并且使用ps.setInt(1, userId)设置参数值。然后,数据库驱动程序会执行这个带有实际参数值的PreparedStatement,并返回结果集。

你可能感兴趣的:(JDBC,mybatis,数据库,mysql,sql,oracle)