MyBatis学习笔记
Posted 佳云分享网
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MyBatis学习笔记相关的知识,希望对你有一定的参考价值。
接上期《MyBatis学习笔记(二)》
5.sqlMapConfig.xml
mybatis 的全局配置文件 sqlMapConfig.xml 配置的内容如下:
properties(属性)
settings(全局配置参数)
typeAliases(类别别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境集合属性对象)
environment(环境子属性对象)
transactionManager(事务管理)
dataSource(数据源)
mappers(映射器)
5.1 properties 属性
需求:
将数据连接的参数单独配置在 db.properties 文件中,只需求在 SqlMapConfig.xml 文件中加载 db.properties 的属性值。
在 SqlMapConfig.xml 文件就不需要对数据库连接的参数进行硬编码了。
将数据库连接参数配置到 db.properties 文件中的原因:方便对参数进行统一管理,其他 xml 文件可以引用该 db.properties 的属性值。
在 SqlMapConfig.xml 文件加载属性文件并引用对应的属性值:
<!-- 加载属性文件 -->
<properties resource="config/db.properties"></properties>
<!-- 和spring整合后 environments配置将废除-->
<environments default="development">
<environment id="development">
<!-- 使用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>
</environment>
</environments>
properties 特性:
注意:mybatis 按照下列顺序加载属性值
1.在 properties 元素体内的属性首先被加载。
2.然后读取 properties 中元素 resource 或 url 加载的属性,覆盖已读取的同名属性值。
3.最后读取 parameterType 传递的属性,覆盖已加载的并读取的同名属性值。
建议:
不要在 properties 元素体内添加任何属性值,只将属性值定义在 properties文件中。
并且在 properties文件中定义的属性值要有一定的特殊性,比如 xxxx.xxx.xxx
5.2 settings 全局参数配置
mybatis 框架在运行时可以调整一些数,设置不当会影响 mybatis 的性能:
比如:开启二级缓存、开启延迟加载、...。
5.3 typeAliases 类名别名(重点)
5.3.1 需求
在 mapper.xml 中,定义了很多的 statement ,statement 需要 parameterType 指定输入参数的类型,还
需要 resultType 指定输出结果的映射类型。
如果在指定类型是输入类型全路径,不方便进行开发,可以针对 parameterType 或 resultType 指定的类型定义
一些类型别名,在 mapper.xml 中 通过类型别名指定类型,方便开发。
5.3.2 mybatis 默认支持类型别名
5.3.3 自定义类型别名
5.3.3.1 单个别名定义和引用
1)定义:
<typeAliases>
<!-- 单个参数的别名定义
type:类型全路径
alias:类型别名
-->
<typeAlias type="org.hxweb.web.ssm.pojo.User" alias="user"/>
</typeAliases>
2)引用:
<select id="findUserById" parameterType="int" resultType="user">
SELECT * FROM user WHERE id=#{value}
</select>
5.3.3.2 批量别名定义和引用(常用)
<typeAliases>
<!-- 批量扫描别名
name:指定java包名(),mybatis 自动扫描包中的pojo类,自动定义别名,别名就是类名(首字母大写或小写都可以,一般引用建议首字母小写)
<!--
<package name="org.hxweb.web.ssm.pojo"/>-->
</typeAliases>
5.4 typeHandlers 类型处理器
一般情况下 mybatis 支持的类型已经能满足大部分项目的需要,不需要自定义类型。
5.5 mappers 映射器(映射配置)
5.5.1.<!--通过resource方法一次加载一个映射文件 -->
<!-- <mapper resource="mapper/UserMapper.xml"/> -->
5.5.2.<!-- 通过mapper接口加载单个 映射文件
遵循一些规范:需要将mapper接口类名和mapper.xml映射文件名称保持一致,且在一个目录 中
上边规范的前提是:使用的是mapper代理方法
-->
<!-- <mapper class="org.hxweb.web.ssm.mapper.UserMapper"/> -->
5.5.3 (推荐使用)<!-- 批量加载mapper
指定mapper接口的包名,mybatis自动扫描包下边所有mapper接口进行加载
遵循一些规范:需要将mapper接口类名和mapper.xml映射文件名称保持一致,且在一个目录 中
上边规范的前提是:使用的是mapper代理方法
<package name="org.hxweb.web.ssm.mapper"/>-->
6.输入映射
通过 parameterType 指定输入参数类型,包括简单类型、普通pojo类型、hashmap、pojo 包装类型。
6.1 pojo 包装类型
6.1.1 需求,完成用户信息的综合查询,需要传入查询条件很复杂(可能用户信息、其它信息,比如商品的、订单的等)。
6.1.2 自定义的包装类型的 pojo
针对需求,建议使用自定义的包装类型的 pojo。
包装类型的 pojo ,将复杂的查询条件包装进去。
import org.hxweb.web.ssm.custom.UserCustom;
/**
* @see 用户查询的包装类型 pojo
* @author Administrator
*
*/
public class UserQueryVo {
// 包装所需要的查询条件
// 包装用户查询条件(建议使用用户扩展类)
private UserCustom userCustom;
public UserCustom getUserCustom() {
return userCustom;
}
public void setUserCustom(UserCustom userCustom) {
this.userCustom = userCustom;
}
// 包装商品查询条件
// 包装订单查询条件
}
6.1.3 mapper.xml
在 UserMapper.xml 中创建用户信息综合查询(查询条件复杂,通过高级查询进行复杂关联查询)。
<!-- 定义用户信息综合查询
#{userCustom.sex}:取出pojo包装对象中sex的值
${userCustom.username}:取出pojo包装对象中username的值
-->
<select id="findUserList" parameterType="org.hxweb.web.ssm.vo.UserQueryVo" resultType="org.hxweb.web.ssm.custom.UserCustom">
select user.* from user where user.sex=#{userCustom.sex} and user.username like "%${userCustom.username}%"
</select>
6.1.4 mapper.java
在 UserMapper.java 中创建用户信息综合查询方法
//用户信息综合查询
public List<UserCustom> findUserList(UserQueryVo userQueryVo) throws Exception;
6.1.5 测试类:
//用户信息综合查询
@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);
//释放sqlSession
sqlSession.close();
System.out.println(list);
}
7.输出映射
7.1 resultType
7.1.1 输出普通 pojo 类型
使用 resultType 进行映射输出,只有查询出的列名和pojo中的属性名一致,该列才可映射成功。
如果查询出的列名和pojo中的属性名全部不一致,没有创建 pojo 对象。
只要查询出的列名和pojo中的属性名有一个一致,就会创建 pojo 对象,其不一致的列属性值为空或者0.
7.1.2 输出简单类型
7.1.2.1 需求:
用户信息综合查询列表总数,通过查询总数和用户综合查询列表,才可以进行分页。
7.1.2.2 mapper.xml
<!-- 定义用户信息综合查询列数总数
#{userCustom.sex}:取出pojo包装对象中sex的值
${userCustom.username}:取出pojo包装对象中username的值
parameterType 输入类型和findUserList一致
resultType 输出结果类
-->
<select id="findUserCount" parameterType="org.hxweb.web.ssm.vo.UserQueryVo" resultType="int">
select count(1) from user where user.sex=#{userCustom.sex} and user.username like "%${userCustom.username}%"
</select>
7.1.2.3 mapper.java
//用户信息综合查询总数
public int findUserCount(UserQueryVo userQueryVo) throws Exception;
7.1.2.4 测试
//用户信息综合查询总数
@Test
public void testFindUserCount() 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的方法
int userCount = userMapper.findUserCount(userQueryVo);
//释放sqlSession
sqlSession.close();
System.out.println("用户总数:"+userCount);
}
7.1.2.5 小结:
查询出来的结果集只有一列且一行,才可以使用简单类型进行输出映射。
7.1.2.6 输出 pojo 对象 和 pojo 列表
输出:不管输出的是 pojo 单个对象,还是 pojo 对象列表(list中包含 pojo),在mapper.xml中 resultType的类型都是一样的pojo对象
7.1.2.6.1.输出的是 pojo 单个对象,mapper.java 接口方法的返回类型是单个 pojo 对象。
// 根据id查询用户信息
public User findUserById(Integer id) throws Exception;
7.1.2.6.2.输出的是是 pojo 对象列表(list中包含 pojo),mapper.java 接口方法上午返回类型是List<pojo>.
// 根据用户名列查询用户列表
public List<User> findUserByName(String name) throws Exception;
7.1.2.6.3 生成的代理对象会根据mapper.java接口中方法的返回值来自动确定是调用 selectOne (返回单个对象调用) 还是 selectList(返回集合对象调用)。
7.1.3 输出 hashmap
输出的pojo对象可以改用 hashmap ,将输出的字段名称作为 map 的key,字段值作为对应的 value。
7.2 resultMap
mybatis 可以使用 resultMap 完成高级输出结果映射,
7.2.1 resultMap 使用方法
如果查询出的列名和pojo中的属性名不一致,通过定义一个 resultMap 对列名和 pojo 属性名之间做一个映射关系。
7.2.1.1 定义 resultMap
7.2.1.2 使用 resultMap 作为 statement 的输出映射类型
7.2.2 将以下 sql 使用 User 完成输出映射。
select id id_,username username_ from user WHERE id=#{value}
sql查询的列名与 User 类中属性名不一致.
7.2.2.1 定义 resultMap
<!-- 定义resultMap
将select id id_,username username_ from user WHERE id=#{value} 和 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="username" />
</resultMap>
7.2.2.2 使用 resultMap 作为 statement 的输出映射类型
<!-- 使用 resultMap 作为输出映射
resultMap:指定定义的 resultMap 的id,如果 resultMap 在其它 mapper.xml中,需要在前边加上namespace.
-->
<select id="findUserByIdResultMap" parameterType="int" resultMap="userResultMap">
select id id_,username username_ from user WHERE id=#{value}
</select>
7.2.2.3 mapper.java 方法定义
// 根据id查询用户信息,使用resultMap 输出
public User findUserByIdResultMap(Integer id) throws Exception;
7.2.2.4 测试方法
//根据id查询用户信息,使用 resultMap 输出
@Test
public void testFindUserByIdResultMap() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建UserMapper对象,mybatis自动生成mapper代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//调用userMapper的方法
User user = userMapper.findUserByIdResultMap(1);
//释放sqlSession
sqlSession.close();
System.out.println(user);
}
7.3 小结:
7.3.1 使用 resultType 进行映射输出,只有查询出的列名和pojo中的属性名一致,该列才可映射成功。
7.3.2 如果查询出的列名和pojo中的属性名不一致,通过定义一个 resultMap 对列名和 pojo 属性名之间做一个映射关系。
8.动态sql
8.1 什么是动态sql
mybatis 的核心,对sql进行灵活操作,通过表达式判断,对sql进行灵活拼接、组装。
8.2 需求
用户信息综合查询和用户信息综合查询列表总数这两个 statement 的定义使用动态sql。
对查询条件进行判断,如果输入参数不为空才进行查询条件拼接。
8.3 mapper.xml
<!-- 定义用户信息综合查询 #{userCustom.sex}:取出pojo包装对象中sex的值 ${userCustom.username}:取出pojo包装对象中username的值 -->
<select id="findUserList" parameterType="org.hxweb.web.ssm.vo.UserQueryVo"
resultType="org.hxweb.web.ssm.custom.UserCustom">
select user.* 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 "%${userCustom.username}%"
</if>
</if>
</where>
</select>
<!-- 定义用户信息综合查询列数总数 #{userCustom.sex}:取出pojo包装对象中sex的值 ${userCustom.username}:取出pojo包装对象中username的值
parameterType 输入类型和findUserList一致 resultType 输出结果类 -->
<select id="findUserCount" parameterType="org.hxweb.web.ssm.vo.UserQueryVo"
resultType="int">
select count(1) 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 "%${userCustom.username}%"
</if>
</if>
</where>
</select>
8.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();
//扩展对象设置查询条件值
//由于使用了动态sql 如果不设置某个值,就不会拼接到sql中去
userCustom.setSex("1");
//userCustom.setUsername("陈小明");
//包装对象设置查询对象
userQueryVo.setUserCustom(userCustom);
//调用userMapper的方法
List<UserCustom> list = userMapper.findUserList(userQueryVo);
//释放sqlSession
sqlSession.close();
System.out.println(list);
}
//用户信息综合查询总数
@Test
public void testFindUserCount() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建UserMapper对象,mybatis自动生成mapper代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//创建包装对象,设置查询对象
UserQueryVo userQueryVo = new UserQueryVo();
//由于使用了动态sql 如果不设置某个值,就不会拼接到sql中去
//创建扩展对象
UserCustom userCustom = new UserCustom();
//扩展对象设置查询条件值
userCustom.setSex("1");
//userCustom.setUsername("陈小明");
//包装对象设置查询对象
userQueryVo.setUserCustom(userCustom);
//调用userMapper的方法
int userCount = userMapper.findUserCount(userQueryVo);
//释放sqlSession
sqlSession.close();
System.out.println("用户总数:"+userCount);
}
8.5 sql片段
8.5.1 需求
将8.2的需求中的条件判断抽取出来,组成一个sql片段,其它 statement 就可以调用这个 sql片段。
方便程序员开发。
8.5.2 定义sql片段
<!-- 定义sql片段
id:sql片段的唯一标识
经验:1.基于单表查询来定义sql片段,这样的sql片段可重用性高
2.在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 "%${userCustom.username}%"
</if>
</if>
</sql>
8.5.3 引用sql片段
<!-- 定义用户信息综合查询 #{userCustom.sex}:取出pojo包装对象中sex的值 ${userCustom.username}:取出pojo包装对象中username的值 -->
<select id="findUserList" parameterType="org.hxweb.web.ssm.vo.UserQueryVo"
resultType="org.hxweb.web.ssm.custom.UserCustom">
select user.* from user
<!--
where 会自动去掉查询条件中的第一个 and
-->
<where>
<!--引用sql片段id,如果refid指定的sql片段不在本mapper.xml文件中,前面需要加上namespace -->
<include refid="query_user_where"></include>
<!-- 在这里还会引用其它sql片段
<include refid="query_items_where"></include>
<include refid="query_order_where"></include>
-->
</where>
</select>
<!-- 定义用户信息综合查询列数总数 #{userCustom.sex}:取出pojo包装对象中sex的值 ${userCustom.username}:取出pojo包装对象中username的值
parameterType 输入类型和findUserList一致 resultType 输出结果类 -->
<select id="findUserCount" parameterType="org.hxweb.web.ssm.vo.UserQueryVo"
resultType="int">
select count(1) from user
<!--
where 会自动去掉查询条件中的第一个 and
-->
<where>
<!--引用sql片段id,如果refid指定的sql片段不在本mapper.xml文件中,前面需要加上namespace -->
<include refid="query_user_where"></include>
<!-- 在这里还会引用其它sql片段
<include refid="query_items_where"></include>
<include refid="query_order_where"></include>
-->
</where>
</select>
8.5.4 测试
8.6 foreach
向sql中传递数组或者List,mybatis 使用 foreach 解析。
8.6.1 需求
在8.5的需求中,增加多个id输入查询。
sql语句如下:
两种方法:
select * from user where 1=1 and (id=1 or id=10 or id=16)
select * from user where 1=1 and id in(1,10,16)
8.6.2 在输入参数类型中添加List<Integer> ids 属性传入多个id值
public class UserQueryVo {
// 包装所需要的查询条件
//添加多个id属性
private List<Integer> ids;
8.6.3 修改mapper.xml
select * from user where 1=1 and (id=1 or id=10 or id=16)
<if test="ids!=null">
<!-- 使用foreach标签变了传入的多个id
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>
select * from user where 1=1 and id in(1,10,16)
<if test="ids!=null">
<!-- 使用foreach标签变了传入的多个id 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> -->
<!-- 使用如下的sql进行拼接 and id in (1,10,16) -->
<foreach collection="ids" item="user_id" open="and id in ("
close=")" separator=",">
<!-- 每次遍历拼接串 -->
#{user_id}
</foreach>
</if>
8.6.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();
//扩展对象设置查询条件值
//由于使用了动态sql 如果不设置某个值,就不会拼接到sql中去
//userCustom.setSex("1");
userCustom.setUsername("小明");
//传入多个id
List<Integer> ids = new ArrayList<Integer>();
ids.add(1);
ids.add(10);
ids.add(16);
//包装对象设置查询对象
userQueryVo.setUserCustom(userCustom);
//包装对象设置ids属性值,传入多个id
userQueryVo.setIds(ids);
//调用userMapper的方法
List<UserCustom> list = userMapper.findUserList(userQueryVo);
//释放sqlSession
sqlSession.close();
System.out.println(list);
}
9 .总结:
mybatis是什么?
mybatis是一个持久层框架,mybatis是一个不完全的ORM框架。sql语句需要程序员自己去编写,但是mybatis也有映射(输入参数映射、输出结果映射)。
mybatis入门门槛不高,学习成本低,让程序员把精力放在sql语句上,对sql语句优化非常方便,适用与需求变化较多项目,比如互联网项目。
mybatis框架执行过程:
1、配置mybatis的配置文件,SqlMapConfig.xml(名称不固定)
2、通过配置文件,加载mybatis运行环境,创建SqlSessionFactory会话工厂
SqlSessionFactory在实际使用时按单例方式。
3、通过SqlSessionFactory创建SqlSession
SqlSession是一个面向用户接口(提供操作数据库方法),实现对象是线程不安全的,建议sqlSession应用场合在方法体内。
4、调用sqlSession的方法去操作数据。
如果需要提交事务,需要执行SqlSession的commit()方法。
5、释放资源,关闭SqlSession
mybatis开发dao的方法:
1、原始dao 的方法
需要程序员编写dao接口和实现类
需要在dao实现类中注入一个SqlSessionFactory工厂。
2、mapper代理开发方法(建议使用)
只需要程序员编写mapper接口(就是dao接口)
程序员在编写mapper.xml(映射文件)和mapper.java需要遵循一个开发规范:
1、mapper.xml中namespace就是mapper.java的类全路径。
2、mapper.xml中statement的id和mapper.java中方法名一致。
3、mapper.xml中statement的parameterType指定输入参数的类型和mapper.java的方法输入 参数类型一致。
4、mapper.xml中statement的resultType指定输出结果的类型和mapper.java的方法返回值类型一致。
SqlMapConfig.xml配置文件:可以配置properties属性、别名、mapper加载。。。
输入映射:
parameterType:指定输入参数类型可以是简单类型、pojo、hashmap。。
对于综合查询,建议parameterType使用包装的pojo,有利于系统 扩展。
输出映射:
resultType:
查询到的列名和resultType指定的pojo的属性名一致,才能映射成功。
reusltMap:
可以通过resultMap 完成一些高级映射。
如果查询到的列名和映射的pojo的属性名不一致时,通过resultMap设置列名和属性名之间的对应关系(映射关系)。可以完成映射。
高级映射:
将关联查询的列映射到一个pojo属性中。(一对一)
将关联查询的列映射到一个List<pojo>中。(一对多)
动态sql:(重点)
if判断(掌握)
where
foreach
sql片段(掌握)
欢迎关注我的大鱼号:佳云分享
以上是关于MyBatis学习笔记的主要内容,如果未能解决你的问题,请参考以下文章
mybatis学习笔记(14)-spring和mybatis整合
mybatis学习笔记(14)-mybatis整合ehcache