MyBatis 映射文件
在 MyBatis 中,可以通过 XxxMapper.xml 映射文件,将 SQL 语句与数据操作方法相绑定。
一个最简单的映射文件样例:
1 |
|
其中:
mapper 标签
- namespace 属性指定接口
子标签
- id 属性指定方法名
- 子标签名指定方法的类型
- 其它属性描述实现方法的参数、返回值等
一、namespace
在之前版本的 MyBatis 中,命名空间(Namespaces)的作用并不大,是可选的。 但现在,随着命名空间越发重要,你必须指定命名空间。
命名空间的作用有两个,一个是利用更长的全限定名来将不同的语句隔离开来,同时也实现了你上面见到的接口绑定。就算你觉得暂时用不到接口绑定,你也应该遵循这里的规定,以防哪天你改变了主意。 长远来看,只要将命名空间置于合适的 Java 包命名空间之中,你的代码会变得更加整洁,也有利于你更方便地使用 MyBatis。
命名解析:为了减少输入量,MyBatis 对所有具有名称的配置元素(包括语句,结果映射,缓存等)使用了如下的命名解析规则。
- 全限定名(比如 “com.mypackage.MyMapper.selectAllThings)将被直接用于查找及使用。
- 短名称(比如 “selectAllThings”)如果全局唯一也可以作为一个单独的引用。 如果不唯一,有两个或两个以上的相同名称(比如 “com.foo.selectAllThings” 和 “com.bar.selectAllThings”),那么使用时就会产生“短名称不唯一”的错误,这种情况下就必须使用全限定名。
namespace 的作用是:
将不同的方法分隔开
不同 Mapper 下的同名方法不会冲突
实现接口绑定
将 xml 文件与接口相互绑定,
Mybatis 可以根据 namespace 寻找到对应的接口,根据 id 寻找到对应的方法,构造 mapper 实例
二、select
1. 说明
用于映射查询方法。
2. 示例
1 |
|
- 映射名为 selectPerson 的方法
- 接收一个 int 类型的参数
- 返回一个 hashmap 类型的对象
- 映射的 SQL 语句为
SELECT * FROM PERSON WHERE ID = #{id}
3. 属性
属性 | 描述 |
---|---|
id |
在命名空间中唯一的标识符,可以被用来引用这条语句。 |
parameterType |
将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。 |
resultType |
期望从这条语句中返回结果的类全限定名或别名。 注意,如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型。 resultType 和 resultMap 之间只能同时使用一个。 |
resultMap |
对外部 resultMap 的命名引用。结果映射是 MyBatis 最强大的特性,如果你对其理解透彻,许多复杂的映射问题都能迎刃而解。 resultType 和 resultMap 之间只能同时使用一个。 |
flushCache |
将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:false。 |
useCache |
将其设置为 true 后,将会导致本条语句的结果被二级缓存缓存起来,默认值:对 select 元素为 true。 |
timeout |
这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖数据库驱动)。 |
fetchSize |
这是一个给驱动的建议值,尝试让驱动程序每次批量返回的结果行数等于这个设置值。 默认值为未设置(unset)(依赖驱动)。 |
statementType |
可选 STATEMENT,PREPARED 或 CALLABLE。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。 |
resultSetType |
FORWARD_ONLY,SCROLL_SENSITIVE, SCROLL_INSENSITIVE 或 DEFAULT(等价于 unset) 中的一个,默认值为 unset (依赖数据库驱动)。 |
databaseId |
如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有不带 databaseId 或匹配当前 databaseId 的语句;如果带和不带的语句都有,则不带的会被忽略。 |
resultOrdered |
这个设置仅针对嵌套结果 select 语句:如果为 true,将会假设包含了嵌套结果集或是分组,当返回一个主结果行时,就不会产生对前面结果集的引用。 这就使得在获取嵌套结果集的时候不至于内存不够用。默认值:false 。 |
resultSets |
这个设置仅适用于多结果集的情况。它将列出语句执行后返回的结果集并赋予每个结果集一个名称,多个名称之间以逗号分隔。 |
其中,
id:用于唯一标识语句,应该与所映射的方法名相同
描述传入参数:
parameterType:传入参数的类名,可选
MyBatis 能够通过类型处理器推当初参数类型
描述返回结果:
resultType 和 resultMap 二选一
resultType:返回结果的类名
若返回的是一个集合,则此处应该填集合元素的类型,而非集合本身的类型
resultMap:引用 resultMap,通过它来描述返回结果
三、insert, update 和 delete
1. 说明
分别用于映射插入、更新和删除方法。
2. 示例
1 |
|
3. 属性
属性 | 描述 |
---|---|
id |
在命名空间中唯一的标识符,可以被用来引用这条语句。 |
parameterType |
将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。 |
flushCache |
将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:(对 insert、update 和 delete 语句)true。 |
timeout |
这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖数据库驱动)。 |
statementType |
可选 STATEMENT,PREPARED 或 CALLABLE。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。 |
useGeneratedKeys |
(仅适用于 insert 和 update)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的自动递增字段),默认值:false。 |
keyProperty |
(仅适用于 insert 和 update)指定能够唯一识别对象的属性,MyBatis 会使用 getGeneratedKeys 的返回值或 insert 语句的 selectKey 子元素设置它的值,默认值:未设置(unset )。如果生成列不止一个,可以用逗号分隔多个属性名称。 |
keyColumn |
(仅适用于 insert 和 update)设置生成键值在表中的列名,在某些数据库(像 PostgreSQL)中,当主键列不是表中的第一列的时候,是必须设置的。如果生成列不止一个,可以用逗号分隔多个属性名称。 |
databaseId |
如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有不带 databaseId 或匹配当前 databaseId 的语句;如果带和不带的语句都有,则不带的会被忽略。 |
其中,
- id:用于唯一标识语句,应该与所映射的方法名相同
- 描述传入参数:
- parameterType:传入参数的类名,可选
4. 递增字段
在实际应用中,往往需要给数据一个”无意义但不重复”的字段,用于区分每一条数据。
例如:
1
2
3
000001 zhang 23
000002 li 22
000003 wang 19
可以通过 useGeneratedKeys=”true”
取得由数据库内部自动生成的主键,再将 keyProperty 设为目标属性即可。
1 |
|
三、传入参数
1. parameterType
parameterType 用于指定传入参数的类型
只能传入一个参数
可选,因为 Mybatis 会自动识别
2. 传入一个参数
直接填写参数类型,或者不填也可以
3. 传入多个参数
可以通过以下方式传入多个参数:
将参数写在对象中
将参数写在 Map 中
使用 @Param 注解参数
顺序传值法:按顺序传入参数,通过
param[n]
或arg[n]
使用参数其中,n 表示第几个参数
有时虽然不加 @Param 注解,但参数仍然能够顺利传入。
这是由于本地 IDE 默认添加了 -parameters 参数,使得方法的参数名在编译时强制保留,从而能够顺利取到参数。
4. 使用参数
当传入一个参数时,使用
#{任意命名}
使用参数1
2
3<select id="getUserById" resultType="Map">
select * from user where id = #{随意}
</select>当传入对象或 Map 时,使用
#{属性名/key 值}
使用参数1
2
3
4
5
6
7
8
9
10
11
12
13
14
15HashMap<String, Integer> map = new HashMap<>();
map.put("username", "root");
map.put("password", "root");
···
<select id="getUserById" resultType="Map">
select
*
from
user
where
username = #{username}
and password = #{password}
</select>
5. 参数占位符
在 MyBatis 中,使用 #{}
和${}
作为参数占位符。它们将占据位置并等待数值插入。
其中,
${}
拿到数值后直接进行字符串拼接#{}
更加安全,可以防止 SQL 注入
四、返回结果
1. 取出返回结果
对于 select 来说,执行完之后应该取出结果。在 MyBatis 中,需要通过 resultType 或 resultMap 描述返回结果。
实际应用中,以下情形可以很方便地取出:
返回结果为单个字段,设置 resultType 为对应基本类型,直接取出即可
1
2
3
4
5
6
7String getUserNameById(int id);
···
<select id="getUserNameById" resultType="string">
select username from user where id = #{id}
</select>返回结果由多个字段组成(或者是多个由多个字段组成的信息组成的集合),且字段与实体类中的属性一一对应,设置 resultType 为 实体类名,直接取出即可
1
2
3
4
5
6
7User getUserById(int id);
···
<select id="getUserById" resultType="pojo.User">
select * from user where id = #{id}
</select>
但如果返回结果中的字段与实体类中的属性不对应,便需要寻找解决方案。
2. 取出多个字段
假设实体类为:
1 |
|
数据库为:
字段名与属性名无法一一对应,此时有几种解决方案:
(1) 在 select 中设置列别名
1 |
|
(2) 使用 Map
1 |
|
将返回结果赋给 Map,返回结果会以字段名为 key,值为 value 放入 Map 之中。再自行取出 Map 中的值,放入实体类对象中。
(3) 使用 resultMap
1 |
|
五、sql
1. 说明
用于定义可复用的 SQL 片段,以便在其它标签中使用。并且该 SQL 片段可以与 SQL 语句“拼接”使用。
2. 使用
1 |
|
使用 sql 标签定义 SQL 片段
id 用于唯一标识此片段
SQL 片段中可以放置参数占位符,待引用时再赋值
1 |
|
- 在需要使用 SQL 片段的地方用 include 标签引用
- refid 属性填写唯一标识值
- SQL 中需要赋值的参数通过 property 赋值
3. 示例
1 |
|