Mybatis 是一个对数据库进行操作的 ORM 框架,主要是封装提供灵活的增删改查sql,开发中,service层能够通过mybatis组件查询和修改数据库中表的数据;作为查询工具,mybatis有使用缓存,当我们从数据库中查询过的数据,会存入缓存,当我们进行二次查询时,就不需要重新链接数据库进行二次查询,缓存的生命周期创建的会话。
什么是ORM框架
- 首先ORM是对象关系映射,作用是实现java对象和数据库表的自动转换,屏蔽原生SQL,用面向对象的方式操作数据库。
- 核心映射关系
- 实体类(emp)<->数据库表
- 类的成员属性<->表的字段(列)
- 类的对象实例<->表的一行数据
- 核心思想
- 不用大量手写sql,通过操作对象,由框架自动生成,执行sql,完成增删改查。
Mybatis的环境搭建
- 导入maven依赖
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.19</version>
</dependency>
- 编写实体类(实体类的属性名要和数据库的字段名对应)
- 编写Mapper接口,例如
@Select("select * from emp where empno=#{id}")
emp findAll(int id);
- 编写Mybatis核心配置文件(config.xml)--可直接复制粘贴
<?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>
<settings>
<!--输出日志到控制台中-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<!--分别书写驱动类、网址、账号和密码 注意网址中&使用&代替-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/book_21"/>
<property name="username" value="root"/>
<property name="password" value="LQYOW2580"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--引入的资源文件-->
<package name="org.example.mybatis.m5.mapper"/>
</mappers>
</configuration>
5.编写Mapper 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="org.example.mybatis.m1.mapper.informationMapper">//这个是你当前映射文件的路径
<!--
代表一个查询方法
id:方法名(必须和Mapper接口全类名完全一致)
resultType:返回类型路径
parameterType:参数类型,没有就删掉
-->
<select id="findAll" resultType="org.example.mybatis.m1.bean.information">
<!--这里是Sql-->
select * from information
</select>
利用注解的方式
- 依赖,实体类,配置文件这些和XML完全一样,不用改,只有一处要改,config.xml的,改成扫包注册接口:
<package name="org.example.mybatis.m2.mapper"/>
2。注解版Mapper接口,举个全查询例子
@Select("select * from emp")//注解
List<emp> findAll();
3.最常考,最常用的一个:主键回填,新增时想插入后自动把数据库生成id赋给java对象
@Options(useGeneratedKeys=ture,keyProperty="id")
直接加在@insert下面就行
- 测试类,直接复制粘贴
//加载配置文件
InputStream resourceAsStream = Main.class.getClassLoader().getResourceAsStream("config.xml");
//创建会话工厂
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
//创建会话
SqlSession sqlSession = build.openSession();
// 获取到对象
empMapper mapper = sqlSession.getMapper(empMapper.class);
mybatis的参数问题
在mybatis中,接口传递参数到xml或者注解的形式,主要分为单参数,多参数,特殊参数(Map)三种情况
1.单参数
- mybatis对单参数没有限制,直接通过#{}或${}(这个时拼接具体区别请看别的文章)
//单个参数问题
@Select("select * from emp where empno=#{id}")//#{}输出对应占位符
emp findEmpById(int id);
@Select("select * from emp where empno=${id}")//${}直接把参数拼接上去
emp findEmpById1(int id);
//单个参数时,名称可以不对应
@Select("select * from emp where empno=#{abc}")
emp findEmpById2(int id);
2多参数问题.
-
当方法传入多个参数的时候,mybatis会自动进行封装,不能注解使用参数名,必须使用指定别名 - 解决方案:使用@Param注解--这是最优雅的方式,通过注解给参数起别名
@Select("select * from emp where ename like #{name} and job=#{job}")
List<emp> findEmp3(@Param("name") String name, @Param("job") String job);
- 数据库表中的列和对象的属性名不一致时
- 方案1:给数据库字段起个别名,让其和java属性相等
@Select("select e.*,job as 'job1'from emp e where empno=#{id}")
emp find1(int id);
3方案二. //解决方案2--让数据库名等于Java名
@Select("select * from emp where empno=#{id}")
```
@Results(
@Result(column = "job",property = "job1")
)
emp find2(int id);
映射
- 映射是指将数据库查询的结果集转换成java对象的过程
- 自动映射
- 前提条件:数据库字段名和java实体类属性名一致
- 使用场景:简单的单表查询,字段名差异不大
2.手动映射
- 当字段名与属性完全不一致,或者需要多表查询,例多表查询:
@Select("select * from emp where empno=#{empno}")
@Results(
/*
column:将数据库查出来的列赋给property
propery:代表bean包中的某一个属性
*/
value = {
@Result(column = "empno", property = "empNo", id = true),
//非主键
@Result(column = "ename", property = "ename", javaType = String.class),
@Result(column = "deptno",
property = "dept",javaType = dept.class,
one = @One(select = "org.example.mybatis.m3.mapper.DeptMapper.findDeptById")
)
}
)
emp findEmpById(int empno);
- 在另一个类中写查找dept的方法
@Select("select * from dept where deptno=#{deptNo}")
dept findDeptById(int deptNo)
这就是多表查询,多对一的例子,一对多同理,将One改成Many
mysql动态sql--用xml方便,利用注解很麻烦
- 动态sql核心作用是根据不同条件动态生成不同的sql语句
- 核心标签详解:
- <if 标签:条件判断--这里id必须和接口中方法名一致
<select id="find1" resultType="org.example.mybatis.m4.bean.emp">
select * from emp
<if test="ename!=null">
where ename like #{ename}
</if>
</select>
2.类似if-else标签《choose>《when>《otherwise>
<choose>
<when test="sal>3000">
where job='程序员'
</when>
<when test="sal>6000">
where job='网页设计'
</when>
<otherwise>
where job='歌手'
</otherwise>
</choose>
3.《where>标签:自动处理where子句:
select * from emp
<where>
<if test="job!=null">
job=#{job}
</if>
<if test="sal!=null">
and sal>#{sal}
</if>
</where>
<!--第二种方式-->
<trim prefix="where" suffixOverrides="and|or">
<if test="job!=null">
job=#{job}
</if>
<if test="sal!=null">
and sal>#{sal}
</if>
</trim>
</select>
4.《foreach>标签:遍历集合
//集合必须加Pararm,起名字,或者用默认名”collection“
List<emp> find5( @Param("job") List<String> job);
select * from emp
<where>
<if test="job!=null">
job in
<!--
for(String ab:job)
-->
<foreach collection=" job" open="(" close=")" separator="," item="ab">
#{ab}
</foreach>
</if>
</where>
</select>
5.《set>标签,动态更新
update emp
<set>
<if test="ename!=null">
ename=#{ename},
</if>
<if test="job!=null">
job=#{job},
</if>
<if test="mgr!=null">
mgr=#{mgr},
</if>
</set>
where empno=#{empNo}
</update>
5.《bind> 模糊查询
<bind name="abc" value="'%' + _parameter.getEname() + '%'"/>
select *
from emp
where ename like #{abc}
缓存问题
- 缓存是将频繁查询,不常修改的数据存储到数据存储在内存的技术 第一次查询:从数据库中查询数据,存入缓存
- 后续查询相同内容,直接从缓存中取数据,无需访问数据库
1.一级缓存(sqlsession级别,默认开启)
- 作用域也可以说缓存的生命周期:同一个sqlSession内有效,sqlsession关闭后清空
缓存失效场景:
1.执行insert,delete,update操作(会清空当前sqlsession的一级缓存)
2.手动调用sqlsession.clearCache()清空缓存
3.不同sqlsession之间不共享
// 同一个SqlSession,两次查询,第二次命中一级缓存
try (SqlSession sqlSession = MyBatisUtils.getSqlSession(true)) {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user1 = mapper.selectUserById(1); // 第一次:查数据库
User user2 = mapper.selectUserById(1); // 第二次:命中缓存,不查数据库
System.out.println(user1 == user2); // true(同一个对象)
}
二级缓存
-作用域:全局共享
-默认关闭,要手动开启
- 开启缓存的步骤在config.xml中配置
<!--开启全局二级缓存-->
<setting name="cacheEnabled" value="true"/>
</settings>