文章目录
- 1、参数
- 2、结果映射
- 2.1、resultMap 元素的属性
- 2.2、id 和 result 元素
- 2.3、constructor 元素
- 2.4、association 元素
- 2.5、collection 元素
- 2.5、discriminator 元素
- 3、缓存
- 3.1、一级缓存
- 3.2、二级缓存
- 3.3、共享相同的缓存配置
1、参数
在映射文件中的select、insert、update、delete
元素中都有parameterType
属性,这个属性就是用于确定参数的类型,可以是原始类型、简单数据类型或对象,它的值可以是别名也可以是全限定名。
<select id="selectUsers" parameterType="int" resultType="User">
select *
from users
where id = #{id}
</select>
当传入单个参数时,parameterType
可以省略,MyBatis 会自动设置。且#{id}
中的id
可以随意命名,当然最好还是按规范命名,在之后进行整合时更加方便。
<select id="selectUser" resultType="com.***.User" parameterType="com.***.User">
select *
from users
where id = #{id}
</select>
当传入 java 对象类型的参数时,会根据#{参数名称}
中的名称查找对象中的字段,然后将它们的值传入预处理语句的参数中。在使用#{id}
完成预处理语句的设置时,还可以设置参数:
<select id="selectUser" resultType="com.***.User" parameterType="com.***.User">
select *
from users
where id = #{id,javaType=double,jdbcType=NUMERIC,typeHandler=MyTypeHandler,numericScale=2}
</select>
{id,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler,numericScale=2}
使用的一些属性 :
- id:表示具体的属性值
- javaType :表示参数在 java 中的数据类型
- jdbcType:表示参数在数据库中的数据类型
- typeHandler:表示使用规定的类型处理器,一般可以省略,除非该属性需要使用自定义类型处理器
- numericScale:数值类型,用于指定小数点后保留的位数。
2、结果映射
resultMap
元素是 MyBatis 中用于返回结果的元素,之前你已经见过简单映射语句的示例,我们并没有显示的配置resultMap
元素。
<select id="selectUsers" resultType="User">
select *
from users
where id = #{id}
</select>
在这些情况下,MyBatis 会在幕后自动创建一个 ResultMap
元素,再根据属性名来映射列到 JavaBean 的属性上。在一般情况下,这种方式就已经猪足够使用了,但是在遇到多表查询等情况时,我们就需要显示的创建resultMap
元素。在使用了resultMap
元素之后:
<resultMap id="userResultMap" type="com.***.User">
<id property="user_id" column="id" />
<result property="user_name" column="name"/>
<result property="user_age" column="age"/>
</resultMap>
<select id="selectUsers" resultType="userResultMap">
select *
from users
where id = #{id}
</select>
那么我们具体来了解一下resultMap
元素,它子元素比较多,讨论起来比较宽泛:
constructor
:实例化的时,通过构造器将结果集注入到类中
-
idArg-ID
参数;标记出作为 ID 的结果可以帮助提高整体性能 -
arg
- 注入构造器的结果集
-
id
:结果集ID,将结果集标记为ID,以方便全局调用 -
result
:注入一个字段或者javabean属性的结果 -
association
: 复杂类型联合;许多查询结果合成这个类型 -
collection
:复杂类型集合 discriminator
:使用一个结果值以决定使用哪个resultMap
-
case
:基于不同值的结果映射
2.1、resultMap 元素的属性
resultMap
元素本身有三个属性:
-
id
:结果集的唯一标识,用于标识一个结果映射。 -
type
:类的完全限定名, 或者一个类型别名 -
autoMapping
:是否开启自动映射
2.2、id 和 result 元素
id
和 result
元素是最基本的结果集映射,它们将列映射到属性或简单的数据类型字段(String, int, double, Date等)。id
元素用于为主键映射;result
元素用于其他基本数据库表字段到实体类属性的映射。
属性 | Value |
property | 需要映射到 JavaBean 的属性名称。 |
column | 数据表的列名或者标签别名。 |
javaType | 一个完整的类名,或者是一个类型别名。如果你匹配的是一个JavaBean,那MyBatis 通常会自行检测到。 |
jdbcType | 数据表支持的类型列表。这个属性只在insert,update 或delete 的时候针对允许空的列有用。JDBC 需要这项,但MyBatis 不需要。如果你是直接针对JDBC 编码,且有允许空的列,而你要指定这项。 |
typeHandler | 使用这个属性可以覆写类型处理器。这项值可以是一个完整的类名,也可以是一个类型别名。 |
最主要的还是 |
2.3、constructor 元素
constructor
元素和id
、result
元素作用差不多。id
、result
是通过 set 方法来赋值。而在某些特定情况下,不能使用 set 方法时,那么我们可以使用该constructor
元素。它的作用是:构造方法来实现值的映射,当然必须提供一个有参构造函数。在这个元素中,有两个子元素idArg
和age
,它们具体的作用和id
和result
相同。这两个元素的具体属性:
属性 | Value |
column | 数据库中的列名,或者是列的别名。 |
name | 构造方法形参的名字。 |
select | 用于加载复杂类型属性的映射语句的 ID,它会从 column 属性中指定的列检索数据,作为参数传递给此 select 语句。具体请参考关联元素。 |
resultMap | 结果映射的 ID,可以将嵌套的结果集映射到一个合适的对象树中。 |
javaType | 同上 |
jdbcType | 同上 |
typeHandler | 同上 |
最主要的还是 |
2.4、association 元素
用于数据库一对一关系。 例如,有一个登录表和用户表,在用户登录成功之后,我们需要获取到用户表的信息。
<!-- 查询用户表 -->
<select id="selectUser" resultMap="userResult">
SELECT * FROM BLOG WHERE ID = #{id}
</select>
<!-- 查询登录表 -->
<select id="selectCard" resultType="com.***.Card">
SELECT * FROM AUTHOR WHERE ID = #{id}
</select>
<!--定义 selectUser 表的结果集 -->
<resultMap id="userResult" type="com.***.User">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<result column="age" property="age"></result>
<association property="card" column="id" javaType="com.***.Card" select="selectCard">
</resultMap>
上述代码的执行流程:
- 调用
selectUser
语句,会根据传入的参数进行查询,然后查询结果进入userResult
结果集进行处理 - 在结果集出来过程中,结果集会去执行
association
的select
属性所指的selectCard
语句,并且再执行过程中将column
属性对应的值传过去。 -
selectCard
语句查询到的结果隐式的使用resultMap
元素将查询注入到 Card 对象中,然后将其的数据返回给userResult
结果集,然后注入给 User 对象的 card 属性。
其实我们在中间省略了一步创建selectCard
语句结果集的代码,我们也可以添加上去:
<!-- 查询用户表 -->
<select id="selectUser" resultMap="userResult">
SELECT * FROM BLOG WHERE ID = #{id}
</select>
<!-- 查询登录表 -->
<select id="selectCard" resultMap="cardResult">
SELECT * FROM AUTHOR WHERE ID = #{id}
</select>
<!--定义 selectCard 的结果集 -->
<resultMap id="cardResult" type="com.itlong.domain.Card">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<result column="pass" property="pass"></result>
</resultMap>
<!--定义 selectUser 的结果集 -->
<resultMap id="userResult" type="com.***.User">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<result column="age" property="age"></result>
<association property="card" column="id" javaType="com.***.Card" select="selectCard">
</resultMap>
这种方式是通过两条 SQL 语句分别执行,还有另外一种方法如下:
<select id="findByUserId_2" resultMap="userResult_2">
select *,u.id as id,u.name as user_name,c.name as card_name
from user u,card c where u.id = c.id and u.id =#{id}
</select>
<resultMap id="userResult_2" type="com.itlong.domain.User">
<id column="id" property="id"></id>
<result property="name" column="user_name"></result>
<result property="age" column="age" ></result>
<association property="card" javaType="com.itlong.domain.Card">
<id column="id" property="id"></id>
<result property="name" column="card_name" ></result>
<result column="pass" property="pass"></result>
</association>
</resultMap>
这种方式还有可以将 association
元素的结果映射提取出来:
<!-- sql 语句映射不变,只改变结果集 -->
<resultMap id="userResult_2" type="com.itlong.domain.User">
<id column="id" property="id"></id>
<result property="name" column="user_name"></result>
<result property="age" column="age" ></result>
<association property="card" javaType="com.itlong.domain.Card" resultMap="cardResult_2">
</association>
</resultMap>
<resultMap id="cardResult_2" type="com.itlong.domain.Card">
<id column="id" property="id"></id>
<result property="name" column="card_name" ></result>
<result column="pass" property="pass"></result>
</resultMap>
association
元素的一些常用属性:
属性 | Value |
property | 映射到对象的字段或属性。 |
column | 数据库中的列名,或者是列的别名。 |
javaType | 一个 Java 类的完全限定名,或一个类型别名 |
select | 用于调用其他映射语句的 ID |
resultMap | 结果映射的 ID |
2.5、collection 元素
用于数据库一对多和多对多关系。 collection
元素和association
元素几乎是一样的,它们的相似度很高。我们还是拿登录表和用户表来解析:
//讲解 association 元素时定义的 两个数据模型
public class User {
private int id;
private String name;
private int age;
private Card card;
//省略 get/set 方法
}
public class Card {
private int id;
private String name;
private int pass;
//省略 get/set 方法
}
在讲解 association
元素时定义的两个数据模型,我们可以看出 User 表中的 card 属性就是用于映射 Card 表的。如果现在用户表对应多个登录。那么我们修改 User 表数据了:
public class User {
private int id;
private String name;
private int age;
private list<Card> card;
//省略 get/set 方法
}
那在这种情况下,我们就需要使用collection
元素了,且只能使用collection
元素,其具体的使用规则和association
一样这里不做重复叙述了。唯一多的一个比较重要的属性是ofType
属性,用于指定 List 的泛型的类型。
2.5、discriminator 元素
discriminator
元素是表示在不不同情况下使用不同的 POJO。例如,某人家里有好小轿车,但是小轿车的种类却不同,比如有 电动汽车 和 传统汽车,我们需要按需来创建不同的 POJO。这时我们就需要在汽车类中添加types属性进行判断,同时还要创建两个类继承汽车类。
<select id="findBankCarId" parameterType="long" resultMap="carResult">
SELECT id, car_name, car_price, types FROM car WHERE id = #{id}
</select>
<resultMap id="carResult" type="com.itlong.domain.Car">
<id column="id" property="id"></id>
<result property="name" column="car_name" ></result>
<result property="price" column="car_price" ></result>
<!-- 将查询结果中 列名为 types 的进行处理 -->
<discriminator javaType="int" column="types">
<!-- types 为 1时寻找 结果集 elecars -->
<case value="1" resultMap="elecars"></case>
<!-- types 为 2时寻找 结果集 tradcars -->
<case value="2" resultMap="tradcars"></case>
</discriminator>
</resultMap>
<!-- types 为 1时使用,通过 Elecars 类实例化 父类 Car -->
<resultMap id="elecars" type="com.***.Elecars" extends="carResult"/>
<!-- types 为 1时使用,通过 Tradcars 类实例化 父类 Car -->
<resultMap id="tradcars" type="com.***.Tradcars" extends="carResult"/>
3、缓存
MyBatis 内置了一个强大的事务性查询缓存机制,分为一级缓存和二级缓存, 默认的情况下, 只开启一级缓存。
3.1、一级缓存
当使用同一个 SqlSession 对象执行同一个 SQL 语句两次时,其实只有第一次查询发送了 SQL 语句,第二次查询根本没有发送 SQL 语句, 直接从内存中获取了结果,获取到对象是相同的。
如果使用不同的 SqlSession 对象执行同一个 SQL 语句两次时,两次查询都分别从数据库中取出了数据。 虽然结果相同, 但两个是不同的对象。
在使用一级缓存时:
- 在同一个 SqlSession 对象中, Mybatis 会把执行的方法和参数通过算法生成缓存的键值, 将键值和结果存放在一个 Map 中, 如果后续的键值一样, 则直接从 Map 中获取数据;
- 不同的 SqlSession 对象之间的缓存是相互隔离的;
- 任何的
UPDATE, INSERT, DELETE
语句都会清空缓存。
3.2、二级缓存
要启用全局的二级缓存,只需要在你的 SQL 映射文件中添加一行:<cache/>
。当然它有几个属性:
-
flushInterval
:刷新间隔,单位毫秒。默认值不设置, 即没有刷新间隔,缓存仅仅在刷新语句时刷新。如果设定了之后, 到了对应时间会过期, 再次查询需要从数据库中取数据。 -
size
:对应为引用的数量,即最多的缓存对象数据, 默认为 1024。 -
readOnly
:表示是否只读。可读写(默认为 false)的缓存会(通过序列化)返回缓存对象的拷贝,速度上会慢一些,但是更安全。 eviction
:表示缓存的回收策略, 默认为LRU
。
-
LRU
:最近最少使用, 移除最长时间不被使用的对象。 -
FIFO:
:FIFO: 先进先出, 按对象进入缓存的顺序来移除对象。 -
SOFT
: 软引用, 移除基于垃圾回收器状态和软引用规则的对象。 -
WEAK
:弱引用, 移除基于垃圾回收器状态和弱引用规则的对象。
3.3、共享相同的缓存配置
在多个映射文件中,我们可以需要配置相同的缓存配置,如果都配置就会造成配置代码重复的弊病。所以我们可以定义一次,然后再其他映射文件引用缓存。引用代码:<cache-ref namespace="com.***.XXXMapper"/>
,其中namespace
属性就是表示需要引用缓存配置的映射文件