...敬请期待session
经过上一篇的入门MyBatis学习笔记(1)—使用篇,能够发现除了一些基本配置外,Mybatis的精华就在于Mapper(映射)部分。Mybatis是针对映射器构造的SQL构建的轻量级框架,而且能够经过配置生成对应的JavaBean给调用者。在Mybatis中能够灵活使用SQL来知足各类不一样场景的需求,因此在互联网企业内更偏心于使用Mybatis来应对高速变化的需求,而传统企业更偏向于使用Hibernate。mybatis
上一节咱们仅仅定义了一个select语句:app
<mapper namespace="com.shuqing28.dao.CommodityDao">
<select id="getAllCommodity" resultType="com.shuqing28.pojo.Commodity">
SELECT * FROM commodity
</select>
</mapper>
复制代码
实际上增删改查在Mybatis映射器里面都有对应的元素框架
元素名称 | 描述 | 备注 |
---|---|---|
select | 查询语句,最经常使用的 | 能够自定义参数,返回结果集 |
insert | 插入语句 | 执行后返回一个整数,表明插入的条数 |
update | 更新语句 | 执行后返回一个整数,表明更新的条数 |
delete | 删除语句 | 执行后返回一个整数,表明删除的条数 |
parameterMap | 定义参数映射关系 | 即将被删除的元素,不建议使用 |
sql | 容许定义一部分的SQL,而后在各个地方引用 | 例如,定义一个表名,在其它地方的SQL语句中使用 |
resultMap | 用来描述从数据库结果集中加载对象 | 它将提供映射规则 |
cache | 给定命名空间的缓存配置 | ———— |
cache-ref | 其余命名空间缓存配置的引用 | ———— |
下面咱们探究主要使用的几个元素post
select元素是咱们最经常使用的元素,正如在SQL里是查询功能也是最主要的功能之一。在咱们常识里,查询语句一般都是根据一个或者多个条件,查询数据库返回一个,多个或者全部字段。以前咱们举得getAllCommodity
没有查询条件,返回全部字段。学习
在Mybatis里,咱们能够传入简单的参数类型,像int,float,String这些,也能够传入一些复杂的类型,好比JavaBean、Map之流的,Mybatis把这些参数转换成SQL语句须要的类型后,返回结果,而且经过映射,将结果集自动绑定到JavaBean中,因此JDBC里面那一套一个一个从ResultSet获取值的操做都被省略了。
下面咱们看一个有参数的select语句:
<select id="getCommodityById" parameterType="int" resultType="com.shuqing28.pojo.Commodity">
SELECT * FROM commodity where id=#{id}
</select>
复制代码
同时咱们定义了接口方法:
Commodity getCommodityById(Integer id);
复制代码
不一样于getAllCommodity
没有传入参数,getCommodityById
有一个int类型的传入参数,返回的仍是Commodity。 上面的select语句包含如下属性:
这里看resultType,咱们查询的是commodity的全部字段,再次回顾字段定义:
字段名 | 类型 |
---|---|
id | int |
name | varchar(255) |
price | decimal(8,2) |
description | varchar(255) |
而咱们的POJO类包含:
private Integer id;
private String name;
private Double price;
private String description;
复制代码
这里Mybatis帮咱们完成了自动映射,只要返回的SQL列名和JavaBean的属性一致,Mybatis就能够帮助咱们自动回填这些字段而无需任何配置。咱们能够再Mybatis的配置文件里,经过autoMappingBehavior来设置自动映射,它包含3个值:
刚才咱们举例的是只传递了一个参数,若是传递多个参数呢?这时候就要说说输入映射了。
传递多个参数一般来讲有3种方式,经过Map,经过注解,以及经过POJO对象
假设咱们想查询带有饼的食物,而且价格低于80的。那么咱们能够这么写SQL语句
<select id="getCommodityByMap" parameterType="map" resultType="com.shuqing28.pojo.Commodity">
SELECT * FROM commodity WHERE name like '%${name}%' AND price<#{price}
</select>
复制代码
由于mybatis使用xml定义Mapper,因此这里'<'用了转义符<
表示,其实仍是同样的。 parameterType定义为map,咱们定义的接口也是接受Map做为参数
List<Commodity> getCommodityByMap(Map<String, Object> params);
复制代码
使用:
CommodityDao commodityDao = sqlSession.getMapper(CommodityDao.class);
Map<String, Object> paramsMap = new HashMap<String , Object>();
paramsMap.put("name", "饼");
paramsMap.put("price", 80.0);
List<Commodity> commodities = commodityDao.getCommodityByMap(paramsMap);
复制代码
最后打印commodities:
[Commodity{id=1001, name='野葡萄烤饼', price=10.0, description='吃完还有点饿'}, Commodity{id=1003, name='南瓜百吉饼', price=50.0, description='份大量足,能够去很远的地方'}]
复制代码
虽然Map很简单,可是光是看传入参数Map,你不知道包含了怎样的内容,如果深刻还得看如何设置Map的,并且使用时还要一项项指定Map的Key的名字,因此不怎么提倡使用了。
注解方式使用了**@Param**注解,咱们这样定义接口:
List<Commodity> getCommodityByAnnation(@Param("name") String name, @Param("price") Double price);
复制代码
Mybatis根据@Param提供的名称,把变量值传到SQL语句中对应的参数中,参数的可读性大大提升,可是不足之处在于,如果参数不少,一个一个写很麻烦,下降了可读性。
因此最常用的仍是利用POJO传递参数。
一般咱们只须要传递简单的POJO对象就能够了,好比咱们这样定义select元素:
<select id="getCommodityByPOJO" parameterType="com.shuqing28.pojo.Commodity" resultType="com.shuqing28.pojo.Commodity">
SELECT * FROM commodity WHERE name like '%${name}%' AND price<#{price}
</select>
复制代码
测试:
@Test
public void getLowPriceCommodityByPOJO(){
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
CommodityDao commodityDao = sqlSession.getMapper(CommodityDao.class);
Commodity commodity = new Commodity();
commodity.setName("饼");
commodity.setPrice(80.0);
List<Commodity> commodities = commodityDao.getCommodityByPOJO(commodity);
System.out.println(commodities);
} finally {
sqlSession.close();
}
}
复制代码
也会返回和上面同样的结果,这里Mybatis会把POJO里对应的属性值传到SQL里,而后返回结果,注意看传入参数就是POJO的彻底限定名,和ResultType是同样的,其实能够经过别名减小名称的长度,咱们只须要在mybatis-config.xml
中的configuration中定义:
<typeAliases>
<typeAlias alias="commodity" type="com.shuqing28.pojo.Commodity" />
</typeAliases>
复制代码
就能够用commodity替换全部的全称了,可是不能有重名的,不然会出错。
有些负责的状况,咱们须要定义POJO做为查询参数,好比上面的例子,你只须要两个输入参数,你也能够定制一个只包含这两个参数的POJO。
public class CommodityCustom {
private String name;
private Double price;
复制代码
固然使用过程仍是同样的,定义本身包装过的POJO一般用来解决传入查询条件很复杂的状况,好比设计到几张表联查的,这时候原先定义的POJO解决不了问题,就须要定义一些复合的POJO。
在输入参数中还有个常常被提到的问题,即#和$的区别
Mybatis自己是基于JDBC封装的。因此#{para}
是预编译处理(PreparedStatement
),至关于原来的?
,而${para}
是字符串替换。Mybatis在处理#时,会调用PreparedStatement
的set
系列方法来赋值;处理$
时,就是把${para}
替换成变量的值。#
方式可以很大程度防止sql
注入,$
方式通常用于传入数据库对象,例如传入表名,通常能用#
的就别用$
.
说完输入咱们说输出映射。
MyBatis的输出映射分为两种方式,resultType和resultMap
咱们上面全部的例子里都是定义的resultType,resultType能够是简单类型,好比咱们想获取商品数量啊之类的,还有就是输出POJO对象或者POJO列表。
不论是POJO对象仍是POJO列表,咱们在resultType中的定义都是同样的,只不过接口定义不同:
Commodity getCommodityById(Integer id);
复制代码
Mybatis根据接口返回值判断返回一条对象,若是用过ibatis的能够知道内部调用了session.selectOne。
List<Commodity> getCommodityByPOJO(Commodity commodity);
复制代码
内部使用session.selectList,Mapper接口使用List<XXX>
做为返回值。
查询出来的列名和POJO属性只要有一个一致就会建立POJO对象,顶多别的字段为默认值,可是若是所有不一致,就不会建立该POJO对象了。
上面的resultType在查询的列名和POJO属性值一致的时候才能够映射成功,若是不一致的话,就须要resultMap登场表演了。
若是查询出来的列名和POJO的属性名不一致,经过定义一个resultMap对列名和POJO属性名之间做一个映射关系。
在使用resultMap前咱们须要定义resultMap 假设咱们查询商品类的两个字段id和name,可是查询的时候定义为id_
和name_
。列名和属性名不一致了,先定义resultMap
<resultMap id="commodityResultMap" type="commodity">
<id column="id_" property="id"/>
<result column="name_" property="name"/>
</resultMap>
复制代码
其中
再看咱们的select元素:
<select id="getCommodityByPrice" parameterType="double" resultMap="commodityResultMap">
SELECT id id_, name name_ FROM USER WHERE price=#{price}
</select>
复制代码
使用resultType进行输出映射时,只有查询出来的列名和pojo中的属性名一致,该列才能够映射成功。若是查询出来的列名和pojo的属性名不一致,经过定义一个resultMap对列名和pojo属性名之间做一个映射关系。 此外,resultMap还能够作一对多、多对多等高级映射,这些内容将在后续文章中介绍。
insert相对于select简单不少,下面是往商品表插入一个商品的实例:
<insert id="insertCommodity" useGeneratedKeys="true"
keyProperty="id">
insert into commodity (name,price,description)
values (#{name},#{price},#{description})
</insert>
复制代码
接口为:
void insertCommodity(Commodity commodity);
复制代码
这里咱们注意到了insert语句里多了两个属性useGeneratedKeys
和keyProperty
,这里涉及到的是主键回填的概念。
@Test
public void insertCommodity(){
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
CommodityDao commodityDao = sqlSession.getMapper(CommodityDao.class);
Commodity commodity = new Commodity();
//commodity.setId(1005);
commodity.setName("艾蒿小麦饼");
commodity.setPrice(100.0);
commodity.setDescription("像在艳阳下恋爱");
commodityDao.insertCommodity(commodity);
System.out.println(commodity.getId());
} finally {
sqlSession.close();
}
}
复制代码
经过打印咱们能获得1005
,说明commodity已经具有了id,这就是回填的效果。 在这里,系统默认的方式是给主键值加1,若是咱们想要定义本身的主键生成方式,可使用selectKey进行自定义:
<insert id="insertCommodity" useGeneratedKeys="true"
keyProperty="id">
<selectKey keyProperty="id" resultType="int" order="BEFORE">
select if (max(id) is null, 1, max(id) + 2) as newId from commodity
</selectKey>
insert into commodity (name,price,description)
values (#{name},#{price},#{description})
</insert>
复制代码
这里咱们定义主键值是最大id加2,若是尚未记录,则初始化为1。
update和的delete都会返回影响的条目数 下面仅仅列出配置的实例:
<update id="updateCommodity" parameterType="commodity">
update commodity set
name=#{name},
price=#{price},
description=#{description}
where id=#{id}
</update>
<delete id="deleteCommodity" parameterType="int">
delete from commodity where id=#{id}
</delete>
复制代码
这一节主要介绍了主要的几个语句的使用,着重介绍了select语句,同时结合select语句说明了Mybatis中输入映射和输出映射的内容,其它一些高级的映射内容,留到后面的文章介绍。