文章目录
# 入门:简单 静态 SQL 映射
## 获取 新增数据id? (MySQL 、 Oracle)
原生 使用 statement 的方法
mysql 支持自增主键,自增主键值的获取,mybatis 也是利用 statement.getGeneratedKey()
useGeneratedKeys="true"
使用自增组件获取主键值策略keyProperty
指定对应的主键属性,也就是 mybatis 获取到主键值以后,封装到 javaBean 的哪个属性keyColumn
指定 数据库查出的表中,哪一列是 id
<mark>Oracle 怎么搞?</mark>
## @Param
-
POJO:
如果多个参数正好是我们业务逻辑的数据模型,我们就可以直接传入 pojo
#{属性名}:取出传入的 pojo 的属性值 -
Map:
如果多个参数不是业务模型中的数据,没有对应的 pojo ,为了方便传入 map
#{key}:取出key 对应的 value -
TO:
如果多个参数不是业务模型中的数据,但是经常要使用,推荐来编写一个 TO(Transfer Object) 数据传输对象class Page{ int index; int size; }
文章目录
# 进阶1(@Param 和 参数名映射 源码分析)
以 selectById 为例,step into
来到 MapperProxy
的 invoke 方法
MapperProxy
实现了InvocationHandler
接口
当前要执行的方法 ⇒ 参数 method
继续看 invoke 方法 (下面图)
第一行 Object.class.equals(method.getDeclaringClass())
判断如果是 Object 的方法(如 toString 方法)
<mark>直接放行</mark>
否则,进行处理(下图)
首先,final MapperMethod mapperMethod = cachedMapperMethod(method);
把 method 包装成 MapperMethod
(这块不是重点,暂时跳过)
看上图 第二句代码 mapperMethod.execute(sqlSession, args);
作用:执行mapper方法
先看传入的参数
args 的 1 是我们传入的 参数 id
sqlsession
下面 step into execute
方法
从 command 里面获取数据
知道是 增删查改的 哪个方法(这里是 select)
首先会执行执行 method.convertArgsToSqlCommandParam(args)
(看下图)
把 args 传入的 参数 转换为 param sql语句
select 方法有点特殊(下图)
会先判断返回类型
返回 void?多个?Map?图标(Cursor)?或者一个对象(else)
可以看到(下图)
查询一个的情况,底层调用的 还是 sqlSession 的 selectOne 方法 ()
只不过 这里需要传入的是 处理好的 param
所以 , step into method.convertArgsToSqlCommandParam(args);
看看是怎么玩的
可以看到(上图)
names 已经有值了
值怎么来的?
ParamNameResolver
构造时候 赋值的(下图)
(上图)最后,map 把 name 值 put 进去
然后 上面 有 isUseActualParamName 方法,值 根据 配置 确定的
如果配置了为
true
并且是jdk1.8
之后的。
那么,就<mark>使用方法签名中的名称作为语句参数名称</mark>
好,知道 names 的值是怎么来的了,
现在 ,回到 getNamedParams
方法 (下图)
第一层 if 判断 args 的数目
如果 数目为0 ⇒ return null
如果 数目为1 ⇒ 返回第一个
否则 遍历取值
如:names={0=id,1=lastName}
⇒ param={id:args[0] , lastName:args[1]}
前者用于 匹配参数名,后者用于 根据参数名 找 参数值
文章目录
# 入门 :#{} 和 ${} 的区别
- #{}:是以预编译的形式,将参数设置到 sql 语句中,PreparedStatement <mark>防止 sql 注入</mark>
- ${}:取出的值直接拼装在 sql 语句中;<mark>会有安全问题</mark>
但也有使用情况:
如 列名的拼接
select * from ${year}_salary where xxx;
select * from tbl_employee order by ${f_name} ${order} ;
#{}:更丰富的用法
规定参数的一些规则:
## JdbcType.class
jdbcType 通常需要在某种特定条件下被设置:
在我们数据为 null 的时候, 有些数据库(如Oracle)可能不能识别 mybatis 对 null 的默认处理
<mark>如 Oracle 在这种情况下就会报错</mark>
原因:JdbcType OTHER , 无效的类型,因为 mybatis 对所有的 null 映射都是 原生 Jdbc 的 OTHER 类型。而 Oracle 无法识别 OTHER 类型
在 JdbcType.class 里面可以看到所有的 类型
对于 上面 Oracle 不支持 OTHER 类型,
<mark>解决方法有两个</mark>如下:
-
(在 #{…} 里面 加
jdbcType=NULL
)
-
全局配置(jdbcTypeForNull)
文章目录
# 入门:map映射
第一种 map 映射(【一条数据】key:属性名、value:属性值)
第二种 map 映射(【多条数据】key:对象 id、value:对象)
文章目录
# 入门:select 标签 中的属性
文章目录
# 入门 :resultMap
resultMap resultType 只能 二选一
文章目录
# 入门:resultMap - 级联 - 一对多
文章目录
# 入门:association 联合 查询
文章目录
# 入门:association 分步查询(为延时加载做铺垫)
# 入门:延时加载(按需加载)
上面的 分步查询有一个问题
:我们每次查询 Employee 对象的时候,将把 Dept 一起查询出来。
我们希望,部门信息在我们使用的时候再去查询。
.
实现起来其实很简单。
<mark>只需要在 分段查询的基础上 加上两个配置</mark>
lazyLoadingEnabled
懒加载 。 设置所有的懒加载aggressiveLazyLoading
如果开启,懒加载也会完全的加载全部属性。否则,只有需要时候才加载
文章目录
# 入门:collection 联合查询
文章目录
# 入门:collection 分步查询
## <mark>传多列</mark>时候怎么搞?
## fetchType
文章目录
# 入门:discriminator 鉴别器
鉴别器:mybatis 可以使用 discriminator 判断某列的值,然后根据某列的值改变封装行为
封装 Employee:
如果查出的是女生,就把部门信息查询出来,否则不查询
如果是男生,把 last_name 这一列的值赋值给 email