1
0
mirror of https://github.com/Snailclimb/JavaGuide synced 2025-06-25 02:27:10 +08:00
This commit is contained in:
guide 2020-10-08 14:58:20 +08:00
commit 77b89d69bd
4 changed files with 59 additions and 48 deletions

View File

@ -2,9 +2,9 @@
JAVA 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为 java 语言的反射机制。
### 获取 Class 对象的种方式
### 获取 Class 对象的种方式
如果我们动态获取到这些信息,我们需要依靠 Class 对象。Class 类对象将一个类的方法、变量等信息告诉运行的程序。Java 提供了种方式获取 Class 对象:
如果我们动态获取到这些信息,我们需要依靠 Class 对象。Class 类对象将一个类的方法、变量等信息告诉运行的程序。Java 提供了种方式获取 Class 对象:
1.知道具体类的情况下可以使用:
@ -12,18 +12,29 @@ JAVA 反射机制是在运行状态中,对于任意一个类,都能够知道
Class alunbarClass = TargetObject.class;
```
但是我们一般是不知道具体类的,基本都是通过遍历包下面的类来获取 Class 对象
但是我们一般是不知道具体类的,基本都是通过遍历包下面的类来获取 Class 对象通过此方式获取Class对象不会进行初始化
2.通过 `Class.forName()`传入类的路径获取:
```java
Class alunbarClass1 = Class.forName("cn.javaguide.TargetObject");
```
Class.forName(className)方法内部实际调用的是一个native方法 forName0(className, true, ClassLoader.getClassLoader(caller), caller);
第2个boolean参数表示类是否需要初始化Class.forName(className)默认是需要初始化。
一旦初始化,就会触发目标对象的 static块代码执行static参数也会被再次初始化。
3.通过对象实例`instance.getClass()`获取:
```
Employee e;
```java
Employee e = new Employee();
Class alunbarClass2 = e.getClass();
```
4.通过类加载器`xxxClassLoader.loadClass()`传入类路径获取
```java
class clazz = ClassLoader.LoadClass("cn.javaguide.TargetObject");
```
通过类加载器获取Class对象不会进行初始化意味着不进行包括初始化等一些列步骤静态块和静态对象不会得到执行
### 代码实例

View File

