Mybatis学习笔记
Posted *^O^*—*^O^*
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mybatis学习笔记相关的知识,希望对你有一定的参考价值。
ORM框架
ORM(Object Relational Mapping),即对象关系映射。在面向对象编程语言中,将关系型数据库中的
数据与对象建立起映射关系,进而自动的完成数据与对象的互相转换:
- 将输入数据(即传入对象)+SQL 映射成原生 SQL
- 将结果集映射为返回对象,即输出对象
ORM 把数据库映射为对象:
数据库表(table)–> 类(class)
记录(record,行数据)–> 对象(object)
字段(field) --> 对象的属性(attribute)
一般的 ORM 框架,会将数据库模型的每张表都映射为一个 Java 类。
常见的ORM框架
Mybatis
Mybatis是一种典型的半自动的 ORM 框架,所谓的半自动,是因为还需要手动的写 SQL 语句,再由框
架根据 SQL 及 传入数据来组装为要执行的 SQL。其优点为:
- 因为由程序员自己写 SQL,相对来说学习门槛更低,更容易入门。
- 更方便做 SQL的性能优化及维护。
- 对关系型数据库的模型要求不高,这样在做数据库模型调整时,影响不会太大。适合软件需求变更
比较频繁的系统,因此国内系统大部分都是使用如 Mybatis 这样的半自动 ORM 框架。
其缺陷为:
不能跨数据库,因为写的 SQL 可能存在某数据库特有的语法或关键词
Hibernate
Hibernate是一种典型的全自动 ORM 框架,所谓的全自动,是 SQL 语句都不用在编写,基于框架的
API,可以将对象自动的组装为要执行的 SQL 语句。其优点为: - 全自动 ORM 框架,自动的组装为 SQL 语句。
- 可以跨数据库,框架提供了多套主流数据库的 SQL 生成规则。
其缺点为:
学习门槛更高,要学习框架 API 与 SQL 之间的转换关系
对数据库模型依赖非常大,在软件需求变更频繁的系统中,会导致非常难以调整及维护。可能数据
库中随便改一个表或字段的定义,Java代码中要修改几十处。
很难定位问题,也很难进行性能优化:需要精通框架,对数据库模型设计也非常熟悉。
Mybatis整体执行步骤
- 根据application.properties配置,初始化数据库连接(真实的其实是执行SQL时连接)
- Spring能扫描到的接口,如果是带@Mapper注解,会基于Mybatis框架,将接口生成代理类
(为什么可以直接使用接口来调用方法:代理类会注册到容器中,注入或者装配时,接口父类引用指向代理子类对象)
#指定Mybatis表和实体映射关系xml配置文件,包含表与实体的映射,字段和属性的映射,及各个sql语句
mybatis.mapper-locations=classpath:mapper/**Mapper.xml
- 加载Mybatis的xml映射文件
调用Mapper接口的执行流程
-
查找xml映射文件中,namespace 命名空间和mapper全限定名一致的文件
-
根据调用的方法找文件中crud标签id相等的语句块,(id和mapper方法名一致的,作为要执行的sql语句)
-
替换占位符
如果有多个参数,方法参数加@Param(“变量名”)注解
如果是Java对象,作为方法参数,对象属性名绑定占位符变量名一个Java对象,不使用@Param注解,在xml中,占位符写法为#(属性名)
多个方法参数,使用@Param注解作为Java对象变量名,xml占位符的写法为#(对象绑定的变量名.属性名) -
根据查询语句返回值,和要返回的id的类型返回数据
Xml中的配置项
1) 命名空间要和mapper全限定名一致
2) Crud分别为
3) 结果集映射标签
:id的值要和标签的resultMap属性值一致
Mapper接口
1) 根据全限定名查找命名空间一致的xml文件
2) 根据方法名查找crud标签,方法名和id属性值一致的SQL语句
3) 方法参数对应要替换的占位符的值 (xml映射文件,不加parameterType)
接口方法的设计
1) 方法名绑定xml中,crud标签的id
2) 方法参数为要替换的占位符的值
3) 返回类型:如果是更新(新增,修改,删除),统一设计为int,
如果是查询,统一设计为一个对象或List<类型>
Mybatis占位符
1)#{变量名}:实现原理为,先替换为带?的预编译的SQL语句,然后再以jdbc中,操作命令对象,set类型(占位符的索引,替换的值):满足预编译的特性,防止sql注入,预编译提高性能;
2)
变
量
名
:
实
现
原
理
为
,
以
字
符
串
拼
接
的
方
式
,
拼
接
预
编
译
的
s
q
l
语
句
,
{变量名}:实现原理为,以字符串拼接的方式,拼接预编译的sql语句,
变量名:实现原理为,以字符串拼接的方式,拼接预编译的sql语句,{变量名},组织为变量前的sql字符串+${变量名}字符串+变量后的sql字符串——整个作为带?的预编译sql——存在sql注入问题,及性能问题
查询的结果集数据,如果产生了不同表的关系映射,返回的结果集对应就是多种Java类型,并且包含对象间的关系
1) 希望返回的结果集对象的类型,添加关系的对象
1对1关系,添加属性:private关系对象属性 属性名
public class Article {
private Integer id;
private String title;
private String content;
private Integer viewCount;
private Integer userId;
private Date createTime;
//一个文章对象绑定一个用户对象
private User user;
}
1对多关系,添加属性:private List<关系对象属性> 属性名
public class User {
private Integer id;
private String username;
private String password;
private String nickname;
private Boolean sex;
private Date birthday;
private String head;
private Date createTime;
private List<Article> articles;
}
2) xml映射文件中,修改sql的内容
a) 表关联查询;
b) 返回的查询字段,当前命名空间的结果集字段沿用,关联字段,全部加上统一的字段别名及前缀
3) xml映射文件中,中添加映射标签
a) 1对1的映射为
b) 1对多的映射为
属性都是一样:
Property=”对象中关联的属性名”
columnPrefix=“字段前缀”
resultMap=”关联的Mapper命名空间id.结果集映射id”(外部结果集映射写全)
<resultMap id="BaseResultMap" type="org.example.model.Article">
<id column="id" property="id"/>
<result column="title" property="title"/>
<result column="content" property="content"/>
<result column="view_count" property="viewCount"/>
<result column="user_id" property="userId"/>
<result column="create_time" property="createTime"/>
<association property="user"
columnPrefix="u_"
resultMap="org.example.mapper.UserMapper.BaseResultMap"></association>
</resultMap>
<resultMap id="BaseResultMap" type="org.example.model.User">
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
<result column="nickname" property="nickname"/>
<result column="sex" property="sex"/>
<result column="birthday" property="birthday"/>
<result column="head" property="head"/>
<result column="create_time" property="createTime"/>
<collection property="articles"
columnPrefix="a_"
resultMap="org.example.mapper.ArticleMapper.BaseResultMap"/>
</resultMap>
<select id="selectById" resultMap="BaseResultMap">
select
a.id a_id,
a.title a_title,
a.content a_content,
a.view_count a_view_count,
a.user_id a_user_id,
a.create_time a_create_time,
u.id ,
u.username ,
u.password ,
u.nickname,
u.sex ,
u.birthday ,
u.head ,
u.create_time
from article a
join user u on a.user_id=u.id
where u.id=#{id}
</select>
动态sql
1)
<if test=”变量名或者对象属性名 !=null”>
sql片段
满足某种条件,拼接sql的场景
@Test
public void selectByCondition(){
User user = new User();
user.setUsername("b");
// user.setPassword("5");
List<User> list = userMapper.selectByCondition(user);
list.forEach(System.out::println);
}
<select id="selectByCondition" parameterType="org.example.model.User"
resultMap="BaseResultMap">
select * from user
<where>
<if test="username != null">
and username=#{username}
</if>
<if test="password != null">
and password=#{password}
</if>
<if test="nickname != null">
and nickname=#{nickname}
</if>
<if test="sex != null">
and sex=#{sex}
</if>
<if test="birthday != null">
and birthday=#{birthday}
</if>
<if test="head != null">
and head=#{head}
</if>
<if test="createTime != null">
and create_time=#{createTime}
</if>
</where>
</select>
2)
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
insert into article
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="title != null">
title,
</if>
<if test="content != null">
content,
</if>
<if test="viewCount != null">
view_count,
</if>
<if test="userId != null">
user_id,
</if>
<if test="createTime != null">
create_time,
</if>
</trim>
values
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="title != null">
#{title},
</if>
<if test="content != null">
#{content},
</if>
<if test="viewCount != null">
#{viewCount},
</if>
<if test="userId != null">
#{userId},
</if>
<if test="createTime != null">
#{createTime},
</if>
</trim>
</insert>
3)
=
CRUD中,只要可以使用条件语句的地方,都可以使用where
4)
=
用于update修改操作
5)
集合遍历
collection:绑定方法参数中的集合,如 List,Set,Map或数组对象
item:遍历时的每一个对象
open:语句块开头的字符串
close:语句块结束的字符串
separator:每次遍历之间间隔的字符串
<delete id="deleteByIds">
delete from article where id in
<foreach collection="list" item="i" open="(" close=")" separator=",">
#{i}
</foreach>
</delete>
以上是关于Mybatis学习笔记的主要内容,如果未能解决你的问题,请参考以下文章
mybatis学习笔记使用generator生成mybatis基础配置代码和目录结构