目录
为什么说Mybatis是半自动ORM映射工具?它与全自动的区别在哪里?
什么是Mybatis
Mybatis是一个半ORM(对象关系映射)框架,它内部封装了JDBC,开发时只需要关注Sql语句本身,不需要花费精力去处理加载驱动,创建链接,创建statement等繁杂的过程,程序元直接编写原生态sql,可以严格控制sql执行性能,灵活度高。
Mybatis可以使用XML或者注释来配置和映射原生信息,将POJO映射成数据库中的记录,避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。
通过XML文件或注释的方式将要执行的各种statement配置起来,并通过java对象和statement中sql的动态参数进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射为java对象并返回
Mybaits的优点与缺点以及使用场合?
优点:
1)基于SQL语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL写在XML里,解除sql与程序代码的耦合,便于统一管理;提供XML标签,支持编写动态SQL语句,并可重用。
2)与JDBC相比,减少了50%以上的代码量,消除了JDBC大量冗余的代码,不需要手动开关连接很好的与各种数据库兼容(因为MyBatis使用JDBC来连接数据库,所以只要JDBC支持的数据库MyBatis都支持)
3)能够与Spring很好的集成提供映射标签,支持对象与数据库的ORM字段关系映射;提供对象关系映射标签,支持对象关系组件维护
缺点:
1)SQL语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写SQL语句的功底有一定要求
2)SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库
使用场合:
MyBatis专注于SQL本身,是一个足够灵活的DAO层解决方案对性能的要求很高,或者需求变化较多的项目,如互联网项目,MyBatis将是不错的选择
Mybatis实现数据查询时的两种sql写法
1.将所有的SQl语句都写到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="cn.pqz.emsboot.modules.output.mapper.OutputLogMapper">
<select id="getOutputLogList" resultType="cn.pqz.emsboot.modules.output.entity.OutputLog">
SELECT ol.*,u.username from output_log ol,user u where ol.operator=u.id and ol.oid = #{oid}
</select>
</mapper>
id是mapper接口中的抽象方法名
package cn.pqz.emsboot.modules.output.mapper;
import cn.pqz.emsboot.modules.output.entity.OutputLog;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface OutputLogMapper extends BaseMapper<OutputLog> {
public List<OutputLog> getOutputLogList(Integer oid);
}
resultType是映射数据库列名的属性类的全路径
package cn.pqz.emsboot.modules.output.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
public class OutputLog implements Serializable {
private Integer id;
private String orderNum;
private String orderName;
private Date startTime;
private Date endTime;
private Integer oid;
private Integer operator;
@TableField(exist = false)
private String username;
}
调用在severe里面调用
package cn.pqz.emsboot.modules.output.service;
import cn.pqz.emsboot.modules.output.entity.OutputLog;
import cn.pqz.emsboot.modules.output.mapper.OutputLogMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@Transactional
public class OutputLogService extends ServiceImpl<OutputLogMapper, OutputLog> {
@Autowired
private OutputLogMapper outputLogMapper;
public List<OutputLog> getOutputLogList(Integer oid){
return outputLogMapper.getOutputLogList(oid);
}
}
参数解析
别名:alias
在sqlMapConfig.xml配置,映射文件中直接写对象名称即可
<typeAliases>
<typeAlias type="cn.mybatis.pojo.User" alias="User"/>
</typeAliases>
参数值:parameterType
指定参数类型,通常制定一个对象类型
返回值:resultType
非常重要的东西,即完成ORM的映射关系所在,这里指定的cd.tedu.mybatis.domain.User代表把结果集转换成一个User对象实例。
返回值:resultMap
resultMap用于对复杂对象结构时,对应的ResultMap结构名称
2.可以将sql语句通过注解的方式标识在接口方法中(只适用于简单操作)
动态sql
1.同一个dao的方法,根据不同的条件表示不同的sql语句,主要是where部分有变化;
2.使用mybatis提供的标签,实现动态sql能力,主要使用如 if, where, foreach, sql;
3.使用动态sql的时候,dao方法的形参使用java对象;
4.多条件查询时可以使用动态sql;
通过注解实现
说明:该注解一般都是操作简单的数据查询,如果遇到相关查询、复杂sql则使用Mapper映射文件的形式更加通用
Xml 映射文件中,除了常见的 select|insert|updae|delete 标签之外,还有哪些标签?
还有很多其他的标签<resultMap><parameterMap><sql><include><selectKey>,加上动态 sql 的 9 个标签, trim|where|set|foreach|if|choose|when|otherwise|bind 等,其中为<sql>片段标签,通<include>过标签引入 sql 片段,<selectKey> 为不支持自增的主键生成策略标签
MybatisPlus
MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
使用MP主要完成单表的CURD操作简化开发,提高开发效率
编辑POJO类
说明:
1.POJO应该与数据库中的表完成映射
2.POJO中的属性与表中的字段一一映射.注解:
1. @TableName(“demo_user”) //实现对象与表名映射
2. //设定主键自增 @TableId(type = IdType.AUTO)
3. @TableField(“name”) 实现属性与字段映射.
规则: 如果属性与字段的名称一致,则注解可以省略
实际用法:
配置过程
MP生效配置
说明: 将原来的mybatis 改为mybatis-plus
MP常用操作
根据ID查询
//1.根据id主键 查询id=1的数据
//SELECT id,name,age,sex FROM demo_user WHERE id=?
@Test
public void testSelect1(){
User user = userMapper.selectById(1);
System.out.println(user);
}
selectList查询(一)
//2.查询name="小乔" sex="男"的用户
//Sql: select * from demo_user where name="xx" and sex="xx"
@Test
public void testSelect2(){
//创建条件构造器 封装where条件的.
User user = new User();
user.setName("小乔").setSex("男");
//实现时会动态的根据对象中不为null的属性,拼接where条件,
//默认的关系链接符 and
QueryWrapper queryWrapper = new QueryWrapper(user);
List<User> userList = userMapper.selectList(queryWrapper);
System.out.println(userList);
}
selectList查询(二)
//3.查询name="小乔" sex="男"的用户
//Sql:SELECT id,name,age,sex FROM demo_user WHERE name=? AND sex=?
@Test
public void testSelect3(){
QueryWrapper<User> queryWrapper = new QueryWrapper();
queryWrapper.eq("name","小乔")
.eq("sex","男");
List<User> userList = userMapper.selectList(queryWrapper);
System.out.println(userList);
}
selectList查询(三)
//4.查询 age> 18 sex="女"的用户
//Sql:SELECT * demo_user WHERE age > 18 and sex="女"
//逻辑运算符 > gt, < lt, = eq, >= ge, <= le, != ne
@Test
public void testSelect4(){
QueryWrapper<User> queryWrapper = new QueryWrapper();
queryWrapper.gt("age",18)
.eq("sex","女");
List<User> userList = userMapper.selectList(queryWrapper);
System.out.println(userList);
}
selectList查询-like关键字
//5. like关键字
//5.1 查询name包含"乔" where name like '%乔%'
//5.2 查询name以乔结尾的 where name like '%乔'
@Test
public void testSelect5(){
QueryWrapper<User> queryWrapper = new QueryWrapper();
//queryWrapper.like("name","乔");
queryWrapper.likeLeft("name","乔");
List<User> userList = userMapper.selectList(queryWrapper);
System.out.println(userList);
}
selectList查询-in关键字
/**
* 6. in 关键字
* 需求: 查询ID为1,3,5,6的数据
* Sql: select * from demo_user where id in (1,3,5,6)
*/
@Test
public void testSelect6(){
//一般的数组采用包装类型,使用对象身上的方法 基本类型没有方法
Integer[] ids = {1,3,5,6};
QueryWrapper<User> queryWrapper = new QueryWrapper();
queryWrapper.in("id",ids);
//采用可变参数类型 实现查询
//queryWrapper.in("id",1,3,5,6);
List<User> userList = userMapper.selectList(queryWrapper);
System.out.println(userList);
}
selectList查询-order by
/**
* 关键字: order by 排序
* 默认规则: 升序 asc 如果降序 desc
* 需求: 查询性别为男的用户并且 按照年龄降序排列.
* Sql: select * from demo_user where sex="男" order by age desc
*/
@Test
public void testSelect7(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("sex","男")
.orderByDesc("age");
List<User> userList = userMapper.selectList(queryWrapper);
System.out.println(userList);
}
selectList查询-动态sql
/**
* 动态Sql:
* 根据用户的条件,动态的拼接where条件
* 案例: 根据sex,age查询数据
* 1.select * from demo_user where age > 18 and sex="女"
* API说明:
* queryWrapper.gt(判断条件,字段名称,字段值)
* 判断条件: true 则动态的拼接where条件
* false 不会拼接where条件
* 判断语句:
* Boolean sexBoo = (sex !=null) && sex.length()>0;
*/
@Test
public void testSelect8(){
Integer age = 18;
String sex = "女";
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
Boolean ageBoo = (age !=null);
Boolean sexBoo = StringUtils.hasLength(sex);
queryWrapper.gt(ageBoo, "age",age)
.eq(sexBoo,"sex","女");
List<User> userList = userMapper.selectList(queryWrapper);
System.out.println(userList);
}
selectList查询-objs
/**
* 练习9: 只获取主键ID的值
* Sql: select id from demo_user
*/
@Test
public void testSelect9(){
List idList = userMapper.selectObjs(null);
System.out.println(idList);
}
删除操作
/**
* 练习10: 删除name="xxx"的数据
*/
public void testDelete(){
//删除ID为100的数据
userMapper.deleteById(100);
//userMapper.deleteBatchIds(null);
//删除操作的条件构造器
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("name","xxx");
userMapper.delete(queryWrapper);
}
更新操作-ById
/**
* 练习11: 数据修改
* 案例1: 要求修改id=233 name改为="晚上吃什么"
* API说明: userMapper.updateById(对象信息)
*/
@Test
public void testUpdate(){
//修改除ID之外的所有不为null的数据,id当作where一位条件
User user = new User();
user.setId(233).setName("晚上吃什么");
userMapper.updateById(user);
}
更新操作-任意字段
/**
* 练习12: 数据修改
* 案例2: 将name=mp的用户改为name="宵夜吃什么" age=20 sex=女
* API说明:
* userMapper.update(对象,修改条件构造器)
* 对象: 修改后的数据使用对象封装
* 修改条件构造器: 负责修改的where条件
*/
@Test
public void testUpdate2(){
User user = new User();
user.setName("宵夜吃什么").setAge(20).setSex("女");
UpdateWrapper updateWrapper = new UpdateWrapper();
updateWrapper.eq("name","MP");
userMapper.update(user,updateWrapper);
}
总结:
#{}和${}的区别是什么?
- #{}是预编译处理,${}是字符串替换
- Mybatis在处理#{}时,会将sql中的#{}替换成?号,调用PreparedStatement的set方法来赋值
- Mybatis在处理${}时,就是把${}替换成变量的值
- 使用#{}可以有效的防止sql注入,提高安全性
Mybatis的一级,二级缓存:
- 一级缓存:基于PerpetualCache的HashMap本地缓存,其存储作用域为Session,当Session flush或者close之后,该Session中的所有Cache就将清空,默认打开一级缓存
- 二级缓存与一级缓存其机制相同,默认也是采用PerpetualCache,HashMap存储,不同在于其存储作用域为Mapper,并且可以自定义存储源,如Ehcache。默认不打开二级缓存,要开启二级缓存,使用二级缓存属性类需要实现Serializable序列化接口,可在它的映射文件中配置判断是否刷新。
- 对于缓存数据更新机制,当某个作用域(一级缓存Session、二级缓存Namespaces)的进行了CUD操作后,默认该作用域下所有select中的缓存将被clear掉并重新更新,如果开启了二级缓存,则只根据配置判断是否刷新
Mybatis是如何进行分页的?分页插件的原理是什么?
Mybatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页,而非物理分页。可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。
分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数。
为什么说Mybatis是半自动ORM映射工具?它与全自动的区别在哪里?
Hibernate属于全自动ORM映射工具,使用Hibernate查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。而Mybatis在查询关联对象或关联集合对象时,需要手动编写sql来完成,所以,称之为半自动ORM映射工具。