MyBatis 学习
一、 什么是mybaits
- mybatis是一款性能持久化工具,它的性能接近原生,主要特点是支持定制化的sql语句,普通的增删改查语句根本不用写(很多框架都能实现)
- 是基于sql语句的一种框架
- mybatis 的SQL语句灵活,能够完成很复杂的查询语句
二、 mybatis优点
- 性能优秀,接近原生的JDBC
- sql语句灵活
- 结果集映射灵活
三、 Mybaits配置文件
3.1 分层
3.2 mybatis的执行流程
体系结构
mybatis配置文件,包括Mybatis全局配置文件和Mybatis映射文件,其中全局配置文件配置了数据源、事务等信息;映射文件配置了SQL执行相关的 信息。
- mybatis通过读取配置文件信息(全局配置文件和映射文件),构造出SqlSessionFactory,即会话工厂。
- 通过SqlSessionFactory,可以创建SqlSession即会话。Mybatis是通过SqlSession来操作数据库的。
- SqlSession本身不能直接操作数据库,它是通过底层的Executor执行器接口来操作数据库的。Executor接口有两个实现类,一个是普通执行器,一个是缓存执行器(默认)。
- Executor执行器要处理的SQL信息是封装到一个底层对象MappedStatement中。该对象包括:SQL语句、输入参数映射信息、输出结果集映射信息。其中输入参数和输出结果的映射类型包括java的简单类型、HashMap集合对象、POJO对象类型。
Executor将mapper.xml的动态sql解析出来放到MappedStatement里面,MappedStatement里面放解析出来的sql语句,和执行sql语句返回的结果集
四、 MyBatis交互方式
- 传统的交互方式
statementId 是一条sql语句的标识
Sqlstatement是Mybatis的核心
- mapper 文件
五、 mapper文件详解
5.1 mapper文件中的namesace和约定
- mapper文件中的命名空间一定要对Dao接口完整包路径一致
- sql语句中的id名字必须跟dao接口中的方法名一致
- sql语句中的参数类型必须跟dao接口中的参数类型对应
- sql语句的返回结果返回结果,必须跟dao接口中的方法返回值类型一致
5.2自定义sql标签
用某个sql语句语句片段替换sql语句标签
作用:重复的sql语句片段不用写,直接引用
<sql id="Base_Column_List">
goods_id, title, old_price, now_price, create_time, update_time, update_user, sold,
score, merchant_id, img
</sql>
调用自定义sql <include refid=“Base_Column_List”>,refid的值与<sql>id的值一致
<select id="selectUserByIds2">
select
<include refid="Base_Column_List">
from user
<where>
user_id in
<foreach collection="ids1" open="(" close=")" item="u" separator=",">
#{u.userId}
</foreach>
</where>
</select>
六、【重点】mybatis动态sql语句 ,6个sql语句标签
- where
动态的增加或者删除where关键字。根据where标签中是否有内容来决定。where后的第一个and[or]会自动被删除。
<select id="selectByQuery">
select
<include refid="Base_Column_List"/>
from user
<where>
<if test="nickName!=null and nickName!=''">
and nick_name=#{nickName}
</if>
<if test="realName!=null and realName!=''">
and real_name=#{realName}
</if>
<if test="phone!=null and phone!=''">
and phone=#{phone}
</if>
<if test="userId!=null">
and user_id=#{userId}
</if>
</where>
</select>
mybatis的where标签会根据标签中是否有内容自动生成对应的sl语句
- if标签
<select id="selectByQuery">
select
<include refid="Base_Column_List"/>
from user
<where>
<if test="nickName!=null and nickName!=''">
and nick_name=#{nickName}
</if>
<if test="realName!=null and realName!=''">
and real_name=#{realName}
</if>
<if test="phone!=null and phone!=''">
and phone=#{phone}
</if>
<if test="userId!=null">
and user_id=#{userId}
</if>
</where>
</select>
根据条件的真假来决定是否追加if中的内容
- trim标签
prefix 用于加前缀,suffix加后缀
suffixOverrides="" 末尾忽略某个关键字
prefixOverrides="" 开头忽略某个关键字
<insert id="" parameterType="类全名">
<trim prefix="("suffix=")" suffixOverrides=",">
<if test="orderId!=null">
order_id,
</if>
</trim>
</insert>
trim查询
<select id="selectTest">
select
<include refid="Base_Column_List"/>
from user
<trim prefix="where" prefixOverrides="and">
<if test="userId!=null">
AND user_id=#{userId}
</if>
</trim>
</select>
- set标签,自动拼接set关键字,和去掉末尾逗号
<!-- if/set(判断参数) - 将实体 User类不为空的属性更新 -->
<update id="updateUser_if_set" parameterType="com.pojo.User">
UPDATE user
<set>
<if test="username!= null and username != '' ">
username = #{username},
</if>
<if test="sex!= null and sex!= '' ">
sex = #{sex},
</if>
<if test="birthday != null ">
birthday = #{birthday},
</if>
</set>
WHERE user_id = #{userid};
</update>
用trim代替set标签
<update id="updateTest">
update user
<trim prefix="set" suffixOverrides=",">
<if test="userId!=null">
user_id=#{userId},
</if>
</trim>
</update>
- foreacher标签:循环标签
传集合(数组)的一定要加@Param(“集合名”) 注解,而且对用的mapper.xml文件中的集合名字就完全等于集合名字。
例:批量的根据用户id查询用户信息
<select id="selectUserByIds">
select <include refid="Base_Column_List"/>from user
<where>
user_id in
<foreach cillection = "ids" open="(" close=")" item="id" separator=",">
#{id}
</foreach>
</where>
</selects>
collection 集合名 ,值与dao接口中@Param("")值一致
open 开始的符号
close 结束的符号
item 对象的引用声明 例: User u = new User,方便调用属性
separator 分隔符
例2:目前这种集合的元素是一个单个的基本对象 例:List
注意:传递集合(数组)的时候,一定需要@Param(“集合的名字随意”)注解。而且对应的mapper.xml文件中的集合名字就完全等于集合的名字随意。
<select id="selectUserByIds2">
select
<include refid="Base_Column_List">
from user
<where>
user_id in
<foreach collection="ids1" open="(" close=")" item="u" separator=",">
#{u.userId}
</foreach>
</where>
</select>
例3:对象的某一个属性为一个集合,将对象的属性写如collection
<select id= "selectUserByIds3">
select
<include refid="Base_column_List"/>
from user
<where>
user_id in
<foreach collection = "users" open="(" close=")" item="u" separator=",">
#{u.userId}
</foreach>
</where>
</select>
- choose when otherwise
<select id= "selectUserByIds4" parameterType="com.qf.pojo.User">
select * from user u
<where>
<choose>
<when test="username != null">
and u.username like concat(concat("%",#{username,jdbcType=VARCHAR})"%")
</when>
<when test="sex != null and sex !=''">
and u.sex = #{sex,jdbcType=Integer}
</when>
<otherwise>
</otherwise>
</choose>
</where>
</select>
六、 mybatis参数传递
6.1 单个元素
【掌握】基本数据类型的参数类型传递包括String
单个参数传递,#{参数名[,参数类型]},参数名称随意
应用数据类型
直接#{应用类型属性名称} 属性名不能乱写
集合
集合一定要加@param("")注解,名字随意
6.2多个参数传递
生成的sql语句剪切到最后,或放到新文件之中,为避免找不到,或重新生成被覆盖掉
CONCAT函数,拼接字符串函数
concat("%",#{realName},"%") #{@Param名一样}
concat#{}不能识别解决方案
- 每个参数前加@Param("")
- 可用arg0,arg1
- 把参数封装成一个查询对象,直接用查询对象的属性【重】
- 也可以用Map,但Map的key值必须是属性名称
七、pojo概念
pojo就是简单的java类对象
主要有:
实体类{entity}:就是数据库表生成的对应的简单的java类。(mybatis逆向生成,不要去更改)
对象传输类dto:在程序之间传输数据对象的时候会用到,如统一返回给前端的对象就可以叫做ResponseDTO对象,统一分页对象叫做PageDto对象
查询类query:封装查询参数的查询对象,单独写出来
视图类vo,vo目前有两种说法,一种叫viewObject,专门给前端展示用的视图对象。还有一种说法叫value object,指的是从数据库查询出来的结果value映射级,vo类继承实体类,在vo类里边增加属性,就好了
经验:在生成实体类和持久层(DAO)时建议新建一个小项目,在小项目例生成,然后复制粘贴,不要直接托过去
Mybaits测试
package com.qf.study;
import com.qf.dao.GoodsDao;
import com.qf.pojo.entity.Goods;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class TestMybaits {
public static void main(String[] args) {
//通过配置文件得到SqlSessionFactory 会话工厂
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(TestMybaits.class.getClassLoader().getResourceAsStream("mybatis/mybatisConfig.xml"));
//通过会话工厂拿到sqlSessionFactory 拿到sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//sqlSession完成增删查改操作
GoodsDao goodsDao = sqlSession.getMapper(GoodsDao.class);
Goods goods = goodsDao.selectByPrimaryKey(3L);
System.err.println(goods);
sqlSession.close();
}
}