1. choose、when、otherwise
有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
如下列子,当**userId **条件满足时 查询所有的等于userId的数据 当userId不满足时 则根据otherwish下的条件进行查询。
<select id="selectOrders" parameterType="java.lang.Long" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from orders where status=2
<choose>
<when test="userId!=null and userId!=0">
and user_id=#{userId,jdbcType=BIGINT} order by create_time desc
</when>
<otherwise>
order by create_time desc limit 10
</otherwise>
</choose>
</select>
2. foreach
foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符
<select id="selectForech" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from orders
<where>
<foreach collection="list" item="item" index="index" open="id in(" close=")" separator=",">
#{item}
</foreach>
</where>
</select>
<select id="selectForechMap" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from orders
<where>
<foreach collection="key" item="item" index="index" open="id in(" close=")" separator=",">
#{item}
</foreach>
</where>
</select>
mapper层
List<Orders> selectForech(List list);
List<Orders> selectForechMap(HashMap map);
controller层
List<Integer> list = Arrays.asList(158, 160, 161);
HashMap<String, Object> map = new HashMap<>();
map.put("key",list);
List<Orders> orders = ordersMapper.selectForech(list);
System.out.println(orders);
System.out.println("____________________");
System.out.println(ordersMapper.selectForechMap(map));
Preparing: select id, order_num, pay_ano, user_id, shop_id, shop_name, commodity_nums, address_id, pay_type, pay_amount, status, remarks, pay_time, deal_time, deliver_time, create_time, update_time, express_name, express_number from orders WHERE id in( ? , ? , ? )
==> Parameters: 158(Integer), 160(Integer), 161(Integer)
<== Columns: id, order_num, pay_ano, user_id, shop_id, shop_name, commodity_nums, address_id, pay_type, pay_amount, status, remarks, pay_time, deal_time, deliver_time, create_time, update_time, express_name, express_number
<== Row: 158, 5330cf005c16d53a4d188089f4377ea8, 5332baef80393edd4690a0224a46f83d, 32, 18, 教育, 4, 39, null, 0.04, 0, null, null, null, null, 2021-05-19 09:53:31, 2021-05-19 17:12:53, null,
<== Row: 160, 4008332049fe0df846eaabd769399359, 4009554577f46cc54ee8ba69a3f0efe9, 36, 18,教育, 1, 38, 微信, 0.01, 2, null, 2021-05-19 10:40:26, null, 2021-05-19 11:14:45, 2021-05-19 10:40:08, 2021-05-19 11:14:45, null,
<== Row: 161, 4224927db7983f524be7b2aca3419b30, 44021f84e3c769fd4a3d97650592468d, 36, 18, 教育, 1, 38, 支付宝, 0.01, 2, null, 2021-05-19 10:44:21, null, 2021-05-19 11:09:14, 2021-05-19 10:42:25, 2021-05-19 11:09:14, 中通快递, 123456
<== Total: 3
3.延迟加载
懒加载就是在需要查询关联信息的时候去加载查询语句,在不需要的时候就不去执行查询。
在mybatis中,一对一关联的 association 和一对多的collection可以实现懒加载。
1. 开启懒加载
mybatis默认是没有开启懒加载的,要使用懒加载,需要先在全局配置中开启懒加载配置;
配置mybatis-config.xml
<settings>
<!-- 开启懒加载(开启延迟加载)-->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 关闭实时加载 按需加载-->
<setting name="aggressiveLazyLoading" value="false"/>
<!-- 防止默认的触发方法调用,导致延迟加载失效-->
<setting name="lazyLoadTriggerMethods" value=""/>
<!-- 开启二级缓存-->
<setting name="cacheEnabled" value="true"/>
<!-- 设置日志类型-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
xm文件
<mapper namespace="com.example.springboot.mapper.UserBaseInfoMapper">
<resultMap id="BaseResultMap" type="com.example.springboot.pojo.UserBaseInfo">
<id column="id" jdbcType="BIGINT" property="id" />
<result column="name" jdbcType="VARCHAR" property="name" />
<result column="username" jdbcType="VARCHAR" property="username" />
<result column="session_id" jdbcType="VARCHAR" property="sessionId" />
<result column="avatar" jdbcType="VARCHAR" property="avatar" />
<result column="pwd" jdbcType="VARCHAR" property="pwd" />
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
<result column="status" jdbcType="VARCHAR" property="status" />
<!--fetchType用来设置数据加载方式,可选值有2种lazy和eager,分别为延迟加载和积极加载,这个配置会覆盖全lazyLoadingEnabled 配置-->
<association property="orders" column="id"
fetchType="lazy" select="selectOdersByUserId"></association>
</resultMap>
<resultMap id="ordersMap" type="com.example.springboot.pojo.Orders">
<id column="id" jdbcType="BIGINT" property="id" />
<result column="order_num" jdbcType="VARCHAR" property="orderNum" />
<result column="pay_ano" jdbcType="VARCHAR" property="payAno" />
<result column="user_id" jdbcType="BIGINT" property="userId" />
<result column="shop_id" jdbcType="BIGINT" property="shopId" />
<result column="shop_name" jdbcType="VARCHAR" property="shopName" />
<result column="commodity_nums" jdbcType="BIGINT" property="commodityNums" />
<result column="address_id" jdbcType="BIGINT" property="addressId" />
<result column="pay_type" jdbcType="VARCHAR" property="payType" />
<result column="pay_amount" jdbcType="DECIMAL" property="payAmount" />
<result column="status" jdbcType="TINYINT" property="status" />
<result column="remarks" jdbcType="VARCHAR" property="remarks" />
<result column="pay_time" jdbcType="TIMESTAMP" property="payTime" />
<result column="deal_time" jdbcType="TIMESTAMP" property="dealTime" />
<result column="deliver_time" jdbcType="TIMESTAMP" property="deliverTime" />
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
<result column="express_name" jdbcType="VARCHAR" property="expressName" />
<result column="express_number" jdbcType="VARCHAR" property="expressNumber" />
</resultMap>
<sql id="Base_Column_List">
id, name, username, session_id, avatar, pwd, create_time, update_time, status
</sql>
<select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from user_base_info
where id = #{id,jdbcType=BIGINT}
</select>
<select id="selectOdersByUserId" parameterType="java.lang.Long" resultMap="ordersMap">
select * from Orders where user_id=#{id}
</select>
select也可在不同的xml文件配置,需要写上方法的全限定类名
<association property="orders" column="id"
select="com.example.springboot.mapper.OrdersMapperselectOdersByUserId"></association>
</resultMap>
<!--collection 的属性ofType="com.example.springboot.pojo.Orders"-->
</--collection>
<collection property="orders" column="id" ofType="com.example.springboot.pojo.Orders"
select="com.example.springboot.mapper.OrdersMapper.selectOdersByUserId"></collection>
</resultMap>
缓存
缓存是存在于内存中的临时数据。
使用缓存减少和数据库的交互次数,提高执行效率。
Mybatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制
1、适用于缓存
- 经常查询并且不经常改变的;
- 数据的正确与否对最终结果影响不大的;
2、不适用于缓存
- 经常改变的数据;
- 数据的正确与否对最终结果影响很大的;
- 例如:商品的库存,银行的汇率,股市的牌价;
一级缓存
mybatis 的缓存分为2类,分别是一级缓存和二级缓存,一级缓存是默认开启的,它在一个sqlSession会话里面的所有查询操作都会保存到缓存中,一般来说一个请求中的所有增删改查操作都是在同一个sqlSession里面的,所以我们可以认为每个请求都有自己的一级缓存,如果同一个sqlSession会话中2 个查询中间有一个 insert 、update或delete 语句,那么之前查询的所有缓存都会清空;
在springboot+mybatis中使用一级缓存默认是失效的 需要在方法上开启事务
springboot集成mybatis,如果不开启事务,则每一个请求,都会开启一个sqlSession,执行完成后,sqlSession就会close,则在并发的请求下,虽然mapper是单例,但是能保证线程安全,当用了事务之后,当执行完service方法后,sqlSeesion才会close,所以一个请求service中多次调用,第二次调用可以从缓存中读取
@Test
@Transactional
void contextLoads(){
//springboot集成mybatis,如果不开启事务,则每一个请求,都会开启一个sqlSession,执行完成后,sqlSession就会close,则在并发的请求下,虽然mapper是单例,但是能保证线程安全,当用了事务之后,当执行完service方法后,sqlSeesion才会close,所以一个请求service中多次调用,第二次调用可以从缓存中读取
Orders orders = ordersMapper.selectByPrimaryKey(160l);
Orders orders2 = ordersMapper.selectByPrimaryKey(160l);
System.out.println(orders);
}
二级缓存
二级缓存是全局的,也就是说;多个请求可以共用一个缓存,二级缓存需要手动开启,有2种方式配置二级缓存,
- 缓存会先放在一级缓存中,当sqlSession会话提交或者关闭时才会将一级缓存刷新到二级缓存中;
- 开启二级缓存后,用户查询时,会先去二级缓存中找,找不到在去一级缓存中找;
二级缓存显示开启配置 springboot中Mybatis的二级缓存默认为true
<!-- 开启二级缓存-->
<setting name="cacheEnabled" value="true"/>
2.在需要开启缓存的xml中添加 cache标签即可使用二级缓存
<cache>
</cache>
cache官方配置
<cache eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true">
</cache>
这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。
可用的清除策略有:
LRU
– 最近最少使用:移除最长时间不被使用的对象。FIFO
– 先进先出:按对象进入缓存的顺序来移除它们。SOFT
– 软引用:基于垃圾回收器状态和软引用规则移除对象。WEAK
– 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。
默认的清除策略是 LRU。
flushInterval(刷新间隔)属性可以被设置为任意的正整数,设置的值应该是一个以毫秒为单位的合理时间量。 默认情况是不设置,也就是没有刷新间隔,缓存仅仅会在调用语句时刷新。
size(引用数目)属性可以被设置为任意正整数,要注意欲缓存对象的大小和运行环境中可用的内存资源。默认值是 1024。
readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例。 因此这些对象不能被修改。这就提供了可观的性能提升。而可读写的缓存会(通过序列化)返回缓存对象的拷贝。 速度上会慢一些,但是更安全,因此默认值是 false。
二级缓存是事务性的。这意味着,当 SqlSession 完成并提交时,或是完成并回滚,但没有执行 flushCache=true 的 insert/delete/update 语句时,缓存会获得更新。