一、别名
1.作用
MyBatis提供了别名机制可以对某个类起别名或给某个包下所有类起别名,简化resultType取值的写法。
2.明确指定别名
通过<typeAlias>
标签明确设置类型的别名。
type:类型全限定路径。
alias:别名名称。
指定别名方式优点和缺点:
优点:别名可以设置为单个字母,以后使用别名时比较方便。
缺点:当需要定义别名的类比较多时,定义别名是个较大工程量。
1.在mybatis.cfg.xml全局配置文件中,添加下面配置
<!-- 按照DTD顺序要求:typeAliases放在properties下面,environments上面 -->
<typeAliases>
<!-- type:类型全限定路径 alias:别名名称 -->
<typeAlias type="com.pojo.People" alias="p"></typeAlias>
<typeAlias type="com.pojo.People" alias="p2"></typeAlias>
</typeAliases>
2.在mapper中的resultType中使用别名,类全限定路径方式也可以使用。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="a.b.c">
<select id="list" resultType="p">
select * from people
</select>
<select id="list2" resultType="p2">
select * from people
</select>
<select id="list3" resultType="com.bjsxt.pojo.People">
select * from people
</select>
</mapper>
运行测试类,发现3个查询都可以成功执行。这也说明了:
(1)一个类可以有多个别名
(2)设置别名后,类的全限定路径依然可以使用。
(3)尝试修改resultType="p"中p为大写的P,依然运行成功。说明在明确配置别名时不区分大小写。
3.指定所有类别名
通过<package>
标签指定包下全部类的别名。
在mybatis.cfg.xml中指定包
<!-- 指定包 -->
<package name="com.bjsxt.pojo"/>
4.MyBatis内置别名
MyBatis框架中内置了一些常见类型的别名。这些别名不需要配置
别名 | 映射的类型 | 别名 | 映射的类型 | 别名 | 映射的类型 | ||
---|---|---|---|---|---|---|---|
_byte | byte | string | String | date | Date | ||
_long | long | byte | Byte | decimal | BigDecimal | ||
_short | short | long | Long | bigdecimal | BigDecimal | ||
_int | int | short | Short | object | Object | ||
_integer | int | int | Integer | map | Map | ||
_double | double | integer | Integer | hashmap | HashMap | ||
_float | float | double | Double | list | List | ||
_boolean | boolean | float | Float | arraylist | ArrayList | ||
boolean | Boolean | collection | Collection | ||||
iterator | Iterator |
二、接口绑定方案
1.接口绑定的意义
MyBatis提供了一种接口绑定方案,通过SqlSession的getMapper方法产生接口的动态代理对象。然后通过对象调用接口中提供的功能。
2.方案流程
1.创建项目并配置pom.xml
需要导入MyBatis框架依赖和数据库驱动。
<dependencies>
<!-- MyBatis 框架依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
<!-- 数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
</dependencies>
2.配置全局配置文件
在resources中创建mybatis.cfg.xml
<mappers>
<!-- 此处换为package,里面写接口和映射文件所在的包 -->
<package name="com.bjsxt.mapper"/>
</mappers>
3.创建实体类
public class People {
private int id;
private String name;
//get,set方法重写tostring,有参、无参构造
}
4.创建接口
按照MyBatis的规范,接口应该放在mapper包中。每个接口中编写对某个表的访问,且接口名称以Mapper结尾
package com.mapper;
import com.bjsxt.pojo.People;
import java.util.List;
public interface PeopleMapper {
List<People> selectAll();
}
5.映射文件
在接口绑定方案中,对于映射文件有几点强制要求:
映射文件和接口需要在同一个包中
映射文件名称要和接口名称相同
namespace取值必须是接口的全限定路径
id属性值必须和方法名对应
resultType必须和方法返回值类型对应。如果方法返回值是集合类型,resultType中写泛型的类型
新建PeopleMapper.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjsxt.mapper.PeopleMapper">
<select id="selectAll" resultType="People">
select * from people
</select>
</mapper>
6.添加资源拷贝插件
由于映射文件添加到了com.bjsxt.mapper包中,所以需要添加资源拷贝插件,保证映射文件能被编译。 资源拷贝插件配置的主要目的是为了让src/main/java下映射文件能被编译时包含。
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
三、接口绑定方案下参数传递
在接口绑定方案中唯一需要重点注意的是:
当方法带有多个参数将使用session.selectList("",Map类型参数)或session.selectOne("",Map类型参数)作为底层调用。
Mybatis自动创建Map的key:
如果接口中方法没有使用注解定义名称,MyBatis使用内置名称作为key。
规则:arg0、arg1、argM(M为从0开始的数字,和方法参数顺序对应)或param1、param2、paramN(N为从1开始的数字,和方法参数顺序对应)。
也可以在接口方法参数中通过@Param("key名称")的形式进行定义key。一定使用了注解argN的这种形式就不能使用了,但是paramN的方式还是可以使用。
使用注解定义参数名称
在接口中添加新方法.@Param("key的名称")中key的名称是自定义的,与方法参数名没有关系。接口中方法的参数前可以加注解,也可以不加注解,也可以部分加注解部分不加注解。
注意:
使用注解方式时,在映射文件中argN的方式就不能使用了,但是paramN的方式还是可以使用,#{paramN}和#{key}的方式也可以混合使用
多个参数企鹅包含对象类型参数
多个对象类型参数,还是多个参数里面有对象和简单数据类型调用方式都是和上面相同。按照顺序分别为paramN或param1。如果这个参数是简单数据类型直接通过paramN或argM的方式调用,如果这个参数是对象通过paramN.属性名或argN-1.属性名可以调用对象中的属性。
// 需要使用peo中id,name,peo2的address
List<People> select3(People peo,String name,@Param("peo2") People peo2);
<select id="select3" resultType="People">
select * from people where id=#{arg0.id} and name=#{arg1} and address=#{peo2.address}
</select>
在映射文件中添加标签,与接口中的方法进行绑定。
People peo:可以通过arg0、param1两种方式获取到。arg0.属性名、param1.属性名获取对象的属性。
String name:可以通过arg1、param2两种方式获取到。
People peo2:可以通过peo2、param3两种方式获取到。peo2.属性名、param3.属性名获取对象属性。
四、主键回填
在一些特殊的需求中,需要执行完新增的SQL后立即知道新增时主键的值。如果主键的值是自己设置的固定值,可以知道主键的值。
MyBatis中有两种方式可以获取到自增主键的值:
使用
<selectKey>
子标签编写SQL进行回填属性值。使用
<select>
的useGeneratedKeys属性值进行自动回填。
1.selectKey使用
1.在接口中添加方法
// 参数peo中包含了name值和address值。
int insert1(People peo);
int insert2(People peo);
2.在映射文件中添加标签
在映射文件中添加标签与接口中方法进行绑定。
<selectKey>
标签是<insert>
的子标签,作用:把查询到的结果填充进行回填。keyProperty:接口方法参数中,对象的哪个属性需要进行回填。
resultType:SQL查询到的结果类型。
select @@identity:是MySQL内置的全局变量表示获取到自增主键值。
order:selectKey中SQL是在添加SQL执行之前还是之后执行。可取值:AFTER和BEFORE。
<insert id="insert1">
<selectKey keyProperty="id" resultType="int">
select @@identity
</selectKey>
insert into people values(default,#{name},#{address})
</insert>
2.自动主键回填
MyBatis的映射文件的<insert>
标签带有自动主键回填功能,只需要设置useGeneratedKeys进行开启自动主键回填功能,同时设置keyProperty的值需要回填到对象的哪个属性。
<insert id="insert2" useGeneratedKeys="true" keyProperty="id">
insert into people values(default,#{name},#{address})
</insert>
五、动态SQL
MyBatis在简化操作方法中提出了动态SQL功能,将使用Java代码拼接SQL语句,改变为在XML映射文件中截止标签拼接SQL语句。相比而言,大大减少了代码量,更灵活、高度可配置、利于后期维护。MyBatis中动态SQL是编写在mapper.xml中的,其语法和JSTL类似,但是却是基于强大的OGNL表达式实现的。
1.if标签
通过if处理用户多变的查询条件
List<People> selectIf(People people);
mapper映射文件通过if进行判断参数的属性是否为null。
<if>
标签的test属性值为OGNL(对象导航图语言)表达式,通过对象属性名可以快速获取到对象属性值。
<select id="selectIf" resultType="People">
select * from people where 1=1
<if test="name!=null">
and name=#{name}
</if>
<if test="address!=null">
and address=#{address}
</if>
</select>
name!=null : OGNL 表达式,直接写属性名可以获取到属性值。不需要添加${}或#{}。
name=#{name} 中name是表中的列名。#{name}是MyBatis获取参数对象属性值的写法(之前学习的)。
where 1=1 中1=1是为了保证SQL语法的正确性。如果if成立没有1=1最后的SQL就是where and name=xxx 这种写法是不对的
2.choose
choose标签相当于Java中的switch...case....default。在choose标签里面可以有多个when标签和一个otherwise(可以省略)标签。只要里面有一个when成立了后面的when和otherwise就不执行了。
<select id="selectIf" resultType="People">
select * from people where 1=1
<choose>
<when test="name!=null">
and name=#{name}
</when>
<when test="address!=null">
and address=#{address}
</when>
<otherwise>
// do something
</otherwise>
</choose>
</select>
3.trim标签
trim标签包含四个属性:
prefix:只要子内容不是空字符串(""),就在子内容前面添加特定字符串。
prefixOverrides:如果子内容是以某个内容开头,去掉这个内容。
suffix:只要内容不是空字符串(""),就在子内容后面添加特定字符串。
suffixOverrides:如果里面内容以某个内容结尾,就去掉这个内容
<select id="selectIf" resultType="People">
select * from people <!-- 子串 -->
<trim prefix="where" prefixOverrides="and">
<if test="name!=null">
and name=#{name}
</if>
<if test="address!=null">
and address=#{address}
</if>
</trim>
</select>
注:
trim作为很多其它标签的底层。无论是开头操作还是结尾的操作,都是先去掉容,后添加。
trim只会对里面的子内容进行操作。如果子内容为空则不进行任何操作。后添加的内容会有空格。
4.where标签
where标签属于trim标签的简化版,被where标签包含的内容具备:
-
如果里面内容不为空串,在里面内容最前面添加where。
-
如果里面内容是以and开头,去掉最前面的and。
<select id="selectIf" resultType="People">
select * from people
<where>
<if test="name!=null">
and name=#{name}
</if>
<if test="address!=null">
and address=#{address}
</if>
</where>
</select>
5.set标签
et标签是专门用在修改SQL中的,属于trim的简化版,带有下面功能:
-
如果子内容不为空串,在最前面添加set。
-
去掉最后一个逗号。
<update id="update">
update people
<set>
<if test="name!=null">
name=#{name},
</if>
<if test="address!=null">
address=#{address},
</if>
id=#{id}
</set>
where id = #{id}
</update>
6.foreach标签
foreach标签表示循环,主要用在in查询或批量新增的情况。
<select id="selectByIds" resultType="People">
select * from people where id in
<foreach collection="array" open="(" close=")" item="id" separator=",">
#{id}
</foreach>
</select>
foreach标签的属性解释说明:
collection:要遍历的数组或集合对象。
1. 如果参数没有使用@Param注解:arg0或array或list。
2. 如果使用@Param注解,使用注解的名称或param1。
open:遍历结束在前面添加的字符串。
close:遍历结束在后面添加的字符串。
item:迭代变量。在foreach标签里面#{迭代变量}获取到循环过程中迭代变量的值。
separator:分隔符。在每次循环中间添加的分割字符串。
index:迭代的索引。从0开始的数字。
nullable:是否允许数组或集合对象为null。如果设置为true,表示集合或数组允许为null。如果设置为false表示不允许数组或集合对象为null,一旦为null会出现:org.apache.ibatis.builder.BuilderException: The expression 'array' evaluated to a null value。
7.bind标签
bind标签表示对传递进来的参数重新赋值。最多的使用场景为模糊查询。通过bind可以不用在Java代码中对属性添加%。
<select id="selectLike" resultType="People">
<bind name="name" value="'%'+name+'%'"/>
select * from people where name like #{name}
</select>
8.sql和include标签
很多功能或SQL都需要使用这些列的话,其实在做很多重复工作。即使复制粘贴,一旦碰到表结构改变或添加、删除列的时候也需要修改很多SQL。MyBatis的sql标签用于定义SQL片段,include标签用于引用sql标签定义的片段。
<sql id="mysqlpart">
id,name,address
</sql>
<select id="selectSQL" resultType="People">
select <include refid="mysqlpart"></include> from people
</select>
六、MyBatis中常用注解
1.介绍
MyBatis中对于特别简单的SQL、尤其不需要定义resultMap的SQL可以使用注解进行实现。通过注解能简化映射文件的编写。
注解 | 解释 |
---|---|
@Select | 查询 |
@Insert | 新增 |
@Delete | 删除 |
@Update | 修改 |
@SelectKey | 主键回填 |
@SelectProvider | 调用SQL构建器。查询专用 |
@DeleteProvider | 调用SQL构建器。删除专用 |
@UpdateProvider | 调用SQL构建器。修改专用 |
@INSERTProvider | 调用SQL构建器。删除专用 |
@Param | 定义参数的名称 |
public interface PeopleMapper {
@Select("select * from people")
List<People> selectAll();
@Insert("insert into people values(default,#{name},#{address})")
int insert(People peo);
@Delete("delete from people where id=#{id}")
int deleteById(int id);
@Update("update people set name=#{name},address=#{address} where id=#{id}")
int updateById(People peo);
}
2.主键回填
使用注解时,主键回填需要通过@SelectKey注解。
该注解中:必有属性
keyProperty:表示回填属性名。
statement:执行的sql。
before:表示是否在@Insert的SQL之前执行。
resultType:表示statement对应SQL执行结果
@Insert("insert into people values(default,#{name},#{address})")
@SelectKey(keyProperty = "id",statement = "select @@identity",before = false,resultType = Integer.class)
int insert2(People people);
3.SQL构建起(Provider)
的SQL构建器赋予了程序员在Java类中编写SQL的方式。把以前写在注解参数中的复杂SQL转移到了类的方法中进行书写。
在接口中提供方法。并在方法上面添加@SelectProvider注解,注解中属性含义:
-
type:编写SQL的类。
-
method:类中哪个方法返回SQL。
3.1 直接写SQL方式代码演示
@SelectProvider(type = MySQLProvider.class,method = "selectprovider")
List<People> select(People peo);
返回SQL的方法必须是public String的。
public class MySQLProvider {
public String selectprovider(){
return "select *" +
" from people" +
" where name=#{name} and address like #{address}" +
" order by id desc";
}
}
3.2使用SQL类
MyBatis提供了SQL类,该类中封装了很多方法,方法名称和SQL的关键字名称正好对应。
里面需要注意的点:
-
如果多个条件可以放在一个where中,也可以放在多个连续where中(放在多个where方法中不需要and关键字)。
-
最终需要调用toString()转换为字符串
public class MySQLProvider {
public String selectprovider2(){
return "select *" +
"from people" +
"where name=#{name} and address like #{address}" +
"order by id desc";
}
public String selectprovider(){
return new SQL()
.SELECT("*")
.FROM("people")
.WHERE("name=#{name}")
// 没有and,多个并列条件使用WHERE方法
.WHERE("address like #{address}")
.ORDER_BY("id desc")
.toString();
}
}
4.使用注解进行结果映射
@Results的value属性类型Result[]。
@Result注解:
column:数据库列
property:属性名
id:是否为主键,默认false
@Results(value = {
@Result(column = "peo_id",property = "id",id = true),
@Result(column = "peo_name",property = "name")
})
@Select("select * from tb_people where peo_name=#{name}")
List<People> select2(People peo);