在这个例子中涉及到的对象由Blog、Author、Post、Comment、Tag。
一个Blog对应一个Author,一个Post集合(一对多)。
Post集合中的每个Post对应一个Author、一个Comment集合、一个Tag集合、一个DraftPost(如果draft列的值为1的时候)。
构造方法:
对应下面这个对象的构造方法
public class User {
//…
public User(int id, String username) {
//…
}
//…
}
3.7 id & result:
id 表示的结果将是当比较对象实例时用到的标识属性。这帮助来改进整体表现,特别是**缓存和嵌入结果映射(也就是联合映射) **。总的来说id就是用于标识对象,以方便缓存,在随后的对象组装、执行查询时,速度更快。
3.8 关联( ,一对一)
关联元素处理“有一个”类型的关系。比如,在我们的示例中,一个博客有一个用户。见下面的使用resultMap映射对象。
加载关联对象,如上面的查询中,查询一个博客时同时加载与该博客对应的用户对象。可以有两种方式:
-
嵌套查询:通过执行另外一个SQL映射语句(产生N+1问题)
-
嵌套结果:使用嵌套结果映射。如上面的复杂SQL语句,一下就把多个表中的所有数据取出。也是我们比较熟悉的一种查询方式。
嵌套查询的一个例子:
SELECT * FROM BLOG WHERE ID = #{id}
SELECT * FROM AUTHOR WHERE ID = #{id}
既然嵌套查询会带来N+1性能问题,什么时候使用嵌套查询呢?
比如上面的selectBlog返回的Blog对象,包含一个Author对象。有的时候我们只需加载Blog对象,只有在需要的时候再加载Author对象。那么我们可以使用嵌套查询,只有在需要的时候再执行selectAuthor,当然这会执行两条select语句。这就是所谓的MyBatis的延迟加载。
MyBatis 能延迟加载这样的查询就是一个好处,因此你可以分散这些语句同时运行的消耗。然而,如果你加载一个列表,之后迅速迭代来访问嵌套的数据,你会调用所有的延迟加 载,这样的行为可能是很糟糕的。如一个Author有一个Post集合(n个post),如果你使用懒加载,然后在程序中遍历这个Post集合(可能是一个List),那么你还要执行n个selectPost语句。
3.9 延迟加载
例子如下:
1.首先需要在mybatis-config.xml中加入如下配置,才能使延迟加载功能生效
2.相应的mapper文件中加入如下设置:
<association property=“college” column=“college_id”
javaType=“College” select=“selectCollegeForStudent”/>
select * from student where id= #{id}
select * from College where id =#{id}
3.测试代码如下:
@Test
public void test0SelectStudentLazyLoadOneToOne(){
System.out.println(“TestCollege.test0SelectStudentLazyLoadOneToOne()”);
SqlSession session;
session = sqlSessionFactory.openSession();
int id = 1;
try {
System.out.println(“=测试LazyLoad=”);
StudentMapper mapper = session.getMapper(StudentMapper.class);
Student student = mapper.selectStudentLazyLoad(id);
System.out.println(student.getName());
System.out.println(“=现在才开始加载College=”);
System.out.println(student.getCollege());
} finally {
session.close();
}
}
对Collection的延迟加载也适用。
4.如果全局打开延迟加载,但希望对个别方法进行积极加载,可以设置fetchType为eager:
<association property=“college” column=“college_id”
javaType=“College” select=“selectCollegeForStudent” fetchType=“eager”/>
**实验证明:**如果不进行任何设置,那么默认为积极加载。只能通过在 设置设置为全局懒加载,然后对个别方法设置为积极加载,如上例。
3.10 多表联合查询解决N+1性能问题
延迟加载会碰到N+1性能问题。碰到这种问题,我们一般直接使用嵌套结果方式(联合查询),例子如下。
select
B.id as blog_id,
B.title as blog_title,
B.author_id as blog_author_id,
A.id as author_id,
A.username as author_username,
A.password as author_password,
A.email as author_email,
A.bio as author_bio
from Blog B left outer join Author A on B.author_id = A.id
where B.id = #{id}
我们看到,只使用了一条select语句。就把两个对象的值一次性填入。
resultMap还支持使用前缀columnPrefix重用映射。具体例子见官网
3.11 集合 :
对应private List<Post> posts;
一个集合嵌套查询的例子:
SELECT * FROM BLOG WHERE ID = #{id}
SELECT * FROM POST WHERE BLOG_ID = #{id}
javaType也可不需要,也可简化为:<collection property="posts" column="id" ofType="Post" select="selectPostsForBlog"/>
3.12 集合的嵌套结果(更常用)
select
B.id as blog_id,
B.title as blog_title,
B.author_id as blog_author_id,
P.id as post_id,
P.subject as post_subject,
P.body as post_body,
from Blog B
left outer join Post P on B.id = P.blog_id
where B.id = #{id}
3.13 鉴别器
对于某一列的不同值,可能对应不同类型的对象,可以使用<discriminator>
,如下属例子
一个简单的例子
详解见官方文档。
3.14 自动映射
一般情况可以直接列名映射为属性名(忽略大小写),如 ID列(数据库字段)->id属性(对象属性)。
通常数据库列使用大写单词命名,单词间用下划线分隔,如User_Name
;而java属性一般遵循驼峰命名法(userName)。 为了在这两种命名方式之间启用自动映射,需要将 mapUnderscoreToCamelCase设置为true。
即在mybatis-config.xml中设置
`
还可以混合使用自动映射和配置映射(id和userName被自动映射,hashed_password 列将根据配置映射):
select
user_id as “id”,
user_name as “userName”,
hashed_password
from some_table
where id = #{id}
3.15 缓存
使用<cache/>
开启,默认情况下没有开启。
一个例子
<cache
eviction=“FIFO”
flushInterval=“60000”
size=“512”
readOnly=“true”/>
这个更高级的配置创建了一个 FIFO 缓存,并每隔 60 秒刷新,存数结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此在不同线程中的调用者之间修改它们会 导致冲突。
详见官方文档。
具体例子见后面缓存。
4. 动态SQL(重点掌握)
5. Java API(简单了解)
专题1.使用resultMap映射对象(sql语句映射)
如果使用JDBC从数据库获取数据的一般流程:
-
创建Connection
-
使用PreparedStatement执行sql语句
-
使用ResultSet获取数据,并创建model对象,执行对象的setter方法为对象赋值。
-
关闭ResultSet、PreparedStatement、Connection
其中第2、3步,mybatis可使用配置文件来完成。
假设有如下sql语句:select e.*,s.id as siteId,s.name as siteName, s.longitude as longitude,s.latitude as latitude from t_equipment e, t_site s where e.sid = s.id
,相关的model对象如下:
public class Site {
private Integer id;
private String name;
private Double longitude;
private Double latitude;
…
}
public class EquipmentDetail {
private Integer id;
private Site site;//注意这里
private String name;
private String type;
private String version;
private String brand;
private String phonenumber;
…
}
传统的对象组装流程:
EquipmentDetail equipment = new EquipmentDetail();
Site site = new Site();
//从resultset中取指定列名的数据,执行对应的equipment的setter方法,
//从resultset中取指定列名的数据,执行对应的一堆site的setter方法
equipment.setSite(site);
//组装完毕
上面这个过程完全写好配置文件,让mybatis按照配置文件进行自动组装,而无需自己编写代码。
上面的过程主要包含几个关键信息: 1. 列名及其对应的属性名。 2.主键、外键信息。
对应的mybatis配置文件如下:
select e.*,s.id as siteId,s.name as siteName, s.longitude as longitude,s.latitude as latitude from t_equipment e, t_site s where e.sid = s.id
其中resultMap="EquipmentDetailResultMap"
表示当sql语句取到数据后可按照其配置信息来进行对象的组装。
实际上resultMap="EquipmentDetailResultMap"
就是代表对象组装的配置信息。这个配置信息可以在多个地方用到。比如下面这段配置信息也复用到了EquipmentDetailResultMap
select e.*,s.id as siteId,s.name as siteName, s.longitude as longitude,s.latitude as latitude from t_equipment e, t_site s where e.sid = s.id and e.id = #{id}
结论: resultMap用来描述组装数据到对象这样的一个过程,并且可以很方便的进行复用。这使我们无需使用硬编码的方式进行繁琐的组装对象的过程。只需要写好配置文件,mybatis就默默地按照配置文件的指示完成对象的组装。
参考
专题2.动态SQL
动态指定条件子句:
使用 <if>
:
select e.*,s.id as siteId,s.name as siteName, s.longitude as longitude,s.latitude as latitude from t_equipment e, t_site s where e.sid = s.id
and s.id = #{sid}
and e.name like ‘%${name}%’
也可以使用<where>
<select id=“findActiveBlogLike”
resultType=“Blog”>
SELECT * FROM BLOG
state = #{state}
AND title like #{title}
AND author_name like #{author.name}
MyBatis还支持:
choose, when, otherwise表达式,只选择其中一个
trim, set(更新的时候用)
foreach(对集合进行遍历,常用语sql中包含IN)
SELECT *
FROM POST P
WHERE ID in
一线互联网大厂Java核心面试题库
正逢面试跳槽季,给大家整理了大厂问到的一些面试真题,由于文章长度限制,只给大家展示了部分题目,更多Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等已整理上传,感兴趣的朋友可以看看支持一波!
加入社区:https://bbs.youkuaiyun.com/forums/4304bb5a486d4c3ab8389e65ecb71ac0
s.id = #{sid}
and e.name like ‘%${name}%’
也可以使用<where>
<select id=“findActiveBlogLike”
resultType=“Blog”>
SELECT * FROM BLOG
state = #{state}
AND title like #{title}
AND author_name like #{author.name}
MyBatis还支持:
choose, when, otherwise表达式,只选择其中一个
trim, set(更新的时候用)
foreach(对集合进行遍历,常用语sql中包含IN)
SELECT *
FROM POST P
WHERE ID in
一线互联网大厂Java核心面试题库
[外链图片转存中…(img-A3qKxvqY-1725695829456)]
正逢面试跳槽季,给大家整理了大厂问到的一些面试真题,由于文章长度限制,只给大家展示了部分题目,更多Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等已整理上传,感兴趣的朋友可以看看支持一波!
加入社区:https://bbs.youkuaiyun.com/forums/4304bb5a486d4c3ab8389e65ecb71ac0