Mybatis基础知识小结
# Mybatis 基础知识小结
# 说说什么是 Mybatis 吧
MyBatis 是一种优秀的持久层框架,它是一个基于 Java 的 半ORM(对象关系映射)
框架,可以使用简单的 XML 或注解配置来映射原始类型、Map 和 Java 对象(POJO)到数据库表中的记录。
MyBatis 支持自定义 SQL
、存储过程和高级映射,可以将复杂的 JDBC 代码封装起来,使开发者只需要关注 SQL
语句的编写和映射关系的配置,从而大大简化了数据库访问的开发工作。
MyBatis 的主要优点包括:易于使用、灵活性强、可以自定义 SQL
、支持多种数据库、性能优秀等。
缺点是:对于复杂的 SQL
还是需要自己手动编写,这就对码农的 SQL 功底有着较高的要求了,而且它的 SQL
语句非常依赖数据库,这就使得可能这个数据库可以用的 SQL
换一个数据库就不行了。
# 你刚刚说了 ORM 框架,能不能告诉我什么是 ORM?为什么说 Mybatis 是半自动的 ORM 框架呢?
ORM
说白了就是建立数据库字段和 Java对象(POJO)
的一种映射关系技术,
而 Mybatis
由于建立这种映射需要我们手动编写 SQL
, 所以说它是半自动的。
# 我们已经有 JDBC 了,为什么需要 Mybatis 呢?
因为 JDBC
有下面几个缺点:
- 建立连接麻烦。
SQL
写在代码里面不好维护。- 传参也很麻烦。
- 处理结果也很麻烦。
一句话就是,JDBC
使用起来麻烦,不如 Mybatis
方便。
# #{} 和 ${} 的区别是什么?
在 MyBatis 中,$
和 #
是两种不同类型的占位符,用于在 SQL 语句中引用参数或表达式,但它们的行为有一些重要区别:
$
占位符(String Substitution):$
用于字符串替换,直接将参数的值嵌入 SQL 语句中,不使用预编译机制。$
不提供参数安全性,可能会导致 SQL 注入风险。- 通常在需要动态生成列名、表名等情况下使用
$
。 - 例如,
select * from ${tableName}
中${tableName}
会被替换成实际的表名。
#
占位符(Parameterized):#
用于预编译参数,会将参数值传递给数据库的预编译语句,提供参数安全性。#
通常在查询条件、插入、更新或删除操作时使用。- 例如,
select * from table where column = #{value}
中#{value}
会被替换成参数值,并使用预编译机制传递给数据库。
# Hibernate 和 MyBatis 的区别是什么?
Hibernate 和 MyBatis 都是 Java 中常用的 ORM(Object-Relational Mapping)框架,用于将 Java 对象映射到数据库表中。
虽然它们都可以用于实现数据库访问,但是它们有一些区别:
- 映射方式不同:
- Hibernate 是一种全自动 ORM 框架,它使用 Java 对象映射到数据库表,
- 而 MyBatis 则是一种半自动 ORM 框架,它使用 SQL 映射文件来指定如何将 Java 对象映射到数据库表。
- 性能不同:
- MyBatis 的性能通常比 Hibernate 更好,因为它可以更好地控制 SQL 语句的生成和执行,可以更好地优化 SQL 语句。
- 而 Hibernate 对 SQL 的生成和优化是自动的,可能会导致性能问题。
- 配置方式不同:
- Hibernate 配置相对比较复杂,需要编写映射文件和配置文件,
- 而 MyBatis 配置相对简单,只需要编写 SQL 映射文件和配置文件即可。
- 支持的数据库不同:
- Hibernate 支持多种数据库,包括 MySQL、Oracle、SQL Server 等,
- 而 MyBatis 对数据库的支持相对较少,主要支持 MySQL、Oracle、SQL Server、PostgreSQL 等常用数据库。
- 对象关系维护不同:
- Hibernate 可以自动维护对象之间的关系,包括一对一、一对多、多对多等关系,
- 而 MyBatis 不支持自动维护对象之间的关系,需要手动编写 SQL 语句来实现。
综合来说:
- 如果需要快速开发,可以选择 Hibernate,
- 如果需要更好的性能和更灵活的 SQL 控制,可以选择 MyBatis。
# xml 映射文件中,除了常见的 select、insert、update、delete 标签之外,还有哪些标签?
还有很多其他的标签,<resultMap>
、<parameterMap>
、<sql>
、<include>
、<selectKey>
,
加上动态 sql 的 9 个标签,trim|where|set|foreach|if|choose|when|otherwise|bind
等,
- 其中
<sql>
为 sql 片段标签,通过<include>
标签引入 sql 片段, <selectKey>
是不支持【自增的主键生成策略】标签。
# Dao 接口的工作原理是什么?
在最佳实践中,通常一个 xml
映射文件,都会写一个 Dao 接口与之对应。( xml
<--> Mapper
)
Dao 接口就是人们常说的 Mapper
接口。
- 接口的全限名,就是映射文件中的
namespace
的值, - 接口的方法名,就是映射文件中
MappedStatement
的 id 值, - 接口方法内的参数,就是传递给 sql 的参数。
Mapper
接口是没有实现类的,当调用接口方法时,【接口全限名 + 方法名】拼接字符串作为 key 值,可唯一定位一个 MappedStatement
,
举例:com.mybatis3.mappers.StudentDao.findStudentById
,可以唯一找到 namespace 为 com.mybatis3.mappers.StudentDao
下面 id = findStudentById
的 MappedStatement
。
在 MyBatis 中,每一个 <select>
、<insert>
、<update>
、<delete>
标签,都会被解析为一个 MappedStatement
对象。
# Dao 接口里的方法,参数不同时,方法能重载吗?
Dao 接口里的方法可以重载,但是 Mybatis 的 xml 里面的 ID 不允许重复。
还需要满足两个条件:
- 仅有一个无参方法和一个有参方法。
- 多个有参方法时,参数数量必须一致。且使用相同的
@Param
注解,或者使用param1
这种。
注意:Mybatis 的 Dao 接口可以有多个重载方法,但是多个接口对应的映射必须只有一个,否则启动会报错。
# 为什么要用 Mybatis 而不直接用 sql
使用 MyBatis 而不直接使用 SQL 有以下几个优势:
- SQL 与 Java 代码分离: MyBatis 将 SQL 语句与 Java 代码分离,将 SQL 配置在 XML 文件中或使用注解方式,使得代码更加清晰、易读和易维护。这样也使得 SQL 可以与 Java 代码进行解耦,方便数据库查询逻辑的修改和优化,而无需修改 Java 代码。
- 参数处理和防止 SQL 注入: MyBatis 提供了参数处理机制,可以将 Java 对象映射到 SQL 参数,有效防止 SQL 注入攻击。同时,MyBatis 也会自动处理参数转义,避免了手动拼接 SQL 语句造成的安全风险。
- 数据库连接管理: MyBatis 管理了数据库连接的生命周期,确保在需要时打开和关闭连接,有效地提高了数据库资源的利用率和系统性能。
- 数据库结果集映射: MyBatis 提供了灵活的结果集映射机制,可以将查询结果直接映射为 Java 对象,使得查询结果的处理更加方便和直观。
- 缓存管理: MyBatis 支持缓存机制,可以缓存查询结果,避免频繁访问数据库,从而提高系统性能。
- 数据库移植性: 使用 MyBatis 可以实现数据库移植性,即通过修改 MyBatis 的配置,可以方便地切换不同的数据库,而无需修改大量的 SQL 语句。
综上所述,使用 MyBatis 可以简化数据库访问的过程,提高代码的可维护性和安全性,并提供更多功能和便利性,使得数据库操作更加优雅和高效。
# Mybatis 一二级缓存
MyBatis 提供了一级缓存和二级缓存来提高数据库访问性能和减少重复查询的次数。
- 一级缓存:
- 一级缓存是 MyBatis 默认开启的缓存机制,它是在 SqlSession 级别的缓存(本地缓存),也就是说在同一个 SqlSession 中,查询的结果会被缓存起来。
- 当执行同一个 SqlSession 的相同 SQL 查询时,如果一级缓存中已经存在查询结果,则直接从缓存中返回结果,而不需要再去数据库查询,这样可以减少数据库的访问次数,提高查询性能。
- 一级缓存是一个本地缓存,它的作用范围是相对狭窄的,只在当前的 SqlSession 内有效,当 SqlSession 关闭时,缓存也会被清空。
- 二级缓存:
- 二级缓存是在 Mapper 级别的缓存,也称为全局缓存。可以被多个 SqlSession 共享。
- 当执行查询时,如果查询结果在二级缓存中存在,则直接从缓存中返回结果,而不需要再去数据库查询。
- 二级缓存是一个全局缓存,它可以跨越多个 SqlSession,适用于多个 SqlSession 共享查询结果的场景。
- 使用二级缓存需要在 MyBatis 配置文件中进行配置,可以选择使用默认的缓存实现或自定义缓存实现。
需要注意的是,虽然缓存可以提高性能,但也会带来一致性的问题。当数据库中的数据发生变化时(比如更新、插入、删除操作),缓存中的数据可能会变得过时,这就需要考虑如何合理地处理缓存的刷新策略,以保证数据的一致性。
因此,在使用 MyBatis 的缓存时,需要根据具体的业务场景和需求,灵活地选择是否开启缓存,以及采用合适的缓存策略,以达到最佳的性能和数据一致性。
# 讲讲 SqLSession
SqlSession
是 MyBatis 中的一个核心接口,它提供了对数据库的操作方法,允许应用程序与数据库进行交互。
SqlSession
是在 MyBatis 的配置文件中通过 SqlSessionFactory
创建的,每个线程通常会有一个独立的 SqlSession
实例,用于执行数据库操作。
SqlSession
接口中定义了许多方法,其中一些重要的方法包括:
- selectOne(String statement, Object parameter): 执行查询操作,返回单个结果对象。
- selectList(String statement, Object parameter): 执行查询操作,返回多个结果对象组成的 List。
- insert(String statement, Object parameter): 执行插入操作,将参数对象插入到数据库中。
- update(String statement, Object parameter): 执行更新操作,更新数据库中的记录。
- delete(String statement, Object parameter): 执行删除操作,删除数据库中的记录。
- commit(): 提交事务。
- rollback(): 回滚事务。
- close(): 关闭
SqlSession
实例。
SqlSession
提供了对数据库的各种操作,通过执行 SQL 语句实现了数据的增删改查功能。在执行 SQL 语句时,SqlSession
会通过 Mapper
接口(或 XML 映射文件)找到对应的 SQL 语句,并将传入的参数映射到 SQL 中执行。
通常情况下,一个 SqlSession
实例对应一个数据库事务,事务的提交和回滚可以通过调用 commit()
和 rollback()
方法实现。一般情况下,我们会在一个业务逻辑方法中创建一个 SqlSession
实例,在该方法中执行数据库操作,然后提交或回滚事务,并最终关闭 SqlSession
。
注意:由于 SqlSession
是非线程安全的,因此应该避免将它作为类成员变量或共享变量使用,而是应该在需要的时候创建新的实例,并在使用完毕后及时关闭。
# 那 Mapper 呢?
Mapper
是 MyBatis 中用于定义数据访问接口的一种机制。
它通过 Java 接口的方式来描述数据库操作,包含了对数据库的增删改查等操作方法的定义,但不包含具体的 SQL 语句。具体的 SQL 语句是在对应的 XML 映射文件中实现的。