mysql常识和jdbc工具类的进化以及连接池思想
Mysql常用版本
| 版本 | 发布年份 | 状态 | 主要特点 |
|---|---|---|---|
| MySQL 5.5 | 2010年 | 已停止官方支持(EOL) | 首个默认InnoDB存储引擎的版本,性能提升 |
| MySQL 5.6 | 2013年 | 即将停止支持 | 优化器改进,全文索引支持InnoDB |
| MySQL 5.7 | 2015年 | 目前最主流的生产版本 | JSON支持,多源复制,性能大幅提升 |
| MySQL 8.0 | 2018年 | 最新稳定版本 | 窗口函数,CTE,角色管理,数据字典重构 |
Mysql5.x 和 Mysql8.0驱动包的区别
<!-- MySQL 5.5, 5.6, 5.7 使用的驱动 -->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.49</version> <!-- 对应5.7的推荐版本 -->
</dependency><!-- 连接URL格式 -->
jdbc:mysql://localhost:3306/database_name<!-- MySQL 8.0+ 使用的驱动(多了一个cj) -->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version> <!-- 8.x版本 -->
</dependency><!-- 实际上,8.0驱动包的全名包含cj -->
<!-- 包名:com.mysql.cj.jdbc.Driver -->驱动类之间的区别
// MySQL 5.x 驱动类
Class.forName("com.mysql.jdbc.Driver");// MySQL 8.0+ 驱动类(多了一个cj)
Class.forName("com.mysql.cj.jdbc.Driver");
// 注意:从8.0开始,可以省略Class.forName()调用
数据库连接池(使用开源的连接池)
连接池概述
总结:
原来:需要自己创建连接和销毁连接,这样是比较消耗时间,资源的
现在:有一些连接池 已经创建好了一些连接 现在可以从连接池中获取到 这样就节省创建时间 直接使用这些连接 归还到连接池中
节省创建连接与释放连接 性能消耗
连接池中连接起到复用的作用 提升程序性能
连接池(池参数,如果不指定,有默认值)
初始大小:10个
* 最小空闲连接数:3个
* 增量:一次创建的最小单位(5个)
* 最大空闲连接数:12个
* 最大连接数:20个
* 最大的等待时间:1000毫秒
- **启动时:**连接池直接创建 10个(初始大小)连接。
- **平时:**池中始终维持至少 3个(最小空闲连接数)空闲连接,但空闲连接最多不超过 12个(最大空闲连接数)。
- **请求高峰:**当请求到来,会优先使用空闲连接。如果连接不够用,且总连接数未到 20个(最大连接数),连接池会以 5个(增量)为单位批量创建新连接。如果总连接数已达 20个,新请求需要排队等待,等待时间最长 1000毫秒(最大的等待时间)。
- **请求低谷:**当连接被归还,如果空闲连接数超过 12个(最大空闲连接数),多出的连接会被关闭,以释放资源,但最终不会低于 3个(最小空闲连接数)。
4个参数:任何的开源的连接池 4大参数都需要自己来设置
驱动的名称: com.mysql.jdbc.Driver (如果是mysql8.0的版本 需要 com.mysql.cj.jdbc.Driver
连接:jdbc:mysql://localhost:3306/数据库
用户名:root
密码:123456
DataSource接口概述
1 DataSource接口 sun公司提供的接口 任何的连接池(开源的,自定义的)必须要实现该接口
2 DataSource接口的方法
Connection getConnection()
开源的连接池已经实现了DataSource接口 通过getConnection()方法就能从连接池中获取到连接
3 连接池
创建连接池的时候 初始化好了一些连接了
用完之后 归还连接
常见的连接池
- DBCP连接池,apache开源组织提供开源连接池对象。
- C3P0连接池,开源的连接池对象。
- DRUID连接池,阿里巴巴提供开源连接池对象
概述:
Druid首先是一个数据库连接池。Druid是目前最好的数据库连接池,在功能、性能、扩展性方面,都超过其
他数据库连接池,包括DBCP、C3P0、BoneCP、Proxool、JBoss DataSource。Druid已经在阿里巴巴部署了
超过600个应用,经过一年多生产环境大规模部署的严苛考验。
功能:
1、替换DBCP和C3P0。Druid提供了一个高效、功能强大、可扩展性好的数据库连接池。最主要使用功能。
2、可以监控数据库访问性能,Druid内置提供了一个功能强大的StatFilter插件,能够详细统计SQL的执行性
能,这对于线上分析数据库访问性能有帮助。
3、数据库密码加密。直接把数据库密码写在配置文件中,这是不好的行为,容易导致安全问题。
DruidDruiver和DruidDataSource都支持PasswordCallback。
4、SQL执行日志,Druid提供了不同的LogFilter,能够支持Common-Logging、Log4j和JdkLog,你可以按需
要选择相应的LogFilter,监控你应用的数据库访问情况。
5、扩展JDBC,如果你要对JDBC层有编程的需求,可以通过Druid提供的Filter机制,很方便编写JDBC层的扩
展插件。
如何使用
1 导入开发的jar包或者依赖
2 直接在代码中写
// 创建连接池对象,从连接池中获取到连接对象
DruidDataSource dataSource = new DruidDataSource();
// 设置4个参数 驱动类 地址 用户名 密码
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///jdbcdemo");
dataSource.setUsername("root");
dataSource.setPassword("root");
// 设置初始化连接个数,默认是0
dataSource.setInitialSize(5);
3. 使用配置文件的方式
// 设置最大连接数
dataSource.setMaxActive(10);
// 最大等待时间,单位是毫秒 2秒
dataSource.setMaxWait(2000);
3 使用配置文件的方式
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///jdbcdemo
username=root
password=root
initialSize=5
maxActive=10
maxWait=3000
maxIdle=6
minIdle=3
JDBC工具类的进化
前提:基础 JDBC 代码(无工具类)
在没有工具类之前,每次操作都充斥着重复代码:
// 1. 注册驱动(可省略)
// 2. 获取连接
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {conn = DriverManager.getConnection(url, username, password);// 3. 执行SQLpstmt = conn.prepareStatement("SELECT * FROM user WHERE id = ?");pstmt.setInt(1, 1);rs = pstmt.executeQuery();// 4. 处理结果集while (rs.next()) {// ... 解析数据}
} catch (SQLException e) {e.printStackTrace();
} finally {// 5. 关闭资源 - 代码非常冗长且容易出错if (rs != null) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } }if (pstmt != null) { try { pstmt.close(); } catch (SQLException e) { e.printStackTrace(); } }if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } }
}
通点:资源获取/释放 异常处理的代码大量重复 业务逻辑不清晰
阶段 1.0:静态方法工具类
目标:封装重复代码,主要是资源的获取和释放。
特点:
- 使用静态代码块加载驱动和初始化连接参数(如
url,username,password)。 - 提供静态方法,如
getConnection(),close(Connection conn, Statement stmt, ResultSet rs)。
public class JdbcUtils1 {// 静态初始化参数(通常从配置文件读取,这里写死)private static String url = "jdbc:mysql://localhost:3306/test";private static String username = "root";private static String password = "123456";// 提供获取连接的方法public static Connection getConnection() {Connection conn = null;try {conn = DriverManager.getConnection(url, username, password);} catch (SQLException e) {e.printStackTrace();}return conn;}// 提供关闭资源的方法(重载)public static void close(Connection conn, Statement stmt, ResultSet rs) {// ... 繁琐的 try-catch 关闭逻辑}public static void close(Connection conn, Statement stmt) {close(conn, stmt, null);}
}#使用方法
Connection conn = JdbcUtils1.getConnection();
// ... 后续操作依然需要自己写
JdbcUtils1.close(conn, stmt, rs);
**优点:**简化了资源关闭的代码。
缺点:
- **连接管理简单:**通常无法管理连接池,只是简单地用
DriverManager获取新连接。 - **事务支持弱:**需要用户自己管理
conn.setAutoCommit(false)和提交/回滚。 - **仍有重复:**用户仍需手动调用
getConnection和close。
阶段 2.0:引入连接池与模板方法模式
**目标:**解决 1.0 的性能问题(连接池)和代码重复问题(模板模式)。
特点:
- **引入连接池:**使用如
C3P0,Druid,HikariCP等数据源,替代DriverManager。 - **使用模板方法模式:**核心是
JdbcTemplate,它封装了所有固定流程(获取连接、创建语句、执行SQL、处理异常、释放资源),用户只需关注可变的业务逻辑(如设置SQL参数、处理结果集)。
示例(模仿 Spring JdbcTemplate 的思想):
public class JdbcTemplate2 {private DataSource dataSource; // 依赖连接池// 核心查询方法public <T> T query(String sql, ResultSetExtractor<T> rse, Object... params) {Connection conn = null;PreparedStatement pstmt = null;ResultSet rs = null;try {// 1. 从连接池获取连接conn = dataSource.getConnection();// 2. 创建语句pstmt = conn.prepareStatement(sql);// 3. 设置参数(可变部分由调用者通过 params 传入)setParameters(pstmt, params);// 4. 执行查询rs = pstmt.executeQuery();// 5. 处理结果集(可变部分由调用者通过 ResultSetExtractor 实现)return rse.extractData(rs);} catch (SQLException e) {// 处理异常throw new RuntimeException(e);} finally {// 6. 释放资源回连接池closeResources(conn, pstmt, rs);}}// ... 类似的 update, execute 等方法
}// 使用方式:用户提供一个处理结果集的回调接口实现
List<User> userList = jdbcTemplate.query("SELECT * FROM user WHERE name = ?",(ResultSet rs) -> { // 使用 Lambda 表达式实现回调List<User> list = new ArrayList<>();while (rs.next()) {User user = new User();user.setId(rs.getInt("id"));user.setName(rs.getString("name"));list.add(user);}return list;},"张三"
);
优点:
- **高性能:**使用连接池。
- **代码极大简化:**用户无需关心资源的开和关,只需关注 SQL 和结果处理。
- **异常处理统一:**将检查异常
SQLException转换为非检查异常RuntimeException,代码更简洁。
缺点:
- **有一定侵入性:**需要学习
JdbcTemplate的 API。 - **ORM 映射仍需手动编写:**需要自己从
ResultSet中提取数据并设置到对象中。
阶段 3.0:声明式事务与强大的 ORM 框架集成
目标:进一步简化数据库操作,特别是管理复杂的事务和实现对象与关系的自动映射。
特点:
- **声明式事务管理:**通过注解(如
@Transactional)来管理事务边界,无需手动编写beginTransaction,commit,rollback。由 Spring 等框架的 AOP(面向切面编程)在背后自动完成。 - **集成 ORM 框架:**如 MyBatis、Hibernate(JPA)。工具类的概念被弱化,核心变成了配置和接口。**MyBatis:**提供
SqlSessionFactory和 Mapper 接口。你定义一个接口,MyBatis 通过动态代理为你生成实现类,将方法调用映射到 SQL Map 文件或注解上的 SQL。**Hibernate/JPA:**完全面向对象。你操作的是实体对象(Entity),框架自动帮你生成 SQL 并执行,几乎看不到 JDBC 的影子。
示例(Spring Data JPA):
// 1. 定义实体类 User,使用 @Entity, @Id 等注解
@Entity
@Table(name = "user")
public class User {@Id@GeneratedValueprivate Long id;private String name;// ... getters and setters
}// 2. 定义仓库接口,继承 JpaRepository(它已经实现了CRUD)
public interface UserRepository extends JpaRepository<User, Long> {// 根据方法名自动生成SQL,无需实现List<User> findByName(String name);
}// 3. 在Service层使用,并声明事务
@Service
public class UserService {@Autowiredprivate UserRepository userRepository;@Transactional // 声明式事务,方法在一个事务中执行public void createUser(String name) {User user = new User();user.setName(name);userRepository.save(user); // 保存对象,而非执行SQL// 如果这里发生异常,事务会自动回滚}
}
优点:
- **开发效率极高:**代码量最少,最符合面向对象思想。
- **强大的事务支持:**声明式事务让复杂的事务管理变得非常简单和清晰。
- **自动化:**ORM 框架处理了大部分枯燥的 CRUD SQL 和对象映射工作。
缺点:
- **复杂度高:**框架本身很复杂,需要深入理解其原理和配置才能优化和排查问题。
- **性能调优:**自动生成的 SQL 可能不是最优的,需要开发者具备一定的调优能力。
- 学习曲线陡峭。
| 特性 | 1.0 静态工具类 | 2.0 模板模式+连接池 | 3.0 声明式事务+ORM |
|---|---|---|---|
| 核心目标 | 封装重复代码 | 解耦固定流程与可变逻辑 | 自动化数据库操作 |
| 连接管理 | DriverManager(简单获取) | 连接池(DataSource) | 连接池(由ORM框架管理) |
| 资源管理 | 手动调用工具类方法关闭 | 自动管理(模板模式) | 完全自动管理 |
| 事务管理 | 手动编程式事务 | 手动编程式事务(可在模板内) | 声明式事务(@Transactional) |
| ORM 映射 | 完全手动 | 手动(通过回调接口) | 自动映射(或通过配置) |
| 代码量 | 较多 | 中等 | 极少 |
| 灵活性 | 高 | 中 | 相对较低(依赖于框架) |
| 学习成本 | 低 | 中 | 高 |
| 典型代表 | 自定义的 JdbcUtils | Spring JdbcTemplate | Spring Data JPA, MyBatis |