@ -401,7 +401,7 @@ Parallel Scavenge 收集器也是使用复制算法的多线程收集器,它
```
**Parallel Scavenge 收集器关注点是吞吐量(高效率的利用 CPU。CMS 等垃圾收集器的关注点更多的是用户线程的停顿时间(提高用户体验)。所谓吞吐量就是 CPU 中用于运行用户代码的时间与 CPU 总消耗时间的比值。** Parallel Scavenge 收集器提供了很多参数供用户找到最合适的停顿时间或最大吞吐量,如果对于收集器运作不太了解的话,手工优化存在困难的话可以选择把内存管理优化交给虚拟机去完成也是一个不错的选择。
**Parallel Scavenge 收集器关注点是吞吐量(高效率的利用 CPU。CMS 等垃圾收集器的关注点更多的是用户线程的停顿时间(提高用户体验)。所谓吞吐量就是 CPU 中用于运行用户代码的时间与 CPU 总消耗时间的比值。** Parallel Scavenge 收集器提供了很多参数供用户找到最合适的停顿时间或最大吞吐量,如果对于收集器运作不太了解手工优化存在困难的时候使用Parallel Scavenge收集器配合自适应调节策略把内存管理优化交给虚拟机去完成也是一个不错的选择。
**新生代采用复制算法,老年代采用标记-整理算法。**
![Parallel Scavenge 收集器 ](./pictures/jvm垃圾回收/parllel-scavenge收集器.png)

View File

@ -1,12 +1,12 @@
> 本篇文章是JavaGuide收集自网络原出处不明。
Mybatis 技术内幕系列博客,从原理和源码角度,介绍了其内部实现细节,无论是写的好与不好,我确实是用心写了,由于并不是介绍如何使用 Mybatis 的文章,所以,一些参数使用细节略掉了,我们的目标是介绍 Mybatis 的技术架构和重要组成部分,以及基本运行原理。
MyBatis 技术内幕系列博客,从原理和源码角度,介绍了其内部实现细节,无论是写的好与不好,我确实是用心写了,由于并不是介绍如何使用 MyBatis 的文章,所以,一些参数使用细节略掉了,我们的目标是介绍 MyBatis 的技术架构和重要组成部分,以及基本运行原理。
博客写的很辛苦,但是写出来却不一定好看,所谓开始很兴奋,过程很痛苦,结束很遗憾。要求不高,只要读者能从系列博客中,学习到一点其他博客所没有的技术点,作为作者,我就很欣慰了,我也读别人写的博客,通常对自己当前研究的技术,是很有帮助的。
尽管还有很多可写的内容,但是,我认为再写下去已经没有意义,任何其他小的功能点,都是在已经介绍的基本框架和基本原理下运行的,只有结束,才能有新的开始。写博客也积攒了一些经验,源码多了感觉就是复制黏贴,源码少了又觉得是空谈原理,将来再写博客,我希望是“精炼博文”,好读好懂美观读起来又不累,希望自己能再写一部开源分布式框架原理系列博客。
有胆就来,我出几道 Mybatis 面试题,看你能回答上来几道(都是我出的,可不是网上找的)。
有胆就来,我出几道 MyBatis 面试题,看你能回答上来几道(都是我出的,可不是网上找的)。
#### 1、#{}和\${}的区别是什么?
@ -15,7 +15,7 @@ Mybatis 技术内幕系列博客,从原理和源码角度,介绍了其内部
答:
- `${}`是 Properties 文件中的变量占位符,它可以用于标签属性值和 sql 内部,属于静态文本替换,比如\${driver}会被静态替换为`com.mysql.jdbc.Driver`
- `#{}`是 sql 的参数占位符Mybatis 会将 sql 中的`#{}`替换为?号,在 sql 执行前会使用 PreparedStatement 的参数设置方法,按序给 sql 的?号占位符设置参数值,比如 ps.setInt(0, parameterValue)`#{item.name}` 的取值方式为使用反射从参数对象中获取 item 对象的 name 属性值,相当于 `param.getItem().getName()`
- `#{}`是 sql 的参数占位符MyBatis 会将 sql 中的`#{}`替换为?号,在 sql 执行前会使用 PreparedStatement 的参数设置方法,按序给 sql 的?号占位符设置参数值,比如 ps.setInt(0, parameterValue)`#{item.name}` 的取值方式为使用反射从参数对象中获取 item 对象的 name 属性值,相当于 `param.getItem().getName()`
#### 2、Xml 映射文件中,除了常见的 select|insert|updae|delete 标签之外,还有哪些标签?
@ -27,65 +27,65 @@ Mybatis 技术内幕系列博客,从原理和源码角度,介绍了其内部
注:这道题也是京东面试官面试我时问的。
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 接口,就是人们常说的 `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 接口的工作原理是 JDK 动态代理Mybatis 运行时会使用 JDK 动态代理为 Dao 接口生成代理 proxy 对象,代理对象 proxy 会拦截接口方法,转而执行`MappedStatement`所代表的 sql然后将 sql 执行结果返回。
Dao 接口的工作原理是 JDK 动态代理MyBatis 运行时会使用 JDK 动态代理为 Dao 接口生成代理 proxy 对象,代理对象 proxy 会拦截接口方法,转而执行`MappedStatement`所代表的 sql然后将 sql 执行结果返回。
#### 4、Mybatis 是如何进行分页的?分页插件的原理是什么?
#### 4、MyBatis 是如何进行分页的?分页插件的原理是什么?
注:我出的。
Mybatis 使用 RowBounds 对象进行分页,它是针对 ResultSet 结果集执行的内存分页,而非物理分页,可以在 sql 内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。
MyBatis 使用 RowBounds 对象进行分页,它是针对 ResultSet 结果集执行的内存分页,而非物理分页,可以在 sql 内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。
分页插件的基本原理是使用 Mybatis 提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的 sql然后重写 sql根据 dialect 方言,添加对应的物理分页语句和物理分页参数。
分页插件的基本原理是使用 MyBatis 提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的 sql然后重写 sql根据 dialect 方言,添加对应的物理分页语句和物理分页参数。
举例:`select _ from student`,拦截 sql 后重写为:`select t._ from select \* from studentt limit 010`
#### 5、简述 Mybatis 的插件运行原理,以及如何编写一个插件。
#### 5、简述 MyBatis 的插件运行原理,以及如何编写一个插件。
注:我出的。
Mybatis 仅可以编写针对 `ParameterHandler``ResultSetHandler``StatementHandler``Executor` 这 4 种接口的插件Mybatis 使用 JDK 的动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这 4 种接口对象的方法时,就会进入拦截方法,具体就是 `InvocationHandler``invoke()`方法,当然,只会拦截那些你指定需要拦截的方法。
MyBatis 仅可以编写针对 `ParameterHandler``ResultSetHandler``StatementHandler``Executor` 这 4 种接口的插件MyBatis 使用 JDK 的动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这 4 种接口对象的方法时,就会进入拦截方法,具体就是 `InvocationHandler``invoke()`方法,当然,只会拦截那些你指定需要拦截的方法。
实现 Mybatis 的 Interceptor 接口并复写` intercept()`方法,然后在给插件编写注解,指定要拦截哪一个接口的哪些方法即可,记住,别忘了在配置文件中配置你编写的插件。
实现 MyBatis 的 Interceptor 接口并复写` intercept()`方法,然后在给插件编写注解,指定要拦截哪一个接口的哪些方法即可,记住,别忘了在配置文件中配置你编写的插件。
#### 6、Mybatis 执行批量插入,能返回数据库主键列表吗?
#### 6、MyBatis 执行批量插入,能返回数据库主键列表吗?
注:我出的。
JDBC 都能Mybatis 当然也能。
JDBC 都能MyBatis 当然也能。
#### 7、Mybatis 动态 sql 是做什么的?都有哪些动态 sql能简述一下动态 sql 的执行原理不?
#### 7、MyBatis 动态 sql 是做什么的?都有哪些动态 sql能简述一下动态 sql 的执行原理不?
注:我出的。
Mybatis 动态 sql 可以让我们在 Xml 映射文件内,以标签的形式编写动态 sql完成逻辑判断和动态拼接 sql 的功能Mybatis 提供了 9 种动态 sql 标签 `trim|where|set|foreach|if|choose|when|otherwise|bind`
MyBatis 动态 sql 可以让我们在 Xml 映射文件内,以标签的形式编写动态 sql完成逻辑判断和动态拼接 sql 的功能MyBatis 提供了 9 种动态 sql 标签 `trim|where|set|foreach|if|choose|when|otherwise|bind`
其执行原理为,使用 OGNL 从 sql 参数对象中计算表达式的值,根据表达式的值动态拼接 sql以此来完成动态 sql 的功能。
#### 8、Mybatis 是如何将 sql 执行结果封装为目标对象并返回的?都有哪些映射形式?
#### 8、MyBatis 是如何将 sql 执行结果封装为目标对象并返回的?都有哪些映射形式?
注:我出的。
答:第一种是使用`<resultMap>`标签,逐一定义列名和对象属性名之间的映射关系。第二种是使用 sql 列的别名功能,将列别名书写为对象属性名,比如 T_NAME AS NAME对象属性名一般是 name小写但是列名不区分大小写Mybatis 会忽略列名大小写,智能找到与之对应对象属性名,你甚至可以写成 T_NAME AS NaMeMybatis 一样可以正常工作。
答:第一种是使用`<resultMap>`标签,逐一定义列名和对象属性名之间的映射关系。第二种是使用 sql 列的别名功能,将列别名书写为对象属性名,比如 T_NAME AS NAME对象属性名一般是 name小写但是列名不区分大小写MyBatis 会忽略列名大小写,智能找到与之对应对象属性名,你甚至可以写成 T_NAME AS NaMeMyBatis 一样可以正常工作。
有了列名与属性名的映射关系后Mybatis 通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。
有了列名与属性名的映射关系后MyBatis 通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。
#### 9、Mybatis 能执行一对一、一对多的关联查询吗?都有哪些实现方式,以及它们之间的区别。
#### 9、MyBatis 能执行一对一、一对多的关联查询吗?都有哪些实现方式,以及它们之间的区别。
注:我出的。
Mybatis 不仅可以执行一对一、一对多的关联查询,还可以执行多对一,多对多的关联查询,多对一查询,其实就是一对一查询,只需要把 `selectOne()`修改为 `selectList()`即可;多对多查询,其实就是一对多查询,只需要把 `selectOne()`修改为 `selectList()`即可。
MyBatis 不仅可以执行一对一、一对多的关联查询,还可以执行多对一,多对多的关联查询,多对一查询,其实就是一对一查询,只需要把 `selectOne()`修改为 `selectList()`即可;多对多查询,其实就是一对多查询,只需要把 `selectOne()`修改为 `selectList()`即可。
关联对象查询,有两种实现方式,一种是单独发送一个 sql 去查询关联对象,赋给主对象,然后返回主对象。另一种是使用嵌套查询,嵌套查询的含义为使用 join 查询,一部分列是 A 对象的属性值,另外一部分列是关联对象 B 的属性值,好处是只发一个 sql 查询,就可以把主对象和其关联对象查出来。
那么问题来了join 查询出来 100 条记录,如何确定主对象是 5 个,而不是 100 个?其去重复的原理是`<resultMap>`标签内的`<id>`子标签,指定了唯一确定一条记录的 id 列Mybatis 根据<id>列值来完成 100 条记录的去重复功能,`<id>`可以有多个,代表了联合主键的语意。
那么问题来了join 查询出来 100 条记录,如何确定主对象是 5 个,而不是 100 个?其去重复的原理是`<resultMap>`标签内的`<id>`子标签,指定了唯一确定一条记录的 id 列MyBatis 根据<id>列值来完成 100 条记录的去重复功能,`<id>`可以有多个,代表了联合主键的语意。
同样主对象的关联对象,也是根据这个原理去重复的,尽管一般情况下,只有主对象会有重复记录,关联对象一般不会重复。
举例:下面 join 查询出来 6 条记录,一、二列是 Teacher 对象列,第三列为 Student 对象列Mybatis 去重复处理后,结果为 1 个老师 6 个学生,而不是 6 个老师 6 个学生。
举例:下面 join 查询出来 6 条记录,一、二列是 Teacher 对象列,第三列为 Student 对象列MyBatis 去重复处理后,结果为 1 个老师 6 个学生,而不是 6 个老师 6 个学生。
t_id t_name s_id
@ -96,17 +96,17 @@ Dao 接口的工作原理是 JDK 动态代理Mybatis 运行时会使用 JDK
| 1 | teacher | 42 |
| 1 | teacher | 43 |
#### 10、Mybatis 是否支持延迟加载?如果支持,它的实现原理是什么?
#### 10、MyBatis 是否支持延迟加载?如果支持,它的实现原理是什么?
注:我出的。
Mybatis 仅支持 association 关联对象和 collection 关联集合对象的延迟加载association 指的就是一对一collection 指的就是一对多查询。在 Mybatis 配置文件中,可以配置是否启用延迟加载 `lazyLoadingEnabled=true|false。`
MyBatis 仅支持 association 关联对象和 collection 关联集合对象的延迟加载association 指的就是一对一collection 指的就是一对多查询。在 MyBatis 配置文件中,可以配置是否启用延迟加载 `lazyLoadingEnabled=true|false。`
它的原理是,使用` CGLIB` 创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用 `a.getB().getName()`,拦截器 `invoke()`方法发现 `a.getB()`是 null 值,那么就会单独发送事先保存好的查询关联 B 对象的 sql把 B 查询上来,然后调用 a.setB(b),于是 a 的对象 b 属性就有值了,接着完成 `a.getB().getName()`方法的调用。这就是延迟加载的基本原理。
当然了,不光是 Mybatis几乎所有的包括 Hibernate支持延迟加载的原理都是一样的。
当然了,不光是 MyBatis几乎所有的包括 Hibernate支持延迟加载的原理都是一样的。
#### 11、Mybatis 的 Xml 映射文件中,不同的 Xml 映射文件id 是否可以重复?
#### 11、MyBatis 的 Xml 映射文件中,不同的 Xml 映射文件id 是否可以重复?
注:我出的。
@ -114,17 +114,17 @@ Dao 接口的工作原理是 JDK 动态代理Mybatis 运行时会使用 JDK
原因就是 namespace+id 是作为 `Map<String, MappedStatement>`的 key 使用的,如果没有 namespace就剩下 id那么id 重复会导致数据互相覆盖。有了 namespace自然 id 就可以重复namespace 不同namespace+id 自然也就不同。
#### 12、Mybatis 中如何执行批处理?
#### 12、MyBatis 中如何执行批处理?
注:我出的。
答:使用 BatchExecutor 完成批处理。
#### 13、Mybatis 都有哪些 Executor 执行器?它们之间的区别是什么?
#### 13、MyBatis 都有哪些 Executor 执行器?它们之间的区别是什么?
注:我出的
Mybatis 有三种基本的 Executor 执行器,**`SimpleExecutor``ReuseExecutor``BatchExecutor`。**
MyBatis 有三种基本的 Executor 执行器,**`SimpleExecutor``ReuseExecutor``BatchExecutor`。**
**`SimpleExecutor`**每执行一次 update 或 select就开启一个 Statement 对象,用完立刻关闭 Statement 对象。
@ -134,36 +134,36 @@ Dao 接口的工作原理是 JDK 动态代理Mybatis 运行时会使用 JDK
作用范围Executor 的这些特点,都严格限制在 SqlSession 生命周期范围内。
#### 14、Mybatis 中如何指定使用哪一种 Executor 执行器?
#### 14、MyBatis 中如何指定使用哪一种 Executor 执行器?
注:我出的
答:在 Mybatis 配置文件中,可以指定默认的 ExecutorType 执行器类型,也可以手动给 `DefaultSqlSessionFactory` 的创建 SqlSession 的方法传递 ExecutorType 类型参数。
答:在 MyBatis 配置文件中,可以指定默认的 ExecutorType 执行器类型,也可以手动给 `DefaultSqlSessionFactory` 的创建 SqlSession 的方法传递 ExecutorType 类型参数。
#### 15、Mybatis 是否可以映射 Enum 枚举类?
#### 15、MyBatis 是否可以映射 Enum 枚举类?
注:我出的
Mybatis 可以映射枚举类不单可以映射枚举类Mybatis 可以映射任何对象到表的一列上。映射方式为自定义一个 `TypeHandler`,实现 `TypeHandler``setParameter()``getResult()`接口方法。`TypeHandler` 有两个作用,一是完成从 javaType 至 jdbcType 的转换,二是完成 jdbcType 至 javaType 的转换,体现为 `setParameter()``getResult()`两个方法,分别代表设置 sql 问号占位符参数和获取列查询结果。
MyBatis 可以映射枚举类不单可以映射枚举类MyBatis 可以映射任何对象到表的一列上。映射方式为自定义一个 `TypeHandler`,实现 `TypeHandler``setParameter()``getResult()`接口方法。`TypeHandler` 有两个作用,一是完成从 javaType 至 jdbcType 的转换,二是完成 jdbcType 至 javaType 的转换,体现为 `setParameter()``getResult()`两个方法,分别代表设置 sql 问号占位符参数和获取列查询结果。
#### 16、Mybatis 映射文件中,如果 A 标签通过 include 引用了 B 标签的内容请问B 标签能否定义在 A 标签的后面,还是说必须定义在 A 标签的前面?
#### 16、MyBatis 映射文件中,如果 A 标签通过 include 引用了 B 标签的内容请问B 标签能否定义在 A 标签的后面,还是说必须定义在 A 标签的前面?
注:我出的
答:虽然 Mybatis 解析 Xml 映射文件是按照顺序解析的,但是,被引用的 B 标签依然可以定义在任何地方Mybatis 都可以正确识别。
答:虽然 MyBatis 解析 Xml 映射文件是按照顺序解析的,但是,被引用的 B 标签依然可以定义在任何地方MyBatis 都可以正确识别。
原理是Mybatis 解析 A 标签,发现 A 标签引用了 B 标签,但是 B 标签尚未解析到尚不存在此时Mybatis 会将 A 标签标记为未解析状态,然后继续解析余下的标签,包含 B 标签待所有标签解析完毕Mybatis 会重新解析那些被标记为未解析的标签,此时再解析 A 标签时B 标签已经存在A 标签也就可以正常解析完成了。
原理是MyBatis 解析 A 标签,发现 A 标签引用了 B 标签,但是 B 标签尚未解析到尚不存在此时MyBatis 会将 A 标签标记为未解析状态,然后继续解析余下的标签,包含 B 标签待所有标签解析完毕MyBatis 会重新解析那些被标记为未解析的标签,此时再解析 A 标签时B 标签已经存在A 标签也就可以正常解析完成了。
#### 17、简述 Mybatis 的 Xml 映射文件和 Mybatis 内部数据结构之间的映射关系?
#### 17、简述 MyBatis 的 Xml 映射文件和 MyBatis 内部数据结构之间的映射关系?
注:我出的
Mybatis 将所有 Xml 配置信息都封装到 All-In-One 重量级对象 Configuration 内部。在 Xml 映射文件中,`<parameterMap>`标签会被解析为 `ParameterMap` 对象,其每个子元素会被解析为 ParameterMapping 对象。`<resultMap>`标签会被解析为 `ResultMap` 对象,其每个子元素会被解析为 `ResultMapping` 对象。每一个`<select>、<insert>、<update>、<delete>`标签均会被解析为 `MappedStatement` 对象,标签内的 sql 会被解析为 BoundSql 对象。
MyBatis 将所有 Xml 配置信息都封装到 All-In-One 重量级对象 Configuration 内部。在 Xml 映射文件中,`<parameterMap>`标签会被解析为 `ParameterMap` 对象,其每个子元素会被解析为 ParameterMapping 对象。`<resultMap>`标签会被解析为 `ResultMap` 对象,其每个子元素会被解析为 `ResultMapping` 对象。每一个`<select>、<insert>、<update>、<delete>`标签均会被解析为 `MappedStatement` 对象,标签内的 sql 会被解析为 BoundSql 对象。
#### 18、为什么说 Mybatis 是半自动 ORM 映射工具?它与全自动的区别在哪里?
#### 18、为什么说 MyBatis 是半自动 ORM 映射工具?它与全自动的区别在哪里?
注:我出的
Hibernate 属于全自动 ORM 映射工具,使用 Hibernate 查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。而 Mybatis 在查询关联对象或关联集合对象时,需要手动编写 sql 来完成,所以,称之为半自动 ORM 映射工具。
Hibernate 属于全自动 ORM 映射工具,使用 Hibernate 查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。而 MyBatis 在查询关联对象或关联集合对象时,需要手动编写 sql 来完成,所以,称之为半自动 ORM 映射工具。
面试题看似都很简单,但是想要能正确回答上来,必定是研究过源码且深入的人,而不是仅会使用的人或者用的很熟的人,以上所有面试题及其答案所涉及的内容,在我的 Mybatis 系列博客中都有详细讲解和原理分析。
面试题看似都很简单,但是想要能正确回答上来,必定是研究过源码且深入的人,而不是仅会使用的人或者用的很熟的人,以上所有面试题及其答案所涉及的内容,在我的 MyBatis 系列博客中都有详细讲解和原理分析。

View File

@ -291,7 +291,7 @@ MVC 是一种设计模式,Spring MVC 是一款很优秀的 MVC 框架。Spring M
`@Transactional`注解作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。如果类或者方法加了这个注解,那么这个类里面的方法抛出异常,就会回滚,数据库里面的数据也会回滚。
`@Transactional`注解中如果不配置`rollbackFor`属性,那么事只会在遇到`RuntimeException`的时候才会回滚,加上`rollbackFor=Exception.class`,可以让事在遇到非运行时异常时也回滚。
`@Transactional`注解中如果不配置`rollbackFor`属性,那么事只会在遇到`RuntimeException`的时候才会回滚,加上`rollbackFor=Exception.class`,可以让事在遇到非运行时异常时也回滚。
关于 `@Transactional ` 注解推荐阅读的文章: