mapper代理:
1.在mapper.xml中namespace等于mapper接口地址
<!-- namespace命名空间,作用就是对sql进行分类化管理,理解sql隔离
注意:使用mapper代理方法开发 namespace有特殊重要作用,namespace等于mapper接口 地址-->
<mapper namespace="cn.xbq.mybatis.mapper.UserMapper">
2.mapper.java接口中的方法名和mapper.xml中statement的id一致
3 - .mapper.java接口中的方法输入参数类型和mapper.xml中statement的parameterType指定类型一致
。
4.mapper.java接口中的方法返回值类型和mapper.xml中statement的resultType指定类型一致。
<select id="findUserById" parameterType="int" resultType="cn.xbq.po.User">
</select>
//根据id查询用户信息
public User findUserById(int id) throws Exception;
5.总结:
以上开发规范主要是对下边的代码进行统一生成:
User user = sqlSession.selectOne("test.findUserById",id);
sqlSession.insert("test.insertUser",user);
…………
6.测试:
记得加载mapper.xml
@Test
public void testFindUserById() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建UserMapper对象,mybatis自动生成mapper代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//调用userMapper的方法
User user = userMapper.findUserById(1);
System.out.println(user);
}
整个的接口:
public interface UserMapper {
//根据id查询用户信息
public User findUserById(int id) throws Exception;
//根据用户名列查询用户列表
public List<User> findUserByName(String name) throws Exception;
//插入用户
public void insertUser(User user) throws Exception;
//删除用户
public void deleteUser(int id) throws Exception;
}
7.代理对象内部调用selectOne或selectList
如果mapper方法返回单个pojo对象(非集合对象),代理对象内部通过selectOne查询数据库。
如果mapper方法返回集合对象,代理对象内部通过selectList查询数据库
8.mapper接口方法参数只能有一个是否影响系统开发
mapper接口方法参数只能有一个,系统是否不利于扩展维护
系统框架中,dao层的代码是被业务层公用的。
即使mapper接口只有一个参数,可以使用包装类型的pojo满足不同的业务方法的需求。
注意:持久层方法的参数可以包装类型,map…,service方法中建议不要使用包装类型(不利于业务层的可扩展)
9.sqlMapConfig.xml
mybatis的全局配置文件sqlMapConfig.xml,配置如下:
properties(属性)
setting(全局配置参数)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境集合属性对象)
environment(环境子属性对象)
transactionManager(事务管理)
dataSource(数据源)
mappers(映射器)
10.properties属性:
需求:
将数据库连接参数单独配置在db.properties中,只需要在sqlMapConfig.xml中加载db.properties的属性值。
在sqlMapConfig.xml中就不需要对数据库连接参数硬编码。
将数据库连接参数只配置在db.properties中,原因:方便对参数进行统一管理,其他xml可以引用该db.properties。
<!--
jdbc.driver = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/mybatis
jdbc.username = root
jdbc.password = 123456
-->
<!-- 加载属性文件-->
<properties resource="db.properties"></properties>
在sqlMapConfig.xml加载属性文件:
<!-- 使用jdbc事务管理,事务控制由mybatis-->
<transactionManager type="JDBC"/>
<!-- 数据库连接池,由mybatis管理-->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}">
<property name="url" value="${jdbc.url}">
<property name="username" value="${jdbc.username}">
<property name="password" value="${jdbc.password}">
</dataSource>
properties特性:
注意:mybatis将按照下面的顺序来加载属性:
在properties元素体内定义的属性首先被读取
然后会读取properties元素中resource或URL加载的属性,他会覆盖已读取的同名属性
最后读取parameterType传递的属性,他会覆盖已读取的同名属性
因此:
通过parameterType传递的属性具有最高优先级,resource或URL加载的属性次之,
最低优先级的是properties元素体内定义的属性。
<!-- 加载属性文件-->
<properties resource="db.properties">
<!-- properties中还可以配置一些属性名和属性值-->
<!-- <property name="jdbc.driver" value="" />-->
</properties>
建议:
不要在properties元素体内添加任何属性值,只将属性值定义在properties文件中。
在properties文件中定义属性名要有一定的特殊性,如:xxx.xxx.xxx
setting全局参数配置:
mybatis框架在运行时可以调整一些运行参数。
比如:开启二级缓存、开启延迟加载…..
全局参数将会影响mybatis的运行行为
typeAliases(别名)重点
1.需求:
在mapper.xml中,定义很多的statement,statement需要parameterType指定输入参数的类型,需要resultType指定输出结果的映射类型。
如果在指定类型时输入类型全路径,不方便进行开发,可以针对parameterType或resultType指定的类型定义一些别名,在mapper.xml中通过别名定义,方便开发。
2.mybatis默认支持别名:
3.单个别名定义:
<!-- 别名定义-->
<typeAliases>
<!-- 针对单个别名定义
type:类型的路径
alias:别名
-->
<typeAlias type="cn.xbq.mybatis.po.User" alias="User" />
</typeAliases>
引用别名:
<select id="findUserById" parameterType="int" resultType="user">
select * from user where id=#{value}
</select>
批量别名的定义(常用):
<!-- 批量别名定义
指定包名,mybatis自动扫描包中的po类,自动定义别名,别名就是类名(首字母大写或小写)
-->
<package name="cn.xbq.mybatis.po" />
typeHandlers(类型处理器)
mybatis中通过typeHandlers完成jdbc类型和Java类型的转换
通常情况下,mybatis提供的类型处理器满足日常需要,不需要自定义。
mappers(映射配置)
1.通过resource加载单个映射文件
<!-- 通过resource方法一次加载一个映射文件-->
<mapper resource="mapper/UserMapper.xml" />
2.通过mapper接口来加载
<!-- 通过mapper接口加载映射文件
遵循一些规范:需要将mapper接口类名和mapper.xml映射文件名保持一致,且在一个目录中上边的规范的前提是:使用的是mapper代理方法
-->
<mapper class="cn.xbq.mybatis.mapper.UserMapper" />
按照上面的规范,将mapper.java和mapper.xml放在一个目录,且同名:
<!--
cn.xbq.mybatis.mapper
UserMapper.java
UserMapper.xml
-->
3.批量加载mapper(推荐使用):
<!-- 批量加载mapper
指定mapper接口的包名,mybatis自动扫描包下边所有的mapper接口进行加载
遵循一些规范:需要将mapper接口类名和mapper.xml映射文件名称保持一致,且在一个目录中
上边规范的前提是:使用的是mapper代理方法
-->
<package name="cn.xbq.mybatis.mapper" />
11.输入映射
通过parameterType指定输入参数的类型,类型可以是简单类型、hashmap、pojo的包装类型
1.传递pojo的包装对象
1.1:需求:
完成用户信息的综合查询,需要传入查询条件很复杂(可能包括用户信息、其他信息,比如商品、订单的)
1.2:定义包装类型pojo:
针对上边需求,建议使用自定义的包装类型的pojo
在包装类型的pojo中将复杂的查询条件包装进去。
public class UserQueryVo {
//在这里包装所需要的查询条件
//用户查询条件
private UserCustom userCustom;
public UserCustom getUserCustom() {
return userCustom;
}
public void setUserCustom(UserCustom userCustom) {
this.userCustom = userCustom;
}
}
1.3 mapper.xml
<!-- 用户信息查询
#{userCustom.sex}:取出pojo包装对象中性别值
${userCustom.username}:取出pojo包装对象中用户名称
-->
<select id="findUserList" parameterType="cn.xbq.mybatis.po.UserQueryVo" resultType="cn.xbq.mybatis.po.UserCustom">
select * from user where user.sex=#{userCustom.sex} and user.username like '%${userCustom.username}%'
</select>
1.4 mapper.java
//用户信息综合查询
public List<UserCustom> findUserList(UserQueryVo userQueryVo) throws Exception;
@Test
public void testFindUserList() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建UserMapper对象,mybatis自动生成mapper对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//创建包装对象,设置查询条件
UserQueryVo userQueryVo = new UserQueryVo();
UserCustom userCustom = new UserCustom();
userCustom.setSex("1");
userCustom.setUsername("卡啦啦啦啦");
userQueryVo.setUserCustom(userCustom);
//调用userMapper的方法
List<UserCustom> list = userMapper.findUserList(userQueryVo);
System.out.println(list);
}
1.5:小节:
查询出来的结果集只有一行且一列,可以使用简单类型进行输出映射。
12.输出pojo对象和pojo列表
不管是输出的pojo单个对象还是一个列表(list中包括pojo),在mapper.xml中resultType 指定的类型是一样的。
在mapper.java指定的方法返回值类型不一样。
1.输出单个pojo对象,方法返回值是单个对象类型。
//根据id查询用户信息
public User findUserById(int id) throws Exception;
2.输出pojo对象list,方法返回值是List
//根据用户名列查询用户列表
public List<User> findUserByName(String name) throws Exception;
生成的动态代理对象中是根据mapper方法的返回值类型确定是调用selectOne(返回单个对象调用)还是selectList(返回集合对象调用)
13. resultType:
使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。
如果查询出来的列名和pojo中的属性名全部不一致,没有创建pojo对象。
只要查询出来的列名和pojo中的属性有一个一致,就会创建pojo对象。
14. resultMap
mybatis中使用resultMap完成高级输出结果映射。
1.resultMap使用方法:
如果查询出来的列名和pojo的属性名不一致,通过定义一个resultMap列名和pojo属性名之间做一个映射关系。
1.1:定义resultMap:
<!--
定义resultMap
将select id id_,username username_ from user 和 user类中的属性作一个映射关系
type:resultMap最终映射的Java对象类型,可以使用别名
id:对resultMap的唯一标识
-->
<resultMap type="user" id="userResultMap">
<!-- id表示查询结果集中唯一标识
column:查询出来的列名
property:type指定的pojo类型中的属性名
最终resultMap对column和property作一个映射关系(对应关系)
-->
<id column="id_" property="id">
<!--
result:对普通名映射定义
column:查询出来的列名
property:type指定的pojo类型中属性名
最终resultMap对column和property作一个映射关系(对应关系)
-->
<result column="username_" property="usrname" />
</resultMap>
1.2使用resultMap作为statement的输出映射类型:
<!-- 使用resultMap进行输出映射
resultMap:指定定义的resultMap的id,如果这个resultMap在其他的mapper文件,前边需要加namespace
-->
<select id="findUserByIdResultMap" parameterType="int" resultMap="userResultMap">
select id id_,username usernmae_ from user where id=#{value}
</select>
1.3测试:
@Test
public void testFindUserList() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建UserMapper对象,mybatis自动生成mapper对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//调用userMapper的方法
User user = userMapper.findUserByIdResultMap(1);
System.out.println(user);
}
1.4:总结:
使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。
如果查询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和pojo属性名之间做一个映射关系。
15:动态sql:
1.什么是动态sql:
mybatis核心对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接、组装。
2.需求:
用户信息综合查询列表和用户信息查询列表总数这两个statement的定义使用动态sql。
对查询条件进行判断,如果输入参数不为空才进行查询条件拼接。
3. mapper.xml
<!--
用户信息综合查询
#{userCustom.sex}:取出pojo包装对象中性别值
${userCustom.username}:取出pojo包装对象中用户名称
-->
<select id="findUserList" parameterType="cn.xbq.mybatis.po.UserQueryVo" resultType="cn.xbq.mybatis.po.UserCustom">
select * from user
<!--
where可以自动去掉条件中的第一个and
-->
<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 '%${usrCustom.username}%'
</if>
</if>
</where>
4.测试代码:
//用户信息的综合查询
@Test
public void testFindUserList() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建UserMapper对象,mybatis自动生成mapper对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//创建包装对象,设置查询条件
UserQueryVo userQueryVo = new UserQueryVo();
UserCustom userCustom = new UserCustom();
userCustom.setSex("1");
userCustom.setUsername("卡啦啦啦啦");
userQueryVo.setUserCustom(userCustom);
//调用userMapper的方法
List<UserCustom> list = userMapper.findUserList(userQueryVo);
System.out.println(list);
}
16.sql片段:
1.需求:
将上边实现的动态sql判断代码块抽取出来,组成一个sql片段,其他的statement中就可以引用sql片段。
方便程序员进行开发。
2.定义sql片段:
<!--
定义sql片段
id:sql片段的唯一标识
经验:是基于单表来定义sql片段,这样话这个sql片段可重用性才高
在sql片段中不要包括where
-->
<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 '%${usrCustom.username}%'
</if>
</if>
</sql>
3.引用sql片段:
在mapper.xml中定义的statement中引用sql片段:
<!--
用户信息综合查询
#{userCustom.sex}:取出pojo包装对象中性别值
${userCustom.username}:取出pojo包装对象中用户名称
-->
<select id="findUserList" parameterType="cn.xbq.mybatis.po.UserQueryVo" resultType="cn.xbq.mybatis.po.UserCustom">
select * from user
<!--
where可以自动去掉条件中的第一个and
-->
<where>
<!-- 引用sql片段的id,如果refid指定的id不在本mapper文件中,需要前边加namespace -->
<include refid="query_user_where"></include>
<!-- 在这里还要引用其他的sql片段-->
</where>
<!--
用户信息综合查询
parameterType:指定输入类型和findUserList一样
resultType:输出结果类型
-->
<select id="findUserList" parameterType="cn.xbq.mybatis.po.UserQueryVo" resultType="cn.xbq.mybatis.po.UserCustom">
select count(*) from user
<!--
where可以自动去掉条件中的第一个and
-->
<where>
<!-- 引用sql片段的id,如果refid指定的id不在本mapper文件中,需要前边加namespace -->
<include refid="query_user_where"></include>
<!-- 在这里还要引用其他的sql片段-->
</where>
17:foreach
向sql传递数组或者List,mybatis使用foreach解析
1.需求:
在用户查询列表和查询总数的statement中增加多个id输入查询。
sql语句如下:
select * from user where id=1 or id=10 or id=16
select * from userwhere id in(1,10,16)
<if test="ids!=null">
<!-- 使用foreach遍历传入ids
collection:指定输入对象中集合属性
item:每个遍历生成对象中
open:开始遍历时拼接的串
close:结束遍历时拼接的串
separator:遍历的两个对象中需要拼接的串
-->
<!-- 使用实现下边的sql拼接:
and (id=1 or id=10 or id=16)
-->
<foreach collection="ids" item="user_id" open="and("close=")" separator="or">
<!-- 每个遍历需要拼接的串 -->
id=#{user_id}
</foreach>
</if>
2.测试代码:
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建UserMapper对象,mybatis自动生成mapper对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//创建包装对象,设置查询条件
UserQueryVo userQueryVo = new UserQueryVo();
UserCustom userCustom = new UserCustom();
userCustom.setSex("1");
userCustom.setUsername("小明");
//传入多个id
List<Integer> ids = new ArrayList<Integer>();
ids.add(1);
ids.add(10);
ids.add(16);
//将id通过userQueryVo传入statement中
userQueryVo.setIds(ids);
userQueryVo.setUserCustom(userCustom);
//调用userMapper的方法
List<UserCustom> list = userMapper.findUserList(userQueryVo);