SqlMapConfig.xml
mybatis的全局文件
SqlMapConfig.xml中配置的内容和顺序如下:
properties(属性)
settings(全局配置参数)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境集合属性对象)
environment(环境子属性对象)
transactionManager(事务管理)
dataSource(数据源)
mappers(映射器)
properties属性
在我们的总配置文件中,这些东西都是参数变量,像数据库的密码,用户名还有地址什么的。如果需要更改了,不方便。我们把这些数据库连接的参数,单独的配置在db.properties中,只需要在SqlMapConfig.xml中加载该配置文件的属性值。
在sqlmapconfig不需要对数据库连接参数硬编码了
加载方法,有一个标签properties这个标签,里面有一个属性直接链接到写好的db.properties即可。
除了在外部引用文件,还可以在内部自定义属性,然后直接调用也即可
<property name="" value=""></property>
注意: MyBatis 将按照下面的顺序来加载属性:
在 properties 元素体内定义的属性首先被读取。
然后会读取properties 元素中resource或 url 加载的属性,它会覆盖已读取的同名属性。
最后读取parameterType传递的属性,它会覆盖已读取的同名属性。
因此,通过parameterType传递的属性具有最高优先级,resource或 url 加载的属性次之,最低优先级的是 properties 元素体内定义的属性。
建议不要在properties元素体内添加任何的值,只将属性值定义在properties体内,
在properties文件中定义的属性名要有一定的特殊性
settings全局参数配置
mybatis框架在运行时,可以调整一些运行参数
比如:开启二级缓存,开启延迟加载
mybatis全局配置参数,如果运用不当,会影响mybatis的运行行为
typeAliases 别名
需求:在mapper.xml中定义了很多的statement,statement需要parameterType指定输入参数的类型,resultType指定输出结果的映射类型
如果在指定类型,输入类型的全路径不方便开发,可以定义一些别名。
可以针对parameter或者result指定的类型定一些别名
在mapper.xml中定义别名,方便开发
mabatis 支持默认别名,但是对于pojo类型需要自己调配
针对单个别名定义,这里用User进行定义
可以在mapper.xml中的resultType直接写入user
更改完别名程序依然运行成功
批量别名定义
如果我们到时候
pojo类有很多,我们不可能一个一个导入,这样就有了批量别名定义
<package name="cn.mmz.mybatis.pojo"></package>
批量定义别名常用
typeHandlers 类型处理器
mybatis 通过typeHandlers完成jdbc类型和java类型的转换
通常情况下,mybatis提供的类型处理器满足日常需要,不需要进行自定义
mappers mapper配置
一次加载一个,通过resource方法,单个映射文件加载
还可以通过mapper接口来加载
遵循的规范,需要将mapper接口类名和mapper.xml映射文件保持一致,且在一个目录
还可以进行批量加载,指定mapper接口的包名,mybatis自动扫描包下面的接口进行加载
推荐使用
批量加载,也需要mapper.xml与.java在同一个目录下面
输入映射
通过parameterType指定输入参数的类型,类型可以是简单类型,hashmap、pojo包装类型
传递pojo的包装对象
需求:完成用户信息的综合查询,需要传入查询条件(可能包括用户信息,或者其他信息,商品信息,订单信息)
针对上面需求,建议使用自定义包装类型的pojo
定义包装类型pojo
在包装类型中,定义pojo包装进去。
package cn.mmz.mybatis.pojo;
/**
* @Classname UserQueryVo
* @Description TODO
* @Date 2020/1/4 10:49
* @Created by mmz
*/
public class UserQueryVo {
//包装所需要的查询条件
//用户查询条件
private UserCustom userCustom;
public UserCustom getUserCustom() {
return userCustom;
}
public void setUserCustom(UserCustom userCustom) {
this.userCustom = userCustom;
}
//订单、商品条件
}
mapper.java
public List<UserCustom> findUserList(UserQueryVo userQueryVo) throws Exception;
mapper.xml
<select id="findUserList" parameterType="UserQueryVo" resultType="UserCustom">
select * from user where user.sex = #{userCustom.sex} and user.username like '%${userCustom.username}%'
</select>
测试代码
@Test
public void findUserList() throws Exception{
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
UserCustom userCustom = new UserCustom();
userCustom.setSex("1");
userCustom.setUsername("张三丰");
UserQueryVo userQueryVo = new UserQueryVo();
userQueryVo.setUserCustom(userCustom);`在这里插入代码片`
List<UserCustom> userCustoms = userMapper.findUserList(userQueryVo);
System.out.println(userCustoms);
}
输出映射
resultType 与resultMap
如果我们把查询的字段select中,如果没写sex,最后查询出来映射的东西是映射不到UserQueryVo对象的
如果使用resultType进行输出的映射,只有查询出来的列名与pojo中的属性名一致,才可以映射成功,如果查询出来的列名与pojo中的属性全部不一致,没有生成创建pojo对象
只要有一个一致,就会创建pojo对象
需求:用户信息的综合查询总数,通过查询总数和上边用户综合查询列表才可以实现我们的分页。
<select id="findUserCount" parameterType="UserQueryVo" resultType="int">
select count(*) from user where user.sex = #{userCustom.sex} and user.username like '%${userCustom.username}%'
</select>
@Test
public void findUserCount() throws Exception{
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
UserCustom userCustom = new UserCustom();
userCustom.setSex("1");
userCustom.setUsername("张三丰");
UserQueryVo userQueryVo = new UserQueryVo();
userQueryVo.setUserCustom(userCustom);
int count = userMapper.findUserCount(userQueryVo);
System.out.println(count);
}
只有查询出来的结果集只有一行只有一列,可以使用简单类型进行结果的映射
不管是输出pojo单个对象还是一个列表(list包括pojo)
在mapper.xml指定的类型中是一样,不一样的是指定方法的返回值
输出单个对象,就是单个对象类型
如果是一个列表,就是list<pojo>
生成的动态代理对象中是根据mapper方法的返回值类型确定是调用selectOne还是selectList
resultMap
mybatis中使用resultMap完成高级输出结果映射
如果查询出来的列名与pojo属性名不一致,通过定义一个resultMap对列名和pojo属性之间做一个映射
需求是:将下边的Sql 使用UserCustom完成映射
<select id="findUserByIdResultMap" parameterType="int" resultMap="">
select * from user where id =#{id}
</select>
定义resultMap ,使用resultMap
<resultMap id="" type=""></resultMap>
type是最终映射成为的java对象的类型 User ,可以使用别名
id 对resultMap唯一标识
属性中:id标识查询结果集中唯一标识 column查询出来的列名 与property pojo中的属性名,也就是type指定的pojo中的类型名
<id column="id_" property="id"></id>
result是对普通列的映射
<resultMap id="userResultMap" type="User">
<id column="id_" property="id"></id>
<result column="username_" property="username"></result>
</resultMap>
resultMap就是resultMap的id,上面提及到的唯一标识符
如果在其他的mapper中,前面加namespace
测试
@Test
public void findUserByIdResultMap() throws Exception {
//创建Usermapper对象
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.findUserByIdResultMap(1);
System.out.println(user);
}
总结
使用resultMap进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。
如果查询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和pojo属性名做一个映射关系
动态sql
什么是动态sql,mybatis的核心就是对sql语句进行灵活的操作,通过表达式进行判断,对sql进行灵活的拼接、组装,也就是动态生成sql
需求:用户信息综合查询列表和 总数两个statement使用动态sql
select * from user where user.sex = #{userCustom.sex} and user.username like '%${userCustom.username}%'
查询的时候,如果第一个条件与第二条件都为空。那么就相当于查询全部了。
对查询条件进行判断,如果输入的参数不为空,那么再进行查询条件的拼接
进行判断
<if test="userCustom.sex!=null and username.sex != ''">
user.sex = #{userCustom.sex}
</if>
<if test="userCustom != null ">
<if test="userCustom.sex!=null and username.sex != ''">
user.sex = #{userCustom.sex}
</if>
<if test="userCustom.username!=null and username.username != ''">
user.username like '%${userCustom.username}%'
</if>
</if>
因为是两个查询,首先判断这个大的查询条件,如果为空,那么就查询全部,如果不为空,在一个一个进行判断,那么问题来了,如何加上这个and
用到了where标签,可以自动的去掉条件中第一个and
测试代码
@Test
public void findUserList() throws Exception{
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
UserCustom userCustom = new UserCustom();
//由于这里使用动态sql,如果不设置某个值,条件不会拼接在sql中
// userCustom.setSex("1");
userCustom.setUsername("张三丰");
UserQueryVo userQueryVo = new UserQueryVo();
userQueryVo.setUserCustom(userCustom);
List<UserCustom> userCustoms = userMapper.findUserList(userQueryVo);
System.out.println(userCustoms);
}
sql片段
将上面的代码段抽取出来,组成一个sql片段
其他的statement中就可以引用这个片段了
定义一个sql片段
基于单表来定义sql片段,可重用性高
在sql片段不要包括where
定义sql 片段
<sql id="query_user_where">
<if test="userCustom != null">
<if test="userCustom.sex != null and userCustom.sex != ''">
and user.sex = #{userCustom.sex}
</if>
<if test="userCustom.username != null and userCustom.username != ''">
and user.username like '%${userCustom.username}%'
</if>
</if>
</sql>
sql片段使用
<where>
<include refid="query_user_where"></include>
</where>
用include标签,refid里面填上面定义好的sql的id
for each
向sql传递数组或者list,mybatis使用foreach解析
需求:在用户查询列表和查询总数的statement中增加多个id输入查询
先实验第一种
在输入参数类型,添加list<integer>
ids传入多个id
修改mapper.xml,在原来的mapper.xml文件中进行修改
<if test="ids != null">
<foreach collection="" item="" open=""></foreach>
</if>
collection指定输入对象的集合属性,也就是我们在Vo定义的ids
item 每次遍历的对象名 id
open 开始遍历时拼接的串 and (
close 是结束遍历拼接的串 )
separator 遍历的两个中间拼接的串 or
中间写上内容
<if test="ids != null">
<foreach collection="ids" item="id" open="and (" close=")" separator="or">
id =#{id}
</foreach>
</if>
测试代码
@Test
public void findUserList() throws Exception{
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
UserCustom userCustom = new UserCustom();
//由于这里使用动态sql,如果不设置某个值,条件不会拼接在sql中
// userCustom.setSex("1");
userCustom.setUsername("小明");
List<Integer> ids = new ArrayList<Integer>();
ids.add(1);
ids.add(10);
ids.add(16);
UserQueryVo userQueryVo = new UserQueryVo();
userQueryVo.setIds(ids);
userQueryVo.setUserCustom(userCustom);
List<UserCustom> userCustoms = userMapper.findUserList(userQueryVo);
System.out.println(userCustoms);
}