1.说说Mybatis的缓存机制:
MyBatis 是一个优秀的持久层框架,它简化了企业应用开发中数据库操作的代码。MyBatis 提供了一级缓存和二级缓存机制来优化对数据库的访问。
一级缓存 (SqlSession级别的缓存)
一级缓存是 MyBatis 中默认开启且无法关闭的缓存机制。它存在于 SqlSession 的生命周期内,当同一个 SqlSession 实例执行相同的查询语句时,MyBatis 会首先检查一级缓存中是否已经有结果存在。如果有,则直接返回缓存中的数据,不再发起数据库查询;如果没有,则查询数据库并将结果存入缓存中。
一级缓存的生命周期与 SqlSession 绑定,因此在以下情况下,一级缓存会被清空:
- 提交或回滚事务后;
- 执行任何更新、插入或删除操作后;
- 手动调用 clearCache() 方法;
- 当 SqlSession 关闭时。
二级缓存 (Mapper级别的缓存)
二级缓存可以跨多个 SqlSession 使用,并且可以在不同的 SqlSession 之间共享。它通常应用于多个用户可能会查询相同的数据的情况。要启用二级缓存,需要做如下配置:
-
在核心配置文件(如 mybatis-config.xml)中设置 来全局开启二级缓存。
-
在具体的 Mapper XML 文件中添加 或者更复杂的 配置来为特定的命名空间开启缓存。
使用二级缓存需要注意的问题包括但不限于:
- 确保实体类是可序列化的,因为缓存对象可能被序列化到磁盘或者分布式缓存系统中。
- 不能对频繁更新的数据使用二级缓存,否则会导致脏读问题。
- 注意并发情况下的缓存一致性问题。
自定义缓存
MyBatis 还允许开发者通过实现自己的缓存接口来自定义缓存策略。你可以通过继承 Cache 接口创建自定义缓存,并将其集成到 MyBatis 的缓存架构中。
总的来说,合理地利用 MyBatis 的缓存机制可以显著提高应用程序的性能,但同时也需要考虑到缓存带来的潜在问题,如数据的一致性和时效性等。
2.JDBC 编程有哪些步骤?
JDBC(Java Database Connectivity)编程是Java应用程序连接和操作数据库的标准方法。以下是使用JDBC进行编程的基本步骤:
-
加载JDBC驱动:
- 早期的JDBC版本需要显式地使用 Class.forName() 方法来加载特定数据库的JDBC驱动程序类。
- 从JDBC 4.0开始,只要JDBC驱动在类路径中,DriverManager 将自动加载它,因此不再需要显式调用 Class.forName()。
-
获取数据库连接:
- 使用 DriverManager.getConnection() 方法提供数据库URL、用户名和密码来建立与数据库的连接。
- 或者使用 DataSource 接口提供的方法来获取连接,这通常用于企业级应用中,因为 DataSource 支持连接池等高级特性。
-
创建Statement对象:
- 使用 Connection.createStatement() 创建一个 Statement 对象用于执行SQL语句。
- 或者使用 Connection.prepareStatement() 来创建一个预编译的 PreparedStatement 对象,以提高性能并防止SQL注入攻击。
- 如果需要调用存储过程,则可以使用 Connection.prepareCall() 创建 CallableStatement 对象。
-
执行SQL语句:
- 对于查询操作,使用 Statement.executeQuery() 执行SQL SELECT语句,并返回一个 ResultSet 对象。
- 对于更新操作(如INSERT, UPDATE, DELETE),使用 Statement.executeUpdate() 执行这些语句,该方法返回受影响的行数。
-
处理结果集(仅适用于查询):
- 使用 ResultSet 的各种 getXXX() 方法来遍历结果集并提取数据。
- 注意要正确处理 ResultSet 中的数据类型转换。
-
清理资源:
- 关闭 ResultSet, Statement 和 Connection 等资源非常重要。未关闭的资源可能会导致内存泄漏或数据库连接耗尽。
- 最好是在finally块中或者使用try-with-resources语句(Java 7及以上)来确保即使发生异常也能正确关闭资源。
示例代码片段如下:
try (Connection conn = DriverManager.getConnection(dbUrl, user, password);Statement stmt = conn.createStatement();ResultSet rs = stmt.executeQuery("SELECT id, name FROM users")) {while (rs.next()) {// Process each row of the result set.int id = rs.getInt("id");String name = rs.getString("name");System.out.println("ID: " + id + ", Name: " + name);}
} catch (SQLException e) {e.printStackTrace();
}
这段代码展示了如何使用 try-with-resources 自动管理资源关闭,并且执行了一个简单的查询操作。
3. MyBatis 中见过什么设计模式?
MyBatis 框架中使用了多种设计模式,以提高代码的可维护性、可扩展性和灵活性。以下是 MyBatis 中常见的一些设计模式:
1. 工厂模式 (Factory Pattern)
MyBatis 使用工厂模式来创建 SqlSessionFactory。SqlSessionFactoryBuilder 根据配置信息(XML 或 Java 配置)构建 SqlSessionFactory 实例。SqlSessionFactory 负责创建 SqlSession 对象,而 SqlSession 是执行数据库操作的主要入口。
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
try (SqlSession session = sqlSessionFactory.openSession()) {// Use the session to execute SQL statements.
}
2. 代理模式 (Proxy Pattern)
MyBatis 利用 JDK 动态代理或 CGLIB 创建 Mapper 接口的代理实例。这些代理对象拦截方法调用,并将它们转换为对底层 JDBC API 的调用,从而隐藏了数据访问层的实现细节。
UserMapper mapper = session.getMapper(UserMapper.class);
List<User> users = mapper.selectAllUsers();
3. 建造者模式 (Builder Pattern)
SqlSessionFactory 的创建过程通过 SqlSessionFactoryBuilder 来完成,它根据不同的配置选项逐步构建出最终的对象。建造者模式使得可以灵活地创建复杂的对象而不必使用大量的构造函数参数。
4. 模板方法模式 (Template Method Pattern)
在 MyBatis 内部,对于 CRUD 操作的流程有一个大致固定的步骤:创建连接 -> 创建语句 -> 执行语句 -> 处理结果 -> 关闭资源。这个流程由框架提供,用户只需要定义具体的 SQL 和映射规则,这正是模板方法模式的应用。
5. 单例模式 (Singleton Pattern)
SqlSessionFactory 通常在整个应用程序生命周期内只被创建一次,并且可以被多个线程安全地共享和重用。因此,它通常被设计成单例模式。
6. 适配器模式 (Adapter Pattern)
MyBatis 的类型处理器(TypeHandler)用于在 JDBC 类型和 Java 类型之间进行转换,起到了适配器的作用,使得不同类型的对象能够兼容工作。
7. 策略模式 (Strategy Pattern)
当涉及到查询缓存时,MyBatis 允许用户选择不同的缓存实现(如一级缓存、二级缓存等),并且可以通过插件机制添加自定义的缓存策略,这体现了策略模式的思想。
这些设计模式共同作用,使得 MyBatis 成为了一个高效、灵活且易于使用的持久层框架。
4.MyBatis 中比如 UserMapper.java 是接口,为什么没有实现类还能调用?
在 MyBatis 中,UserMapper.java 是一个接口,而不需要提供实现类的原因是因为 MyBatis 使用了 动态代理 的机制。具体来说,MyBatis 利用 Java 的反射和动态代理功能(如 JDK 动态代理或 CGLIB)来为这些接口创建代理实例。当你调用 session.getMapper(UserMapper.class) 时,MyBatis 会根据你提供的 Mapper 接口生成一个代理对象。
这个代理对象能够拦截你对 Mapper 接口中定义的方法的调用,并将它们转换成相应的 SQL 操作。例如,如果你有一个方法 List<User> selectAllUsers();,那么 MyBatis 会查找与之对应的 XML 映射文件中的 <select> 标签或者注解配置,并执行该标签内定义的 SQL 语句,然后将结果集映射到返回的对象中。
下面是 MyBatis 如何做到这一点的大致流程:
- 配置映射信息:你需要通过 XML 文件(如 UserMapper.xml)或者注解的方式为接口中的每个方法指定相应的 SQL 语句。
- 获取 Mapper 实例:使用 SqlSession 提供的 getMapper(Class type) 方法传入你的 Mapper 接口类型,MyBatis 会为你创建一个代理实例。
- 代理方法调用:当你调用代理实例上的方法时,实际是触发了 MyBatis 内部逻辑去解析并执行对应的 SQL 语句。
- 执行 SQL 和处理结果:MyBatis 使用底层的 JDBC 连接执行 SQL 语句,并将结果集映射到 Java 对象,最后返回给调用者。
由于这一切都是在运行时由 MyBatis 自动完成的,所以开发者无需编写具体的实现类。这种方式不仅简化了代码,还提高了灵活性,因为你可以轻松地更改 SQL 语句而不必修改业务逻辑代码。此外,它也遵循了面向接口编程的最佳实践,有助于提高代码的可测试性和可维护性。