mybatis 常用标签与注解
基本标签与属性
mapper映射文件 xml常用标签
<!--表明这是一个map接口对应的配置文件,
使用的注意事项:配置文件要与接口类在同一包结构下,在maven项目中resource目录就相当于类的class根路径;配置文件要与接口名相同
namespace 属性要指定为接口的全限定类名,这样才能实现配置绑定
-->
<mapper namespace="com.stack.mapper.UserMapper">
</mapper>
<!-- select标签表名为一个查询的sql语句
id 属性要与接口中的对应方法名保持一致,进行绑定
resultType 返回值类型 要求为方法的返回值类型,如果是注册过别名的像String,int等可直接使用别名,没有注册别名的使用全限定类名,如果函数返回值为 void就不需要配置此属性,可以返回结果是一个自定义的实体类型
parameterType 参数类型 要求为方法的参数列表中参数的类型,适合单个参数的情况,如果是注册过别名的像String,int等可直接使用别名,没有注册别名的使用全限定类名。parameterType可以使用自定的包装类型,在多个参数的情况下可以封装成一个pojo实体类进行传递。
-->
<select id="findUserByName" resultType="com.stack.bean.User" parameterType="string">
select * from user where username like #{username}
</select>
<!-- 查询总记录条数 -->
<select id="findTotal" resultType="int">
select count(*) from user;
</select>
补充说明
我们可以通过 resultType来指定我们查询结果要封装到的实体类。如果查询出来的结果是一个实体类集合,我们也只是需要指定结果的实体类型,查询出来的结果集会自动放入集合中,这时候我们只需要在 mapper接口中 方法的声明上指定返回值的类型为 List<***>就可以。
<!-- insert update delete 分别对应我们DML语句中对数据库表中记录增,改,删操作。
id 属性要与接口中的对应方法名保持一致,进行绑定
parameterType 参数类型 要求为方法的参数列表中参数的类型,适合单个参数的情况,如果是注册过别名的像String,int等可直接使用别名,没有注册别名的使用全限定类名。parameterType可以使用自定的包装类型,在多个参数的情况下可以封装成一个pojo实体类进行传递。
这三个标签默认的返回结果是数据受影响的行数,一般不需要使用 resultType直接表明。在接口中对应的方法的返回值可以为 int,void;mybatis会动态去识别绑定。
-->
<insert id="insertUser" parameterType="com.stack.bean.User">
insert into user(username,sex,age) values (#{username},#{sex},#{age})
</insert>
<update id="updateUser" parameterType="com.stack.bean.User">
update user set username=#{username},sex=#{sex},age=#{age} where userid=#{userid}
</update>
<delete id="deleteUser" parameterType="int">
delete from user where userid=#{userid}
</delete>
<!--扩展-->
新增用户后,同时还要返回当前新增用户的 id 值,因为 id 是由数据库的自动增长来实现的,所以就相
当于我们要在新增后将自动增长 auto_increment 的值返回。
<insert id="saveUser" parameterType="USER">
<!-- 配置保存时获取插入的 id -->
<selectKey keyColumn="id" keyProperty="id" resultType="int">
select last_insert_id();
</selectKey>
insert into user(username,birthday,sex,address)
values(#{username},#{birthday},#{sex},#{address})
</insert>
<!--
mybatis通过 resultType封装实体类的前提是实体类字段名要与查询数据库的字段名一致,当我们自己编写的数据库实体类,与查询出来的数据库字段名不一致时,我们有两种解决方式,一种是在查询语句中为列起别名,一种方式是通过 resultMap注解来完成实体类与查询结果的映射
resultMap: type: 全限定类名 id: 别名
id标签绑定的为数据库主键 column 数据库查询结果(别名的影响)字段名 property java实体类的属性名
result为普通列值 column 数据库查询结果(别名的影响)字段名 property java实体类的属性名
-->
<resultMap type="com.stack.bean.User" id="userMap">
<id column="id" property="userId"/>
<result column="username" property="userName"/>
<result column="sex" property="userSex"/>
<result column="address" property="userAddress"/>
<result column="birthday" property="userBirthday"/>
</resultMap>
<!-- 配置查询所有操作 -->
<select id="findAll" resultMap="userMap">
select * from user
</select>
<!--
例如: 一个银行卡账户拥有一个用户,银行卡账号和用户信息分别存储在两张表中,现在我们需要查询所有账户及其关联的用户信息。
面对上述需求,我们在进性编写查询语句时需要通过两张表去做一个连接查询。采用mybatis进行操作时,所要处理的问题点在如何封装结果集。上述需求中一个账户只有一个用户,账户与用户是一对一的关系。
解决方式:
1.我们可以编写一个AccountUser然后继承Account,在此基础上封装一些查询结果所需的字段。组装成一个新的实体类去使用。因为编写了新的实体类,我们就可以向上面一样使用mybatis做比较简单的sql映射。
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money;
//get set方法省略 无参构造省略
}
public class AccountUser extends Account implements Serializable {
private String username;
private String address;
//get set方法省略 无参构造省略
}
<select id="findAll" resultType="com.stack.bean.AccountUser">
select u.*,a.id as aid,a.uid,a.money from account a,user u where a.uid =u.id;
</select>
2.在我们的账户类中包含一个 user 的属性字段去使用。这种情况下就引出来了 <association> 标签来帮助我们完成从表实体属性对应,也就是我们的一对一查询。
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money;
private User user;
//get set方法省略 无参构造省略
}
-->
<mapper namespace="com.stack.dao.IAccountDao">
<!-- 建立对应关系 -->
<resultMap type="com.stack.bean.Account" id="accountMap">
<id column="aid" property="id"/>
<result column="uid" property="uid"/>
<result column="money" property="money"/>
<!-- 它是用于指定从表方的引用实体属性的 -->
<association property="user" javaType="user">
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="sex" property="sex"/>
<result column="birthday" property="birthday"/>
<result column="address" property="address"/>
</association>
</resultMap>
<select id="findAll" resultMap="accountMap">
select u.*,a.id as aid,a.uid,a.money from account a,user u where a.uid =u.id;
</select>
</mapper>
<!--
例如: 一个用户可以拥有多个账户,用户信息和银行卡账号分别存储在两张表中,现在我们需要查询所有用户及其关联的账户信息。
面对上述需求,我们在进性编写查询语句时需要通过两张表去做一个用户表与账户的左外连接查询。采用mybatis进行操作时,所要处理的问题点在如何封装结果集。上述需求中用户可以持有多个账户,是一个一对多的查询关系。
解决方式:
1.在我们的用户类中包含一个账户的list集合的属性字段去使用。这种情况下就引出来了 <collection> 标签来帮助我们完成从表实体属性对应,也就是我们的一对多查询。
public class User implements Serializable {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
private List<Account> accounts;
//get set方法省略 无参构造省略
}
-->
<mapper namespace="com.stack.dao.IUserDao">
<resultMap type="com.stack.bean.User" id="userMap">
<id column="id" property="id"></id>
<result column="username" property="username"/>
<result column="address" property="address"/>
<result column="sex" property="sex"/>
<result column="birthday" property="birthday"/>
<!-- collectiom 用来建立一对多的的映射关系,
property 配置的是实体类中的属性名称
ofType 配置的是属性的实体类型。
-->
<collection property="accounts" ofType="com.stack.bean.Account">
<id column="aid" property="id"/>
<result column="uid" property="uid"/>
<result column="money" property="money"/>
</collection>
</resultMap>
<!-- 配置查询所有操作 -->
<select id="findAll" resultMap="userMap">
select u.*,a.id as aid ,a.uid,a.money from user u left outer join account
a on u.id =a.uid
</select>
</mapper>
补充 多对多的查询
通过上面的 E-R关系图,我们可以看到,一个用户可以拥有多个角色,一个角色也可以拥有多个用户,它们之间通过用户角色表进行关联,是一个多对多的关系。
1.要求查询出用户及其所属的角色信息。
2.要求查询出角色及其关联的角色信息
上述多对多的关系经过分析,我们可以发现可以转换为一对多的关系,一个用户拥有多个角色,一个角色拥有多个用户,只不过是需要经过一张中间表完成转换。我们要做的其实是增加了连接要求,进行了三表连接的查询,查询出来的结果集还是保持着一个一对多的关系,依然采用我们上面用户与账户一对多关系的 实体,采用resultMap 和 collection 这种标签的组合完成我们结果集的封装。
补充 OGNL表达式
sqlMapConfig(mybatis环境配置)常用标签配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--配置数据库信息-->
<environments default="mysql">
<!--数据库编号-->
<environment id="mysql">
<!--配置 jdbc 事务管理器-->
<transactionManager type="JDBC"></transactionManager>
<!--配置数据源 采用mybatis提供的连接池(POOLED,UNPOOLED,JNDL)-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--上面我们在使用 resultType,parameterType 可以直接使用 String , int 等直接类名,对于我们自定义的java类需要使用全限定类名,原因在于mybatis已经自动注册了常用基本类型的别名,我们可以使用 typeAlias来定义我们的类别名,这样的话我们在使用时也可直接使用别名-->
<typeAliases>
<!-- 单个别名定义 -->
<typeAlias alias="user" type="com.itheima.domain.User"/>
<!-- 批量别名定义,扫描整个包下的类,别名为类名(首字母大写或小写都可以) -->
<package name="com.itheima.domain"/>
<package name="其它包"/>
</typeAliases>
<!-- map映射器用来指明xml,sql配置文件所在的位置位置-->
<mappers>
<!--指明单个映射配置文件位置
<mapper resource="com/stack/mapper/UserMapper.xml"></mapper>
-->
<!--指明单个使用的接口类:此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中
<mapper class="com.stack.mapper.UserMapper"></mapper>
-->
<!--常用 指定到包目录下的所有map接口::此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中
<package name="com.stack.mapper"></mapper>
-->
</mappers>
</configuration>
动态sql标签
动态Sql就是我们在处理复杂业务逻辑时,我们的配置文件中的sql语句不在是一层不变的,而是要根据传递的参数条件进行动态的调整改变。这就是我们常说的动态Sql。
<!--
我们根据实体类的不同取值,需要使用不同的sql语句查询。比如用户名不为空时需要根据username模糊查询,地址不为空时需要根据地址进行模糊查询。
通过 if 标签进行简单条件判读,这中情况下使用的 where语句需要恒有一个 where 1=1 来进行条件连接。
-->
<select id="findByUser" resultType="user" parameterType="user">
select * from user where 1=1
<if test="username!=null and username != '' ">
and username like #{username}
</if>
<if test="address != null">
and address like #{address}
</if>
</select>
<!--
通过 where标签可以用来简化上面的where 1=1 的条件。
-->
<select id="findByUser" resultType="user" parameterType="user">
select * from user
<where>
<if test="username!=null and username != '' ">
and username like #{username}
</if>
<if test="address != null">
and address like #{address}
</if>
</where>
</select>
public class QueryVo implements Serializable {
private List<Integer> ids;
public List<Integer> getIds() {
return ids;
}
public void setIds(List<Integer> ids) {
this.ids = ids; }
}
<!--
查询所有用户在 id 的集合之中 我们使用 foreach来进行遍历参数集合进行组装sql
<foreach>标签用于遍历集合,它的属性:
collection:代表要遍历的集合元素,注意编写时不要写#{}
open:代表语句的开始部分
close:代表结束部分
item:代表遍历集合的每个元素,生成的变量名
sperator:代表分隔符
-->
<select id="findInIds" resultType="user" parameterType="queryvo">
select * from user
<where>
<if test="ids != null and ids.size() > 0">
<foreach collection="ids" open="id in ( " close=")" item="uid" separator=",">
#{uid}
</foreach>
</if>
</where>
</select>
动态sql标签我们是可以进行动态组合使用的。
sql的简化
<!-- 抽取重复的语句代码片段 -->
<sql id="defaultSql">
select * from user
</sql>
<!-- 配置查询所有操作 -->
<select id="findAll" resultType="user">
<include refid="defaultSql"></include>
</select>
<!-- 根据 id 查询 -->
<select id="findById" resultType="UsEr" parameterType="int">
<include refid="defaultSql"></include>
where id = #{uid}
</select>
常用注解
在使用注解进行开发时我们不需要去指定 namespace属性,因为注解是直接在接口类中使用,所以默认情况下,namespace已经为所在注解类的全限定类名
package com.stack.mapper;
import com.stack.bean.User;
import org.apache.ibatis.annotations.*;
import java.util.List;
/**
* create by stack on 2020/10/5
* @author Administrator
*/
public interface UserMapAnnotation {
// results 相当于去 resultMap注解
@Results( id="userMap",
value = {
@Result(id = true,column = "userid",property = "userid"),
@Result(column = "username",property = "username"),
@Result(column = "sex",property = "sex"),
@Result(column = "age",property = "age")
}
)
@Select("select * from user")
List<User> findAllUser();
@Select("select * from user where age=#{age} ")
//指定结果集的类型,如果为查询结果为多条数据会自动封装到集合中
@ResultType(value = com.stack.bean.User.class)
List<User> findUserByAge(int age);
@Select("select * from user where username like #{username} ")
// 引用上面定义的 resultMap 属性为上面声明 resultMap的id
@ResultMap("userMap")
List<User> findUserByName(String username);
//默认情况下,结果集的类型为方法的返回值类型
@Select("select * from user where userid=#{userid} ")
User findUserById(int userid);
@Insert("insert into user(username,sex,age) values (#{username},#{sex},#{age})")
int insertUser(User user);
@Update("update user set username=#{username},sex=#{sex},age=#{age} where userid=#{userid}")
int updateUser(User user);
@Delete("delete from user where userid=#{userid} ")
int deleteUser(int userid);
// @one完成 1 对 1的映射关系 fetchType=FetchType.LAZY,采用懒加载策略,懒加载在后面会去说明。在使用@one注解进行一对一映射时,需要配置 select属性指定另一个注解配置的查询语句或者不采用懒加载直接配置sql语句
@Select("select * from account")
@Results(id="accountMap",
value= {
@Result(id=true,column="id",property="id"),
@Result(column="uid",property="uid"),
@Result(column="money",property="money"),
@Result(column="uid",
property="user",
one=@One(select="com.stack.dao.IUserDao.findById",
fetchType=FetchType.LAZY) )
})
List<Account> findAll();
//@many完成复杂的一对多映射关系
@Select("select * from user")
@Results(id="userMap",
value= {
@Result(id=true,column="id",property="userId"),
@Result(column="username",property="userName"),
@Result(column="sex",property="userSex"),
@Result(column="address",property="userAddress"),
@Result(column="birthday",property="userBirthday"),
@Result(column="id",property="accounts",
many=@Many(
select="com.stack.dao.IAccountDao.findByUid",
fetchType=FetchType.LAZY
) )
})
List<User> findAllAccount();
}
补充说明
@Results 注解
代替的是标签****
该注解中可以使用单个@Result 注解,也可以使用@Result 集合
@Results({@Result(),@Result()})或@Results(@Result())
@Resutl 注解
代替了 **标签和**标签
@Result 中 属性介绍:
id 是否是主键字段
column 数据库的列名
property 需要装配的属性名
one 需要使用的@One 注解(@Result(one=@One)()))
many 需要使用的@Many 注解(@Result(many=@many)()))
@One 注解(一对一)
代替了****标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。
@One 注解属性介绍:
select 指定用来多表查询的 sqlmapper
fetchType 会覆盖全局的配置参数 lazyLoadingEnabled。。
使用格式:
@Result(column=" “,property=”",one=@One(select=""))
@Many 注解(多对一)
代替了**<Collection>标签,**是是多表查询的关键,在注解中用来指定子查询返回对象集合。
注意:聚集元素用来处理“一对多”的关系。需要指定映射的 Java 实体类的属性,属性的 javaType
(一般为 ArrayList)但是注解中可以不定义;
使用格式:
@Result(property="",column="",many=@Many(select=""))