一 .MyBatis框架
1.Mybatis环境搭建步骤
1.新建项目,项目下新建目录lib,涉及到的jar包放入lib目录下,右键add as lib…
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-69GjPWGi-1692620456055)(C:\Users\dis\Desktop\笔记\Mybatis\lib\Snipaste_2023-08-20_14-53-48.png)]
mybatis核心jar包
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bGkgVRqn-1692620456058)(C:\Users\dis\Desktop\笔记\Mybatis\lib\Snipaste_2023-08-20_14-54-39.png)]
mybatis依赖的jar包
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0jKTEJbV-1692620456059)(C:\Users\dis\Desktop\笔记\Mybatis\lib\Snipaste_2023-08-20_14-54-43.png)]
数据库的驱动包
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nHYtsZ8T-1692620456059)(C:\Users\dis\Desktop\笔记\Mybatis\lib\Snipaste_2023-08-20_14-54-48.png)]
2.编写核心配置文件
3.编写SQL映射文件,编写实体类
4.测试
2.使用
//1.加载核心配置文件
InputStream is = Resources.getResourceAsStream("mybatis.xml");
//2.构建SqlSessionFactory实例
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
//3.获取会话
SqlSession session = factory.openSession();
//4.执行sql
//selectList("命名空间.id")
List<Dept> list = session.selectList("com.yjxxt.mappers.DeptMapper.queryAll");
list.forEach(System.out::println);
//5.关闭会话
session.close();
3.配置文件
mybatis提供两种配置文件, 核心配置文件 mybatis-config.xml|mybatis.xml 与 SQL映射文件mapper.xml
1.mybatis.xml
是一个xml文件,命名无要求,位置无要求,一般成为mybatis.xml,放在src路径下
<?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标签 -->
<settings>
<!-- 设置MyBatis使用log4j日志支持 -->
<setting name="logImpl" value="LOG4J"/>
</settings>
<!--
用于指定使用哪一个开发环境
default : 用于指定使用的环境的id属性值
-->
<environments default="dev">
<!--
environment : 用于配置开发环境
id : 环境的唯一标识
-->
<environment id="dev">
<!--
transactionManager 事务管理器
type="JDBC" 采用jdbc相同的事务管理机制
-->
<transactionManager type="JDBC"/>
<!--
dataSource : 用来配置数据库连接参数
type="POOLED" 采用连接池技术
-->
<dataSource type="POOLED">
<property name="driver" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@localhost:1521:XE"/>
<property name="username" value="SCOTT"/>
<property name="password" value="YJXXT"/>
</dataSource>
</environment>
</environments>
<!--扫描SQL映射文件-->
<mappers>
<mapper resource="com/yjxxt/mappers/DeptMapper.xml"/>
</mappers>
</configuration>
2.Mybatis SQL映射文件
在Mybatis中,推荐使用mappers作为包名,我们只需要写一个映射配置文件就可以,UserMapper.xml,用于定义要执行的sql语句,同时可以设置参数|返回值结果类型
SQL 映射文件有很少的几个顶级元素(按照它们应该被定义的顺序):
resultMap – 是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象。
insert – 映射插入语句
update – 映射更新语句
delete – 映射删除语句
select – 映射查询语句
查询语句是 MyBatis 中最常用的元素之一(映射文件配置见代码)
<?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 命名空间
要求 : 唯一的,SQL映射文件的唯一标识
定义方式 :
1.随意定义,只要不重复即可,不推荐,不便于后期维护
2.推荐使用包名.文件名 -> 推荐
-->
<mapper namespace="com.yjxxt.mappers.UserMapper">
<!--
select 定义查询语句
id : 唯一标识,一个命名空间下的唯一
resultType : 结果类型
parameterType : 入参类型
-->
<select id="queryAll" resultType="com.yjxxt.pojo.User">
select * from t_user
</select>
</mapper>
3.三个查询方法
selectList(“命名空间.id”) 用户查询多条数据情况,返回一个List集合, 没有查到数据返回空集合,不是null
selectOne(“命名空间.id”) 用于查询单条数据,返回一个数据, 如果没有查到返回null
selectMap(“命名空间.id”,key的字段名) 用于查询多条记录情况, 返回Map集合, 需要指定那个属性作为key, sql查询结果作为value,指定的字段值作为key, 如果查不到, 返回一个空map集合,不是null
*/
//1.加载核心配置文件
InputStream is = Resources.getResourceAsStream("mybatis.xml");
//2.构建SqlSessionFactory实例
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
//3.获取会话
SqlSession session = factory.openSession();
//4.执行sql
//selectList("命名空间.id")
List<Dept> list = session.selectList("com.yjxxt.mappers.DeptMapper.queryDept");
list.forEach(System.out::println);
System.out.println("--------------------------------------------------");
//selectList("命名空间.id",入参)
List<Dept> list2 = session.selectList("com.yjxxt.mappers.DeptMapper.queryDeptByLoc","NEW YORK");
list2.forEach(System.out::println);
System.out.println("--------------------------------------------------");
//selectOne("命名空间.id")
//selectOne("命名空间.id",入参)
Dept dept = session.selectOne("com.yjxxt.mappers.DeptMapper.queryDeptById",10);
System.out.println(dept);
System.out.println("--------------------------------------------------");
//selectMap("命名空间.id","作为key的字段名")
//selectMap("命名空间.id",入参,"作为key的字段名")
Map<Integer,Dept> map = session.selectMap("com.yjxxt.mappers.DeptMapper.queryDeptByLoc","NEW YORK","deptno");
System.out.println(map);
//5.关闭会话
session.close();
}
4.resultType结果类型
基本数据类型(包装类) String Date JavaBean List Map List-Map
1.Date类型
<!--Date : 根据员工编号查询员工入职日期-->
<select id="queryDateByNo" parameterType="int" resultType="date">
select hiredate from emp where empno = #{empno}
</select>
//Date
Date date = session.selectOne("com.yjxxt.mappers.EmpMapper.queryDateByNo",7369);
System.out.println(date);
2.List类型
<!--List类型 :查询指定名字类型的用户信息 -->
<select id="queryUserByUsernameLike" resultType="user" parameterType="string">
select * from t_user where uname like '%'||#{0}||'%'
</select>
/*
* List : 查询指定名字类型的用户信息
*/
@Test
public void testList(){
SqlSession session = MybatisUtils.getSession();
List<User> list =
session.selectList("com.yjxxt.mapper.UserMapper.queryUserByUsernameLike","i");
list.forEach(System.out::println);
session.close();
}
3.Map类型
<!--Map : 根据员工编号查询员工信息-->
<select id="queryEmpByNo" parameterType="int" resultType="map">
select * from emp where empno = #{empno}
</select>
//Map
Map<String,Object> map = session.selectOne("com.yjxxt.mappers.EmpMapper.queryEmpByNo",7369);
System.out.println(map);
4.List-Map类型
<!--List<Map> : 根据员工姓名模糊查询-->
<select id="queryEmpByNameLike" parameterType="String" resultType="map">
select * from emp where ename like '%'||#{ename}||'%'
</select>
//List<Map>
List<Map<String,Object>> list = session.selectList("com.yjxxt.mappers.EmpMapper.queryEmpByNameLike","A");
list.forEach(System.out::println);
二. Log4J日志
1.日志级别
DEBUG(人为调试信息)
INFO(普通信息)
WARN(警告)
ERROR(错误)
FATAL(系统错误)
这五个级别是有顺序的,DEBUG < INFO < WARN < ERROR < FATAL
Log4j有一个规则:只输出级别不低于设定级别的日志信息
2.配置文件
可以使用properties或者xml进行配置,使用一个叫 log4j.properties 的配置文件, 会设定 log4j的设置信息, 例如日志级别, 日志输出方式, 日志格式等等.
# Set root category priority to INFO and its only appender to CONSOLE.
# log4j.rootCategory=DEBUG, CONSOLE
log4j.rootCategory=INFO, CONSOLE, LOGFILE
# 单独设置SQL语句输出级别为DEBUG
# 方法级别设置(SQL语句)
# log4j.logger.com.yjxxt.mappers.DeptMapper.queryDept=DEBUG
# 类级别设置(SQL映射文件)
# log4j.logger.com.yjxxt.mappers.DeptMapper=DEBUG
# 类级别设置(SQL映射文件)
log4j.logger.com.yjxxt.mappers=DEBUG
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=- %m %n
# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=d:/test.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=- %m %l %n
3.常见的日志输出格式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zVBZXF5x-1692620456061)(C:\Users\dis\Desktop\笔记\Mybatis\lib\Snipaste_2023-08-20_15-13-55.png)]
4.Mybatis对Log4J的支持
通过settings标签开启 log4j 的支持
settings用于设置 MyBatis 在运行时的行为方式, 例如:缓存, 延迟加载, 日志等.
<!-- settings标签 -->
<settings>
<!-- 设置MyBatis使用log4j日志支持 -->
<setting name="logImpl" value="LOG4J"/>
</settings>
三.软编码与别名
1.通过properties标签实现软编码
src下定义配置文件db.properties
driver=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@localhost:1521:XE
username=SCOTT
password=TIGER
mybatis核心配置文件中添加properties标签,指定加载外部的properties文件,注意定义位置 setting上面
<!-- 加载外部的properties文件 -->
<properties resource="db.properties" />
获取properties文件中数据时候,要通过${}的方式获取
<environments default="dev">
<!--环境配置-->
<environment id="dev">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
2.typeAliases标签
给User类定义别名为u
<typeAliases>
<typeAlias type="com.yjxxt.pojo.User" alias="u"/>
</typeAliases>
省略alias属性, 表示类别名为类名, 大小写不敏感
<typeAliases>
<typeAlias type="com.yjxxt.pojo.User"/> alias属性不写,默认类名,不区分大小写
</typeAliases>
可以通过package标签给整个包下的所有类定义别名,别名为类名
<typeAliases>
<package name="com.yjxxt.pojo"/> <!-- 包下所有的类默认类名 -->
</typeAliases>
<select id="queryAll" resultType="u">
select id,uname,upwd,birthday from t_user
</select>
<select id="queryById" resultType="User">
select id,uname,upwd,birthday from t_user where id=125
</select>
3.Mybatis的内建别名
下面是一些为常见的 Java 类型内建的类型别名。它们都是不区分大小写的,注意,为了应对原始类型的命名重复,采取了特殊的命名风格。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PCKSNlm3-1692620456062)(C:\Users\dis\Desktop\笔记\Mybatis\lib\Snipaste_2023-08-20_15-35-22.png)]
四.parameterType入参类型
如果执行的是条件查询,DML,需要在调用方法的时候传递参数,此时, 可以在sql标签中通过parameterType属性指定参数的类型(别名|权限定名). 而在sql语句,通过#{}的方式获取参数
入参类型 : 基本数据类型|包装类 String Date Javabean Map List|数组…
1.一个参数的查询
根据员工姓名查询员工信息,当参数只有一个,#{}可以任意填写匹配参数
<!--String : 根据员工姓名查询员工信息-->
<select id="queryEmpByName" parameterType="String" resultType="emp">
select * from emp where ename = #{ename}
</select>
2.多个参数查询
多个参数传递时, 由于sqlSession中提供的查询方法,只允许传递一个sql参数, 因此可以对多个参数进行封装,可以对象,集合,数组…
<!--Javabean : 根据员工姓名与员工的薪资查询员工信息-->
<!--sql中的占位符的名字匹配入参对象的属性名,根据属性名匹配属性值-->
<select id="queryEmpByNameSal" parameterType="emp" resultType="emp">
select * from emp where ename = #{ename} and sal = #{sal}
</select>
<!--Map : 根据员工薪资与员工的部门编号查询员工信息-->
<select id="queryEmpBySalDeptno" parameterType="map" resultType="emp">
select * from emp where sal = #{sal} or deptno = #{deptno}
</select>
<!--数组|list : 根据多个员工编号查询员工信息-->
<select id="queryEmpByNoSome" resultType="emp">
select * from emp where empno in (
<foreach collection="array" separator="," item="item">
#{item}
</foreach>
)
</select>
五.工具类的封装
package com.yjxxt.utils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
/*
封装获取会话的工具类
*/
public class SessionUtils {
private static SqlSessionFactory factory = null;
static{
try {
factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis.xml"));
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSession(){
SqlSession session = null;
if(factory!=null){
session = factory.openSession(); //手动提交
//session = factory.openSession(true); //自动提交
}
return session;
}
}
//1.获取会话
SqlSession session = SessionUtils.getSession();
//2.执行sql
//selectList("命名空间.id")
List<Dept> list = session.selectList("com.yjxxt.mappers.DeptMapper.queryAll");
list.forEach(System.out::println);
//3.关闭会话
session.close();
六.事务
测试增删改
事务 :
需要手动提交的 : 需要通过session设置提交|回滚 --> 默认手动提交
设置自动提交 factory.openSession(true);
session.commit(); //事务提交
1.增删改操作
测试增删改
insert
update
delete
注意: 增删改结果类型默认影响函数
SQL映射文件:
<!--新增一条部门数据-->
<insert id="insertDept" parameterType="Dept">
insert into dept values(#{deptno},#{dname},#{loc})
</insert>
<!--根据部门编号修改部门名称-->
<update id="updateDept" parameterType="Dept">
update dept set dname=#{dname} where deptno = #{deptno}
</update>
<!--根据部门编号删除部门信息-->
<delete id="deleteDept" parameterType="int">
delete from dept where deptno = #{deptno}
</delete>
Java测试类:
//1.获取会话
SqlSession session = SessionUtils.getSession();
//2.执行sql
//insert
/*int rows = session.insert("com.yjxxt.mappers.DeptMapper.insertDept",new Dept(80,"网管部2","北京"));
System.out.println(rows);
*/
//update
//int rows = session.update("com.yjxxt.mappers.DeptMapper.updateDept",new Dept(80,"网管部2222","北京"));
//delete
int rows = session.delete("com.yjxxt.mappers.DeptMapper.deleteDept",80);
if(rows>0){
session.commit(); //事务提交
}else{
session.rollback(); //回滚
}
//3.关闭会话
session.close();
七.接口绑定方案
Myabtis中,提供了一套接口绑定方案,程序员可以提供一个接口,然后提供一个与接口所对应的mapper.xml文件
1.测试接口绑定方案
步骤 :
1.定义接口,定义抽象功能
package com.yjxxt.mappers;
import com.yjxxt.pojo.Dept;
import java.util.List;
/*
接口绑定方案下的接口 :
*/
public interface DeptMapper {
// 查询所有的部门信息
public List<Dept> queryAll();
}
2.定义与接口绑定的SQL文件,定义SQL语句,按照要求进行定义
1.接口与SQL映射文件名字要保持一致,并放在同一个包下
2.SQL映射文件的命名空间namespace定义为与之绑定的接口的包名.类名
3.SQL标签的id属性值与接口中所对应的抽象方法的方法名保持一致
4.SQL语句的参数与返回值要求与对应的抽象方法的参数与返回值保持一致
<mapper namespace="com.yjxxt.mappers.DeptMapper">
<!--查询所有的部门信息-->
<select id="queryAll" resultType="Dept">
select * from dept
</select>
</mapper>
3.核心配置文件中通过Mapper扫描接口
<!--扫描接口 : 接口绑定方案-->
<mappers>
<!--<mapper class="com.yjxxt.mappers.DeptMapper"/>
<mapper class="com.yjxxt.mappers.EmpMapper"/>-->
<package name="com.yjxxt.mappers"/> <!--包扫描-->
</mappers>
4.在java代码中通过获取接口实现类对象调用功能
//1.获取会话
SqlSession session = SessionUtils.getSession();
//2.获取接口实现类对象--> 指定哪一个接口
DeptMapper mapper = session.getMapper(DeptMapper.class);
//3.调用方法
List<Dept> list = mapper.queryAll();
list.forEach(System.out::println);
//4.关闭会话
session.close();
2.通过接口绑定解决多参数传递问题
方式一:
接口中定义方法
List<Emp> queryEmpBySalDeptno(double sal,int deptno);
映射文件中提供对应的标签. 此时, SQL 语句中获取方式有两种, 通过#{arg+数字}或#{param+数字}的方式.
<select id="queryEmpBySalDeptno" resultType="Emp">
<!--sql中如果出现多参数传递,可以实现,默认占位符的名字为 : [arg0,arg1|param1,param2]-->
<!--select * from emp where sal > #{arg0} and deptno = #{arg1}-->
<!--select * from emp where sal > #{param1} and deptno = #{param2}-->
</select>
方式二:
接口中定义方法, 参数中使用@Param 注解设定参数名用于在 SQL 语句中使用.
List<Emp> queryEmpBySalDeptno(@Param("sal") double sal,@Param("dno") int deptno);
映射文件中提供对应的标签. 此时, SQL 语句中获取方式有两种, 通过#{参数名称}或#{param+数字}的方式.
<select id="queryEmpBySalDeptno" resultType="Emp">
select * from emp where sal > #{sal} and deptno = #{dno}
</select>
3.接口增删改
//插入一个新的部门信息
int insertDept(Dept dept);
//根据部门编号修改部门名称
int updateDept(@Param("deptno") int deptno, @Param("dname") String dname);
//根据部门编号删除
int deleteDept(int deptno);
<!--插入一个新的部门信息-->
<insert id="insertDept" parameterType="dept">
insert into dept values(#{deptno},#{dname},#{loc})
</insert>
<!--根据部门编号修改部门名称-->
<update id="updateDept">
update dept set dname = #{dname} where deptno = #{deptno}
</update>
<!--根据部门编号删除-->
<delete id="deleteDept" parameterType="int">
delete from dept where deptno = #{deptno}
</delete>
//1.获取会话
SqlSession session = SessionUtils.getSession();
//2.获取接口实现类对象--> 指定哪一个接口
DeptMapper2 mapper = session.getMapper(DeptMapper2.class);
//3.调用方法
//1个参数
//int rows = mapper.insertDept(new Dept(66,"六部","上海"));
//int rows = mapper.updateDept(66,"六六六部");
int rows = mapper.deleteDept(66);
System.out.println(rows>0?"操作成功":"失败");
//4.关闭会话
session.close();
八.动态 SQL
1.if
用于进行条件判断, test 属性用于指定判断条件. 为了拼接条件, 在 SQL 语句后强行添加 1=1 的恒成立条件
test : 用于设置判断条件,类似if语句的()
会自动帮助把第一个满足条件的if标签中的and关键字去掉
<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>
2.where
用于管理 where 子句. 有如下功能:
- 如果没有条件, 不会生成 where 关键字
- 如果有条件, 会自动添加 where 关键字
- 如果第一个条件中有 and, 去除之
<select id="queryEmp" resultType="emp">
select * from emp
<where>
<if test="ename!=null and ename!=''">
and ename=#{ename}
</if>
<if test="deptno!=0">
and deptno=#{deptno}
</if>
</where>
</select>
List<Emp> queryEmp(@Param("ename") String ename,@Param("deptno") int deptno);
3.choose…when…otherwise
这是一套标签, 功能类似于 switch…case…
<select id="queryEmpByIdName" resultType="emp">
select * from emp
<where>
<choose> <!--相当于switch-->
<when test="empno!=0"> <!--case-->
and empno = #{empno}
</when>
<when test="ename!=null and ename!=''"> <!--case-->
and ename=#{ename}
</when>
</choose>
</where>
</select>
List<Emp> queryEmpByIdName(@Param("empno") int empno,@Param("ename") String ename);
4.set
用于维护 update 语句中的 set 子句,与where标签类似. 功能如下:
- 满足条件时, 会自动添加 set 关键字
- 会去除 set 子句中多余的逗号
- 不满足条件时, 不会生成 set 关键字
<update id="updateEmp" parameterType="Emp">
update emp
<set>
ename = #{ename},
<if test="sal!=0">
sal=#{sal}
</if>
</set>
where empno = #{empno}
</update>
int updateEmp(Emp emp);
5.trim
用于在前后添加或删除一些内容
- prefix, 在前面添加内容
- prefixOverrides, 从前面去除内容
- suffix, 向后面添加内容
- suffixOverrides, 从后面去除内容
<update id="updateEmp" parameterType="Emp">
update emp
<trim prefix="set" suffixOverrides=",">
ename = #{ename},
<if test="sal!=0">
sal=#{sal}
</if>
</trim>
where empno = #{empno}
</update>
int updateEmp(Emp emp);
6.bind
用于对数据进行再加工, 用于模糊查询
<select id="queryEmpByNameLike" parameterType="string" resultType="emp">
<bind name="ename" value="'%'+ename+'%'"/>
select empno,ename,hiredate,job,sal,comm,deptno from emp where ename like #{ename}
</select>
List<Emp> queryEmpByNameLike(String ename);
7.foreach 与 sql…include
用于在 SQL 语句中遍历集合参数, 在 in 查询中使用
sql用于提取 SQL 语句, include用于引用 SQL 语句
- collection: 待遍历的集合
- open: 设置开始符号
- item: 迭代变量
- separator: 项目分隔符
- close: 设置结束符
<sql id="empField">
empno,ename,hiredate,job,sal,comm,deptno
</sql>
<select id="queryEmpByIdSome" resultType="emp">
select <include refid="empField"/> from emp where empno in
<foreach collection="list" item="item" separator="," open="(" close=")">
#{item}
</foreach>
</select>
List<Emp> queryEmpByIdSome(List<Integer> list);
九.Mybatis缓存机制
缓存的重要性是不言而喻的。 使用缓存, 我们可以避免频繁的与数据库进行交互, 尤其是在查询越多、缓存命中率越高的情况下, 使用缓存对性能的提高更明显。
mybatis 也提供了对缓存的支持, 分为一级缓存和二级缓存。 但是在默认的情况下, 只开启一级缓存。
一级缓存
- 默认开启. 线程级别的缓存, SqlSession 的缓存;
- 在一个 SqlSession 生命周期中有效. SqlSession 关闭,缓存清空;
- 在同一个 SqlSession 中, Mybatis 会把执行的方法和参数通过算法生成缓存的键值, 将键值和结果存放在一个 Map 中, 如果后续的键值一样, 则直接从 Map 中获取数据;
- 不同的 SqlSession 之间的缓存是相互隔离的;
- 用一个 SqlSession, 可以通过配置使得在查询前清空缓存;flushCache=“true”
- 任何的 UPDATE, INSERT, DELETE 语句都会清空缓存。
二级缓存
- 进程级别的缓存, SqlSessionFactory 的缓存
- 在一个SqlSessionFactory生命周期中有效. 可以在多个SqlSession 生命中期中共享.
- 默认关闭, 需要使用的时候, 要为某个命名空间开启二级缓存(在 mapper.xml 中配置cache).
- 由于在更新时会刷新缓存, 因此需要注意使用场合:查询频率很高, 更新频率很低时使用, 即经常使用 select, 相对较少使用delete, insert, update。
- 缓存是以 namespace 为单位的,不同 namespace 下的操作互不影响。但刷新缓存是刷新整个namespace 的缓存, 也就是你 update 了一个, 则整个缓存都刷新了。
- 最好在 「只有单表操作」 的表的 namespace 使用缓存, 而且对该表的操作都在这个 namespace中。 否则可能会出现数据不一致的情况。
十. 列名和属性名不一致问题
如果查询时使用 resultType 属性, 表示采用 MyBatis 的Auto-Mapping(自动映射)机制, 即相同的列名(结果集中的字段名)和属性名会自动匹配.
1)通过resultMap标签自定义表与javabean类型的映射情况
不同名的字段必须手动设置映射关系
同名的字段可以不设置,默认会根据自动映射机制找同名
2)为字段起别名
要求字段的别名与类型对应的属性名保持一致
1.使用resultMap
resultMap用于自定义映射关系, 可以由程序员自主制定列名和属性名的映射关系. 一旦使用 resultMap,表示不再采用自动映射机制.
<mapper namespace="com.yjxxt.mappers.DeptMapper">
<!--自定义结果的映射关系-->
<resultMap id="deptMap" type="Dept">
<!--id : 定义主键字段与属性的映射关系-->
<id column="deptno" property="id"/>
<!--id : 定义非主键字段与属性的映射关系-->
<result column="dname" property="name" />
<!--<result column="loc" property="loc" />-->
</resultMap>
<!--resultMap-->
<!--<select id="queryAll" resultMap="deptMap">
select * from dept
</select>-->
<!--别名实现-->
<select id="queryAll" resultType="dept">
select deptno id,dname name,loc from dept
</select>
</mapper>
2.关系映射查询
数据库中表与表之间的关系:
一对一 (人->身份证)
一对多 (夏令营->学生)
多对一 (学生->班级)
多对多 (学生->课程)
3.resultMap 的关联方式实现多表查询(一对一|多对一)
- 在 EmpMapper.xml 中定义多表连接查询 SQL 语句, 一次性查到需要的所有数据, 包括对应班级的信息.
- 通过resultMap标签定义映射关系, 并通过association标签指定对象属性的映射关系. 可以把association标签看成一个resultMap标签使用. javaType 属性表示当前对象, 可以写全限定路径或别名.
<!--
关系映射查询
resultMap 的关联方式实现多表查询(一对一|多对一)
-->
<mapper namespace="com.yjxxt.mappers.EmpMapper">
<!--自定义结果集中的字段与javabean类中属性的映射关系-->
<resultMap id="EmpDept" type="Emp">
<!--主键字段与属性的映射关系-->
<id column="empno" property="empno"></id>
<!--非主键字段与属性的映射关系-->
<result column="ename" property="ename"></result>
<result column="job" property="job"></result>
<result column="mgr" property="mgr"></result>
<result column="hiredate" property="hiredate"></result>
<result column="sal" property="sal"></result>
<result column="comm" property="comm"></result>
<result column="deptno" property="deptno"></result>
<!--association : 定义javabean类型属性与字段的映射关系-->
<association property="pddDept" javaType="Dept">
<id property="id" column="deptno" />
<result property="name" column="dname" />
<result property="loc" column="loc" />
</association>
</resultMap>
<select id="queryEmpDept" resultMap="EmpDept">
select empno,ename,job,mgr,hiredate,sal,comm,emp.deptno,dname,loc from emp join dept on emp.deptno = dept.deptno
</select>
</mapper>
private int empno;
private String ename;
private double sal;
private String job;
private double comm;
private int mgr;
private Date hiredate;
private int deptno;
//属性: javabean : 员工对象所在的部门信息
private Dept pddDept;
4.resultMap 的关联方式实现多表查询(一对 多)
-
在 ClazzMapper.xml 中定义多表连接查询 SQL 语句, 一次性查到需要的所有数据, 包括对应学生的信息.
-
通过resultMap定义映射关系, 并通过collection标签指定集合属性泛型的映射关系. 可以collection标签看成一个resultMap标签使用.ofType 属性表示集合的泛型, 可以写全限定路径或别名.
班级类中添加一个List容器存储学生类型 的数据 :
public class Clazz implements Serializable{
private int id;
private String name;
private int roomNum;
private List<Student> stus;
}
<mapper namespace="com.yjxxt.mapper.ClazzMapper">
<resultMap type="clazz" id="cmap">
<id property="id" column="cid" />
<result property="name" column="cname" />
<result property="room" column="room" />
<collection property="stus" javaType="list"
ofType="student">
<id property="id" column="sid" />
<result property="name" column="sname" />
<result property="age" column="age" />
<result property="gender" column="gender" />
<result property="cid" column="cid" />
</collection>
</resultMap>
<select id="selAll" resultMap="cmap">
select c.id cid, c.name cname,
c.room, s.id sid, s.name sname, s.age, s.gender from t_student s right
join t_class c on s.cid=c.id </select>
</mapper>
十一.注解开发
Mybatis中注解的作用:
使用注解一般用于简化配置文件. 但是, 注解有时候也不是很友好(有时候反而更麻烦), 例如动态 SQL等,所
以注解和配置文件可以配合使用
1.CRUD 注解
@Select: 类似于select标签
@Insert: 类似于insert标签
@Update: 类似于update标签
@Delete: 类似于delete标签
2.其他注解
@Results: 类似于resultMap标签
@Result: 类似<resultMap的子标签
@One: 类似于association标签
@Many: 类似于collection标签
// 查询所有的部门信息
@Select("select * from dept")
public List<Dept> queryAll();
//插入一个新的部门信息
int insertDept(Dept dept);
//根据部门编号修改部门名称
int updateDept(@Param("deptno") int deptno, @Param("dname") String dname);
//根据部门编号删除
int deleteDept(int deptno);