接口绑定方案 MyBatis中,提供了一套接口绑定方案,程序员可以提供一个接口,然后提供对应接口的一个mapper.xml文件。
MyBatis会自动将接口和xml文件进行绑定,实际上就是MyBatis会根据接口和对应的xml文件创建接口的实现类。
可以得到实现类的对象。
实现:
映射文件的命名和接口的命名一致
映射文件的namespace写接口的全限定路径
Mapper接口与 Mapper.xml放在同一个包下
mybatis如何通过接口查找对应的mapper.xml及方法执行详解 链接:https://www.jb51.net/article/116402.htm
mybatis中接口文件Mapper和接口配置文件 Mapper.xml不在同一个目录下 1:只有单独的Mybatis没有Spring的情况下
a:首先修改*Mapper.xml中的namespace
1 <mapper namespace="cn.gsm.mkm.dao.UserMapper">
指定到你的*Mapper接口
b:在mybatis总配置文件中指定扫描目标
<mappers>
<mapper resource="cn/gsm/mkm/mapper/UserMapper.xml"></mapper>
<package name="cn.gsm.mkm.dao.UserMapper"></package><!-- 指定具体文件-->
</mappers>
需要注意,这样配置必须指定具体的文件 。否则dom4j解析会报错SAXParseException。
通过接口绑定解决多参数的传递 1)接口中定义方法
1 User selByUP(String username, String password);
映射文件中提供对应的标签. 此时, SQL语句中获取方式
有两种, 通过#{index}或#{param+数字}的方式.
1 2 3 4 5 <select id=*"selByUP"* resultType=*"user"*> select * from t_user where username=#{0} and password=#{1} </select>
2) 接口中定义方法, 参数中使用@Param 注解设定参数名用
于在 SQL 语句中使用.
1 User selByUP(@Param("username") String username, @Param("password") String password);
映射文件中提供对应的标签. 此时, SQL语句中获取方式
有两种, 通过#{参数名称}或#{param+数字}的方式.
1 2 3 4 5 6 7 <select id=*"selByUP"* resultType=*"user"*> select * from t_user where username=#{username} and password=#{password} </select>
动态SQL 根据条件的不同, SQL 语句也会随之动态的改变. MyBatis 中, 提供了一组标签用于实现动态 SQL.
if标签 用于进行条件判断, test 属性用于指定判断条件. 为了拼接 条件, 在 SQL 语句后强行添加 1=1 的恒成立条件.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <select id=*"sel"* resultType=*"user"*> select * from t_user where 1=1 <if test=*"username != null and username != ''"*> and username=#{username} </if> <if test=*"password != null and password != ''"*> and password=#{password} </if> </select>
if标签中的test属性中取值直接写别名,不能用索引或者param+数字取值,也不用#{别名}
1 2 3 4 5 <!-- 5.判断字符串是否等于特定字符(比如此处的user) --> <if test='stringParam != null and stringParam == "user"'></if> <if test="stringParam != null and stringParam != 'user'"></if> <!-- 如果要用这个写法要 --> <if test="stringParam != null and stringParam != 'user'.toString()"></if>
where 标签 用于管理 where 子句. 有如下功能:
a)如果没有条件, 不会生成 where 关键字
b)如果有条件, 会自动添加 where 关键字
c)如果第一个条件中有 and, 去除之
1 2 3 4 5 6 7 8 9 10 11 <select id="sel" resultType="user"> select * from t_user <where> <if test="username != null and username != ''"> and username=#{username} </if> <if test="password != null and password != ''"> and password=#{password} </if> </where> </select>
choose,when,otherwise标签 这是一套标签, 功能类似于 switch…case…default
when只成立一个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <select id=*"sel"* resultType=*"user"*> select * from t_user <where> <choose> <!-- when 只成立一个--> <when test=*"username != null and username != ''"*> and username = #{username} </when> <when test=*"password != null and password != ''"*> and password = #{password} </when> <otherwise> and 1=1 </otherwise> </choose> </where> </select>
Set标签 用于维护 update 语句中的 set 子句. 功能如下:
a)满足条件时, 会自动添加 set 关键字
b)会去除 set 子句中多余的逗号
c)不满足条件时, 不会生成 set 关键字
Trim标签 用于在前后添加或删除一些内容
a)prefix, 在前面添加内容
b)prefixOverrides, 从前面去除内容
c)suffix, 向后面添加内容
d)suffixOverrides, 从后面去除内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <update id=*"updUser"* parameterType=*"user"*> update t_user <!-- prefix: 前缀, 表示向前面添加内容 prefixOverrides: 从前面删除内容 suffix: 后缀, 表示向后面添加内容 suffixOverrides: 从后面删除内容 --> <trim prefix=*"set"* prefixOverrides=*"user"* suffix=*"hahaha"* suffixOverrides=*","*> username=#{username}, </trim> where id=#{id} </update>
bind标签 用于对数据进行再加工, 用于模糊查询
1 2 3 4 5 6 7 8 9 10 <select id="sel" resultType="user"> select * from t_user <where> <if test="username!=null and username!=''"> <!-- 处理username,将值处理后依旧赋值给username --> <bind name="username" value="'%' + username + '%'"/> and username like #{username} </if> </where> </select>
foreach标签 用于在 SQL 语句中遍历集合参数, 在 in 查询中使用
a)collection: 待遍历的集合
b)open: 设置开始符号
c)item: 迭代变量
d)separator: 项目分隔符
e)close: 设置结束符号
1 2 3 4 5 6 7 8 9 10 <select id="selIn" parameterType="list" resultType="user"> select * from t_user where id in <!--collection="list" 指定集合是list--> <foreach collection="list" open="(" separator="," close=")" item="item"> #{item} </foreach> </select> //接口中起别名list List<User> selIn(@Param("list") List<Integer> list);
sql,include标签 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <sql>用于提取 SQL 语句, <include>用于引用 SQL 语句 <sql id="mySql"> id, username, password </sql> <select id="selIn" parameterType="list" resultType="user"> select <!--引用提取的sql语句--> <include refid="mySql"/> from t_user where id in <foreach collection="list" open="(" separator="," close=")" item="item"> #{item} </foreach> </select>
MyBatis的缓存机制 a)缓存用于提高查询的效率.
b)MyBatis的缓存是使用SQL标签的. 执行相同的标签可以使用缓缓存.
c) MyBatis 中有两种缓存机制.
注意:缓存的查询通过id标识,即同一个sql语句(namespace+id)
一级缓存 a)默认开启. 线程级别的缓存, SqlSession 的缓存
b)在一个 SqlSession 生命周期中有效. SqlSession 关闭,
缓存清空.sqlSession对象级别的
二级缓存 a)进程级别的缓存, SqlSessionFactory 的缓存
b)在一个 SqlSessionFactory 生命周期中有效.可以在多个
SqlSession 生命中期中共享.
c)默认关闭, 需要使用的时候, 要为某个命名空间开启二级
缓存(在 mapper.xml 中配置\<cache>.
1 2 <!-- 开启二级缓存, 要求实体类进行序列化 --> <cache />
1 2 <!--readOnly只读,实体类可以不实现序列化接口--> <cache readOnly="true"></cache>
解决列名和属性名不一致问题 如果查询时使用 resultType 属性, 表示采用 MyBatis 的 Auto-Mapping(自动映射)机制, 即相同的列名和属性名会自
动匹配. 因此, 当数据库表的列名和类的属性名不一致时, 会导致查不到数据. 解决该问题可以有两种方式:
列别名 查询时, 可以通过列别名的方式将列名和属性名保持一致, 继续使用自动映射, 从而解决该问题. 但是较为麻烦.
1 2 3 <select id="selAll" resultType="user"> select id id1, username username1, password password2 from t_user </select>
使用\<resultMap> \<resultMap>用于自定义映射关系, 可以由程序员自主制定 列名和属性名的映射关系. 一旦使用 resultMap, 表示不再
采用自动映射机制.
1 2 3 4 5 6 7 8 9 10 11 <!--type实体类,id标识该resultMap--> <resultMap type=*"user"* id=*"umap"*> <!-- id用于映射主键 --> <id column=*"id"* property=*"id1"* /> <!-- 非主键使用result映射 --> <result column=*"username"* property=*"username1"* /> <result column=*"password"* property=*"password1"* /> </resultMap> <select id=*"selAll"* resultMap=*"umap"*> select * from t_user </select>
多表查询 resultMap的N+1方式实现多表查询(多对一) resultMap中的association属性用于关联一个对象
1) property: 指定要关联的属性名
2) select: 设定要继续引用的查询, namespace+id
3) column: 查询时需要传递的列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <resultMap type="Student" id="stumap"> <!-- id用于映射主键 --> <id column="s_id" property="id"/> <!-- 非主键使用result映射 --> <result column="s_name" property="name"/> <result column="s_age" property="age"/> <result column="s_gender" property="gender"/> <result column="s_c_id" property="cid"/> <!-- 用于关联一个对象 property:Student实体类中的属性 select:调用一个查询方法 column:使用哪一列的值作为参数传递到select调用的查询方法 注意:column使用数据库列名s_c_id --> <association property="clazz" select="com.szxy.mapper.ClazzMapper.selById" column="s_c_id"></association> </resultMap>
关联查询 a)在 StudentMapper.xml 中定义多表连接查询 SQL 语句, 一 次性查到需要的所有数据, 包括对应班级的信息.
b)通过resultMap定义映射关系, 并通过association指 定对象属性的映射关系. 可以把association看成一个resultMap使用. javaType 属性表示当前对象, 可以写 全限定路径或别名.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <!-- 关联查询 --> <resultMap type="Student" id="smap"> <id column="sid" property="id"/> <result column="sname" property="name"/> <result column="s_age" property="age"/> <result column="s_gender" property="gender"/> <result column="s_c_id" property="cid"/> <!-- property:Student类的属性名 javaType:是一个类型,Clazz的类型,可以当做association的返回值类型 --> <association property="clazz" javaType="Clazz"> <id column="id" property="id"/> <result column="c_name" property="name"/> <result column="c_room" property="room"/> </association> </resultMap> <select id="selAll" resultMap="smap"> select s_id sid,s_name sname,s_age, s_gender,s_c_id cid,c_name cname,c_room from t_student s left join t_class c on s.s_c_id = c_id </select>
resultMap的N+1方式实现多表查询(一对多) 提供 ClazzMapper 和 StudentMapper, ClazzMapper 查询所有
班级信息, StudentMapper 根据班级编号查询学生信息.
在 ClazzMapper 中使用\<collection>设置装配.
a)\<collection>用于关联一个集合
property: 指定要关联的属性名
select: 设定要继续引用的查询, namespace+id
column: 查询时需要传递的列
1 2 3 4 5 6 7 8 9 10 11 <!-- N+1多对一查询 --> <resultMap type="Clazz" id="cmap"> <id column="c_id" property="id"/> <result column="c_name" property="name"/> <result column="c_room" property="room"/> <!-- 关联一个集合 --> <collection property="stus" select="com.szxy.mapper.StudentMapper.selByCid" column="c_id"></collection> </resultMap> <select id="selAll" resultMap="cmap"> select * from t_class </select>
resultMap的关联方式实现多表查询(一对多) a)在 ClazzMapper.xml 中定义多表连接查询 SQL 语句, 一次 性查到需要的所有数据, 包括对应学生的信息.
b)通过\<resultMap>定义映射关系, 并通过\<collection>指 定集合属性泛型的映射关系. 可以把\<collection>看成一
个\<resultMap>使用. ofType 属性表示集合的泛型 , 可以 写全限定路径或别名.
注:colletion关联一个集合
1)property: Clazz类中的stus属性名
2)javaType: Clazz类中的stus属性的类型
3)ofType:stus属性是List集合,指定泛型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <!-- 关联查询(多对一) --> <resultMap type="Clazz" id="clzmap"> <id column="cid" property="id"/> <result column="cname" property="name"/> <result column="croom" property="room"/> <!-- 关联一个集合 ofType:集合的泛型 --> <collection property="stus" javaType="list" ofType="Student"> <id column="sid" property="id"/> <result column="sname" property="name"/> <result column="sage" property="age"/> <result column="sgender" property="gender"/> <result column="cid" property="cid"/> </collection> </resultMap> <select id="selAll2" resultMap="clzmap"> select c.c_id cid,c.c_name cname, c_room croom,s.s_id sid, s.s_name sname,s.s_age sage,s.s_gender sgender from t_class c left join t_student s on c.c_id = s.s_c_id </select>
通过Auto-Mapping实现多表查询(多对一) a)通过 MyBatis 的 Auto-Mapping 机制及数据库查询时的别 名结合, 可以方便的实现多表查询.
b)SQL 语句中, 别名出现特殊符号时, 必须进行处理. MySQL 可以使用(
)符号, Oracle 可以使用(“”)符号.
1 2 3 4 5 6 7 8 9 <!-- AutoMapping 将别名使用属性名.属性来进行自动映射 --> <select id="selAutoMapping" resultType="Student"> select s_id id,s_name name,s_age age,s_gender gender,s_c_id cid,s_c_id `clazz.id`,c_name `clazz.name`,c_room `clazz.room` from t_student s left JOIN t_class c on s.s_c_id = c.c_id </select>
注解开发 a)注解是用于描述代码的代码. 例如: @Test(用于描述方法
进行 junit 测试), @Override(用于描述方法的重写), @Param(用于描述属性的名称)
b)注解的使用风格: @xxx(属性), 使用前必须先导包
c)使用注解一般用于简化配置文件. 但是, 注解有时候也不 是很友好(有时候反而更麻烦), 例如动态 SQL.
d)关于注解的属性
属性的设定方式是: 属性名=属性值
e)关于属性值的类型
基本类型和 String, 可以直接使用双引号的形式
数组类型, name={值 1, 值 2, …}; 如果数组元素只有
一个, 可以省略大括号
对象类型, name=@对象名(属性)
如果属性是该注解的默认属性, 而且该注解只配置这
一个属性, 可以将属性名省略
f)注解和配置文件可以配合使用
1 2 3 4 5 6 7 8 9 10 11 @Select("select * from t_student") List<Student> selAll(); @Insert(value = {"insert into t_student values(default,#{name},#{age},#{gender},#{cid})"}) int insStu(Student student); @Update(value = {"update t_student set s_age = #{age} where s_id = #{0}"}) int updStu(int id, @Param("age")int age); @Delete("delete from t_student where s_id = #{0}") int delStu(int id);
其他注解
1 2 3 4 5 6 7 @Results: 类似于<resultMap> @Result: 类似于<resultMap>的子标签 @One: 类似于<association> @Many: 类似于<collection>
@One
1 2 3 4 5 6 7 8 9 10 11 12 13 14 //N+1查询 @Select("select * from t_student") @Results(value = { @Result(column = "s_id", property = "id",id = true), @Result(column = "s_name", property = "name"), @Result(column = "s_age", property = "age"), @Result(column = "s_gender", property = "gender"), @Result(column = "s_c_id", property = "cid"), @Result(property = "clazz", one = @One(select = "com.szxy.mapper.ClazzMapper.selById"), column = "s_c_id" ) }) List<Student> sel();
@Many
1 2 3 4 5 6 7 8 9 10 11 @Select("select * from t_class") @Results(value = { @Result(column = "c_id", property = "id", id = true), @Result(column = "c_name", property = "name"), @Result(column = "c_room", property = "room"), @Result(property = "stus", many = @Many(select = "com.szxy.mapper.StudentMapper.selByCid"), column = "c_id" ) }) List<Clazz> selClz();
MyBatis运行原理 运行过程中涉及到的类或接口 1)Resources(C)
用于加载 MyBatis 核心配置文件
2)XMLConfigBuilder(C)
用于解析 xml 文件(核心配置文件)
3) Configuration(C)
用于存放 xml 文件解析后的结果
4)DefaultSqlSessionFactory(C)
是 SqlSessionFactory(I)的 实 现 类 , 创 建 时 需 要 使 用
Configuration 对象
5) SqlSession(I)
是 MyBatis 操作的核心
6)DefaultSqlSession(C)
是 SqlSession 接口的实现类
7) TransactionFactory(I)
用于生产 Transaction 对象
8) Transaction(I)
用于表示操作数据库的事务对象
9)Executor(I)
是 MyBatis 的核心执行器, 类似于 jdbc 中的 Statement, 常 用的实现类是 SimpleExecutor
描述 当Mybatis运行开始时,先要通过Resources加载核心配置文件,之后使用XmlConfigBuilder对配置文件进行
解析,将解析结果封装为Configuration对象。接着,使用Configuration对象构建一个DefaultSqlSessionFactory
对象,至此,SqlSession工厂构建完成。
接下来,通过工厂对象调用openSession方法创建SqlSession对象。在这个过程中,需要通过TransactionFactory
生产一个Transaction对象,并且,还需要创建核心执行器Executor对象。之后,通过这些对象来创建DefaultSqlSession对象,至此,SqlSession对象创建成功。
之后,通过SqlSession对象执行相应的操作。如果执行成功,调用commit()方法提交事务;如果失败,调用rollback()方法进行事务回滚。最后,调用close()方法关闭SqlSession资源,以上,就是MyBatis的运行原理。