基础
传参:
1. 传 map 直接用key就行
2. 传 实体类对象 直接用属性
3. @Param绑定
4. param1 param2 param3
5. 传单属性 _parameter
${}和#{}的区别是什么:
#{}是预编译处理,${}是字符串替换。 使用#{}可以有效的防止SQL注入,提高系统安全性。
返回主键问题: useGeneratedKeys="true" keyProperty="id" <selectKey>处理不带自增的数据库
批量插入问题 foreach标签 jdbc: "allowMultiQueries=true"的作用:
1.可以在sql语句后携带分号,实现多语句执行。
2.可以执行批处理,同时发出多个SQL语句
<insert id="insertUserList" parameterType="java.util.List" >
insert into bc_sys_user_pwd_help (user_id, user_pwd) values
<foreach collection="list" item="item" separator=",">
(#{item.ext1}, #{item.ext3})
</foreach>
</insert>
一对一 多对一 一对多 多对多 association vs collection
------------------------------------------------------association-------------------------------------------------
CREATE TABLE `test_table_1` (
`col_1` varchar(32) DEFAULT NULL COMMENT '测试列1',
`col_2` varchar(32) DEFAULT NULL COMMENT '测试列2',
`col_3` varchar(32) DEFAULT NULL COMMENT '测试列3',
`col_4` varchar(32) DEFAULT NULL COMMENT '测试列4',
`col_5` varchar(32) DEFAULT NULL COMMENT '测试列5'
);
insert into test_table_1 (col_1, col_2, col_3, col_4, col_5) values ("1", "2", "a", "b", "c");
insert into test_table_1 (col_1, col_2, col_3, col_4, col_5) values ("2", "3", "a", "b", "c");
CREATE TABLE `test_table_2` (
`col_1` varchar(32) DEFAULT NULL COMMENT '测试列1',
`col_2` varchar(32) DEFAULT NULL COMMENT '测试列2',
`col_3` varchar(32) DEFAULT NULL COMMENT '测试列3',
`col_4` varchar(32) DEFAULT NULL COMMENT '测试列4',
`col_5` varchar(32) DEFAULT NULL COMMENT '测试列5'
);
insert into test_table_2 (col_1, col_2, col_3, col_4, col_5) values ("2", "1", "a", "b", "c");
insert into test_table_2 (col_1, col_2, col_3, col_4, col_5) values ("3", "2", "a", "b", "c");
// 第一种方式:直接进行关联查询 把关联实体的属性在xml中配置 然后关联查出来
<resultMap id="ResultMap" type="com.ccbckj.model.DTO1">
<result column="t1_col1" property="pro1" jdbcType="VARCHAR"/>
<result column="t1_col2" property="pro2" jdbcType="VARCHAR"/>
<result column="t1_col3" property="pro3" jdbcType="VARCHAR"/>
<association property="pro6" javaType="com.ccbckj.model.DTO2"> // column=""属性无意义 也可以单独定义 resultMap="DTO2ResultMap"
<result column="t2_col1" property="dto2_pro1" jdbcType="VARCHAR"/>
<result column="t2_col2" property="dto2_pro2" jdbcType="VARCHAR"/>
<result column="t2_col3" property="dto2_pro3" jdbcType="VARCHAR"/>
</association>
</resultMap>
<select id="test" resultMap="ResultMap">
select
t1.col_1 as t1_col1,
t1.col_2 as t1_col2,
t1.col_3 as t1_col3,
t2.col_1 as t2_col1,
t2.col_2 as t2_col2,
t2.col_3 as t2_col3
from test_table_1 t1
inner join test_table_2 t2 on t1.col_2 = t2.col_1
</select>
// 第二种方式: 单独抽离子查询语句
<resultMap id="ResultMap" type="com.ccbckj.model.DTO1">
<result column="t1_col1" property="pro1" jdbcType="VARCHAR"/>
<result column="t1_col2" property="pro2" jdbcType="VARCHAR"/>
<result column="t1_col3" property="pro3" jdbcType="VARCHAR"/>
<association property="pro6" column="t1_col2" javaType="com.ccbckj.model.DTO2" select="selectDto2ByCol2"></association>
<!-- column="{aaa=t1_col1,bbb=t1_col2}" 多条件示例-->
</resultMap>
<resultMap id="DTO2ResultMap" type="com.ccbckj.model.DTO2">
<result column="col_1" property="dto2_pro1" jdbcType="VARCHAR"/>
<result column="col_2" property="dto2_pro2" jdbcType="VARCHAR"/>
<result column="col_3" property="dto2_pro3" jdbcType="VARCHAR"/>
</resultMap>
<select id="selectDto2ByCol2" resultMap="DTO2ResultMap" parameterType="map">
select
col_1,
col_2,
col_3
from test_table_2 where col_1 = #{t1_col2}
</select>
<select id="test4" resultMap="ResultMap">
select
t1.col_1 as t1_col1,
t1.col_2 as t1_col2,
t1.col_3 as t1_col3
from test_table_1 t1
</select>
-----------------------------------------------------collection---------------------------------------------------------
可以再次添加数据用于测试
insert into test_table_2 (col_1, col_2, col_3, col_4, col_5) values ("3", "2", "a", "b", "c");
collection 基本跟 association 类似
<resultMap id="ResultMap" type="com.ccbckj.model.DTO1">
<result column="t1_col1" property="pro1" jdbcType="VARCHAR"/>
<result column="t1_col2" property="pro2" jdbcType="VARCHAR"/>
<result column="t1_col3" property="pro3" jdbcType="VARCHAR"/>
<collection property="pro6" column="t1_col2" javaType="java.util.List" ofType="com.ccbckj.model.DTO2" select="selectDto2CollectionByCol2"></collection>
</resultMap>
<resultMap id="DTO2ResultMap" type="com.ccbckj.model.DTO2">
<result column="col_1" property="dto2_pro1" jdbcType="VARCHAR"/>
<result column="col_2" property="dto2_pro2" jdbcType="VARCHAR"/>
<result column="col_3" property="dto2_pro3" jdbcType="VARCHAR"/>
</resultMap>
<select id="selectDto2CollectionByCol2" resultMap="DTO2ResultMap" parameterType="map">
select
col_1,
col_2,
col_3
from test_table_2 where col_1 = #{t1_col2}
</select>
<select id="test4" resultMap="ResultMap">
select
t1.col_1 as t1_col1,
t1.col_2 as t1_col2,
t1.col_3 as t1_col3
from test_table_1 t1
</select>
Mybatis的延时加载问题
Mybatis仅支持association关联对象和collection关联集合对象的延迟加载,association指的就是一对一,collection指的就是一对多查询。在Mybatis配置文件中,可以配置是否启用延迟加载
局部延时加载功能
association collection标签中用 fetchType="lazy"
fetchType="lazy" 懒加载策略
fetchType="eager" 立即加载策略
全局加载配置
#全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载。
mybatis.configuration.lazy-loading-enabled=true
#当启用时,有延迟加载属性的对象在被调用时将会完全加载任意属性。否则,每种属性将会按需要加载。
mybatis.configuration.aggressive-lazy-loading=false
lazyLoadingEnabled(lazy-loading-enabled)默认为 false, 也就是不使用懒加载. 所以如果 association 和 collection 使用了 select, 那么 MyBatis 会一次性执行所有的查询. 如果 accociation 和 collection 中的 fetchType 指定为 lazy, 那么即使 lazyLoadingEnabled 为 false, MyBatis 也会使用懒加载 Java 配置中 @One 和 @Many 的 fetchType 支持三个值: LAZY, EAGER, DEFAULT, 其中 DEFAULT 的意思是跟随全局设置即 lazyLoadingEnabled
aggressiveLazyLoading(aggressive-lazy-loading)默认为 true, 也就是说当你开启了懒加载之后, 只要调用返回的对象中的任何一个方法, 那么 MyBatis 就会加载所有的懒加载的属性, 即执行你配置的 select 语句
延迟加载的加载触发方法lazyLoadTriggerMethods默认值为 equals,clone,hashCode,toString, 当你调用这几个方法时, MyBatis 会加载所有懒加载的属性
MyBatis延迟加载主要使用:JavassistProxyFactory,CgliProxyFactoryb实现类。这两种实现类就对应着Mybatis的延迟加载的Javassist和Cgli实现
缓存问题 一级缓存 二级缓存
一级缓存:
一级缓存的作用域默认是一个SqlSession。Mybatis默认开启一级缓存。
关闭或者使一级缓存失效的方法:
1.局部配置 在某mapper.xml文件的select标签中直接增加设置flushCache="true"属性
2.全局配置 在application.properties全局设置mybatis.configuration.local-cache-scope=statement
一级缓存的不足:
使用一级缓存的时候,因为缓存不能跨会话共享,不同的会话之间对于相同的数据可能有不一样的缓存。在有多个会话或者分布式环境下,会存在脏数据的问题。如果要解决这个问题,就要用到二级缓存。
二级缓存:
二级缓存是用来解决一级缓存不能跨会话共享的问题的,作为一个作用范围更广的缓存,它肯定是在SqlSession的外层,否则不可能被多个SqlSession共享。而一级缓存是在SqlSession内部的。二级缓存范围是 namespace 级别的 我也理解为SqlSessionFactory 层面的,可以被多个SqlSession共享 MyBatis查询数据的顺序是:二级缓存 —> 一级缓存 —> 数据库。
1.使用示例
<cache type="org.apache.ibatis.cache.impl.PerpetualCache"
size="1024"
eviction="LRU"
flushInterval="15000"
readOnly="false"/>
2.关于多个xml用一个缓存的问题 可以使用cache-ref标签 假设A B两个Mapper共同用一个缓存 且缓存定义在AMapper.xml中 可以在BMapper.xml中增加 <cache-ref namespace="com.ccbckj.mapper.AMapper"/> 这个namespace对应AMapper.xml中的namespace
测试一级缓存(默认就是开启的)
@RestController
public class TestController {
@Resource
private SqlSessionFactory sqlSessionFactory;
// 测试一级缓存默认开启
@RequestMapping("test2")
public String test2() {
SqlSession session1 = sqlSessionFactory.openSession();
TestMapper mapper1 = session1.getMapper(TestMapper.class);
System.out.println("---->" + mapper1.test1(new HashMap<>()));
System.out.println("---->" + mapper1.test1(new HashMap<>()));
return "OK";
}
}
测试二级缓存(默认是关闭的)
第一步:在application.properties全局配置 mybatis.configuration.cache-enabled=true 就开启整个项目的二级缓存 不设置true确实cache标签也会生效但是设置成false确实是关闭二级缓存
第二步:在Mapper.xml 中配置<cache/>标签:
<cache type="org.apache.ibatis.cache.impl.PerpetualCache"
size="1024"
eviction="LRU"
flushInterval="120000"
readOnly="false"/>
flushInterval(刷新间隔)属性可以被设置为任意的正整数,设置的值应该是一个以毫秒为单位的合理时间量。 默认情况是不设置,也就是没有刷新间隔,缓存仅仅会在调用语句时刷新。
其中eviction代表缓存回收策略,目前mybatis提供以下回收策略:
LRU(Least Recently Used):最近最少使用的,回收最长时间不用的对象;
FIFO(First in first out):先进先出,按照对象进入缓存的顺序来移除;
SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象;
WEAK:弱引用,更积极的移除基于垃圾收集器状态和弱引用规则的对象。
@RestController
public class TestController {
@Resource
private SqlSessionFactory sqlSessionFactory;
// 测试 二级缓存
@RequestMapping("test2")
public String test2() {
SqlSession session1 = sqlSessionFactory.openSession();
TestMapper mapper1 = session1.getMapper(TestMapper.class);
System.out.println("---->" + mapper1.test1(new HashMap<>()));
System.out.println("---->" + mapper1.test1(new HashMap<>()));
session1.commit();
session1.close();
SqlSession session2 = sqlSessionFactory.openSession();
TestMapper2 mapper2 = session2.getMapper(TestMapper2.class);
System.out.println("111---->" + mapper2.test2(new HashMap<>()));
session2.commit();
session2.close();
return "OK";
}
}
网友评论