Connection
, Statement
, PreparedStatement
是三个核心接口,分别代表了与数据库的连接、执行SQL语句的基本方式、执行预编译SQL语句的方式。
代表一个数据库连接,是执行SQL语句和获取结果的起点。可以通过这个接口创建Statement
或PreparedStatement
对象,还可以管理事务、设置数据库的只读模式等。
createStatement()
: 创建一个新的Statement
对象。prepareStatement(String sql)
: 创建一个新的PreparedStatement
对象,该对象包含预编译的SQL语句。commit()
: 提交当前事务。rollback()
: 回滚当前事务。setAutoCommit(boolean autoCommit)
: 设置自动提交模式。用于执行简单的SQL语句,每次执行时都需要将SQL语句发送给数据库进行编译和执行。Statement
对象本身没有参数化的功能,所以直接执行SQL语句可能存在SQL注入的风险。
executeQuery(String sql)
: 执行SQL查询操作,并返回ResultSet
对象。executeUpdate(String sql)
: 执行SQL更新(INSERT、UPDATE或DELETE),并返回受影响的行数。execute(String sql)
: 执行SQL语句,该语句可能返回多个结果。继承自Statement
接口,表示预编译的SQL语句,可以包含输入参数,并且可以被多次执行。PreparedStatement
对象在执行时不需要重新编译SQL语句,因此性能通常优于Statement
。此外,由于PreparedStatement
使用参数化查询,所以它可以有效防止SQL注入攻击。
setXXX(int parameterIndex, XXX value)
: 设置指定参数的值,其中XXX
是数据类型,如Int
, String
, Date
等。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); //第二个参数值是整数类型
在Java代码中,虽然不需要直接处理这些步骤,但是了解这些步骤有助于更好地理解和优化SQL语句的性能。例如,可以通过编写更有效的SQL语句、创建合适的索引、使用连接池等方式来提高数据库操作的性能。
在Java中使用JDBC与MySQL数据库建立连接后,对于发送到MySQL服务端的SQL语句,MySQL会执行一系列的操作:
接收SQL语句:
MySQL服务器通过网络接口(通常是TCP/IP或Unix套接字)接收来自客户端(在这个情况下是JDBC驱动)的SQL语句。
解析SQL语句:
MySQL的解析器会对接收到的SQL语句进行词法和语法分析,检查SQL语句的语法正确性,并将其转换成抽象语法树(AST)。
预处理:
在解析之后,MySQL会进行预处理,包括检查语句中的表名和列名是否存在,用户是否有执行该语句的权限等。
优化SQL语句:
MySQL的查询优化器会对SQL语句进行优化,选择最有效的执行计划。优化可能包括重写查询、选择不同的索引、决定连接表的顺序等。
执行SQL语句:
根据优化器选择的执行计划,MySQL开始执行SQL语句。对于查询(SELECT),MySQL会读取表中的数据,执行连接、过滤、排序等操作,并生成结果集。对于更新(INSERT、UPDATE、DELETE),MySQL会修改表中的数据。
返回结果:
对于查询语句,MySQL将结果集返回给客户端。对于更新语句,MySQL返回受影响的行数。
关闭游标和释放资源:
在客户端处理完结果集之后,应该关闭结果集和相关的游标,并释放服务器上的资源。这通常是通过客户端发送关闭命令来完成的。
此外,MySQL服务器还会处理并发控制、事务管理、错误处理等方面的工作,确保数据的一致性和完整性。这些方面的处理对于开发可靠的数据库应用程序至关重要。
Connection池是一个集合,存储的是Connection对象,是依赖于数据库驱动程序来创建和管理数据库连接的。
主要是为了重用Connection对象,而不是每次需要数据库连接时都创建新的Connection对象。当程序需要使用数据库连接时,它会从连接池中获取一个已经存在的Connection对象。当使用完这个Connection后,它不会被关闭,而是被“归还”给连接池,以便其他程序可以重用。
这种方式显著地提高了数据库连接的使用效率,因为创建数据库连接通常需要消耗相对较大的资源,并且创建时间也可能较长。通过使用连接池,可以避免这种开销,从而提高程序的性能。
此外,连接池还可以管理Connection
对象的生命周期,包括创建、使用和释放等。这样可以确保连接的正确使用和及时释放,有效地减少资源浪费,提高数据库连接的性能和稳定性。
Druid是一个高性能的Java数据库连接池,可以直接添加Druid的依赖并使用。
在JDBC的数据库连接池的基础上提供了更多高级功能,如用缓存提高连接获取的速度、连接状态监控、慢SQL日志记录、连接泄露检测、提供插件机制等,提高了性能和扩展性。
连接池使用工厂模式来创建和管理连接对象。工厂模式是一种创建型设计模式,它提供了一种创建对象的最佳方式。通过工厂方法代替new操作来创建实例化对象。工厂模式的主要目的是将对象的创建与使用分离,降低耦合度,提高系统的可扩展性和可维护性。
工厂模式常用于创建具有复杂初始化逻辑的对象,或者需要根据不同条件创建不同类型对象的场景。例如,创建数据库连接、线程池、缓存等对象。
使用工厂模式,可以将对象的创建过程封装起来,不需要知道具体是如何创建对象的,只需要调用工厂类的方法来获取所需的对象,可以减少重复代码,提高代码的可读性和可维护性。
同时,工厂模式也提供了更好的可扩展性,当需要添加新的产品对象时,只需要增加相应的工厂类和产品类,而不需要修改已有的代码。
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();
}
ORM(Object-Relational Mapping)框架是一种在面向对象编程语言和关系型数据库之间充当“翻译”的框架。它允许开发者使用面向对象的思维来操作数据库,而无需关心底层的SQL语句和数据库结构。
ORM框架通过元数据(通常使用XML或注解形式)描述对象与关系映射的细节。这些元数据定义了如何将对象的状态映射到数据库表中,以及如何将数据库查询结果映射回对象。一旦提供了持久化类与表的映射关系,ORM框架在运行时就能参照映射文件的信息,把对象持久化到数据库中。
当使用
#{}
占位符时,MyBatis 在执行 SQL 语句之前会进行预处理,将#{}
占位符替换为JDBC的?
占位符,并且会安全地设置参数值。这个过程是自动的,MyBatis 负责处理这些细节,以确保 SQL 语句的安全性和效率。
举例:MyBatis的映射文件:
当调用这个映射语句时,MyBatis 会做以下几步:
#{}
占位符。#{}
占位符生成一个对应的 JDBC?
占位符。PreparedStatement
准备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
,并返回结果集。