1. Mybatis介绍
- 持久化:将内存中的数据保存到磁盘中的过程
- 持久层:利用Mybatis操作代码Mapper/Dao,实现数据的持久化
- 高级映射:对象与数据表一一映射,对象中的属性与数据表中的字段一一映射。
- 简化操作:将JDBC代码进行简化,从对象的角度考虑问题,实现数据操作。(面向对象的方式操作数据库)
官网:https://mybatis.org/mybatis-3/zh/index.html
2. Mybatis 相关配置
2.1 导入jar包
pom.xml 文件:
<!--mybatis依赖包-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<!--jdbc依赖包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--添加lombok的包-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
2.2 程序连接数据库
application.yml文件是SpringBoot的配置文件。
#配置数据源
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/jt?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
username: root
#yml文件 0不解析 如果字母以0开头则引号包裹
#password: "0123456"
password: root
#配置Mybatis
mybatis:
#定义别名包
type-aliases-package: com.huo.pojo
#将所有的映射文件全部加载
mapper-locations: classpath:/mappers/*.xml
#开启驼峰映射
configuration:
map-underscore-to-camel-case: true
3. Mybatis—CRUD操作练习
3.1 User 实体类
@Data //lombok 添加get set equals等方法
@Accessors(chain = true) //链式加载
@NoArgsConstructor //添加无参构造
@AllArgsConstructor //添加全参构造
public class User implements Serializable {
private Integer id;
private String name;
private Integer age;
private String sex;
}
3.2 TestMybatis 测试类
package com.huo;
import com.huo.mapper.UserMapper;
import com.huo.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@SpringBootTest
public class TestMybatis {
@Autowired
private UserMapper userMapper;
//1.查询demo_user的全部数据
@Test
public void testFindAll(){
List<User> userList = userMapper.findAll();
System.out.println(userList);
}
//2.demo_user表中存入一条数据
@Test
public void saveUser(){
User user = new User();
user.setId(100).setName("哈哈哈").setAge(18).setSex("男");
userMapper.saveUser(user); //无返回值
int number=userMapper.saveUser2(user);//返回改变表数据的条数
System.out.println(number);
}
//4.修改demo_user表中id为249的name值
@Test
public void testUpdate(){
User user=new User();
user.setId(249).setName("嘿嘿嘿");
userMapper.updateUserById(user);
}
//5.删除demo_user表中name为哈哈哈的数据
@Test
public void deleteUser(){
String name="哈哈哈";
userMapper.deleteUserByName(name);
}
//6.查询demo_user表中id为7的数据
@Test
public void testFindUserById(){
int id=7;
User user=userMapper.testFindUserById(id);
System.out.println(user);
}
//7.查询demo_user表中年龄大于18且小于20的数据
@Test
public void findUserByMap(){
Map map=new HashMap<>();
map.put("minAge",18);
map.put("maxAge",20);
List<User> userList=userMapper.findUserByMap(map);
System.out.println(userList);
}
//8.指定字段作为查询条件 查询demo_user表的数据
@Test
public void findUserByColumn(){
String column="age";
int age=18;
Map map=new HashMap();
map.put("column",column);
map.put("age",age);
List userList=userMapper.findUserByColumn(map);
System.out.println(userList);
}
//9.查询demo_user表中 年龄大于10且小于18的数据 值传递
@Test
public void findUserByParam(){
int minId=10;
int maxId=18;
List<User> userList=userMapper.findUserByMId(minId, maxId);
System.out.println(userList);
}
//10.查询demo_user表中 name值含 君 的数据
@Test
public void findUserByLike(){
String name="君";
List<User> userList=userMapper.findUserByLike(name);
System.out.println(userList);
}
//11.查询demo_user表中 id为1,3,4,5,6 的数据
@Test
public void findUserByIn(){
Integer[] array={1,3,4,5,6};
List<User> userList=userMapper.findUserByIn(array);
System.out.println(userList); //数组方式查询
List userIds= Arrays.asList(array);
List<User> list=userMapper.findUserByIds(userIds);
System.out.println(list); // list集合方式查询
}
//13.查询demo_user表中 id为1,3,4,5,6 的数据 map集合方式查询
@Test
public void findUserByInMap(){
Integer[] array={1,3,4,5,6};
Map map=new HashMap();
map.put("ids",array);
List<User> list=userMapper.findUserByIdMap(map);
System.out.println(list);
}
}
3.3 UserMapper 接口
package com.huo.mapper;
import com.huo.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
@Mapper //将接口交给Spring容器管理 Map<userMapper,JDK代理对象>
public interface UserMapper {
//1. 指定接口方法 查询demo_user的全部数据
List<User> findAll();
//2. 新增数据操作 无需返回值
void saveUser(User user);
//3. 新增数据操作 返回影响行数
int saveUser2(User user);
//4. 更据id修改数据
void updateUserById(User user);
//5. 更据name删除表数据
void deleteUserByName(String name);
//6. 更据id查询数据 单值传递
User testFindUserById(int id);
//7. map封装两个年龄值 查询符合年龄段的数据
List<User> findUserByMap(Map map);
//8. 随意的字段和值作为查询条件 查询数据
List findUserByColumn(Map map);
//9. 将传的多值 封装到map中 mybatis只能接受单值
List findUserByMId(@Param("minId") int minId,
@Param("maxId") int maxId);
//10. 模糊查询 like关键字使用
List<User> findUserByLike(String name);
//11. 多值查询 使用集合类型 数组 in关键字使用
List<User> findUserByIn(Integer[] array);
//12. 多值查询 使用集合类型 list in关键字使用
List<User> findUserByIds(List userIds);
//13. 多值查询 使用集合类型 map in关键字使用
List<User> findUserByIdMap(Map map);
}
3.4 UserMapper.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">
<!--namespace是mybaits映射文件的唯一标识,与接口对应-->
<mapper namespace="com.huo.mapper.UserMapper">
<!--执行业务操作:id: 与接口方法一一对应.
resultType: 返回的POJO对象类型全路径
将结果集自动的封装为对象-->
<!--1. 指定接口方法 查询demo_user的全部数据-->
<select id="findAll" resultType="com.huo.pojo.User">
select * from demo_user
</select>
<!--2. 新增数据操作 无需返回值-->
<insert id="saveUser">
insert into demo_user(id,name,age,sex) value (null,#{name},#{age},#{sex})
</insert>
<!--3. 新增数据操作 返回影响行数-->
<insert id="saveUser2">
insert into demo_user(id,name,age,sex) value (null,#{name},#{age},#{sex})
</insert>
<!--4. 更据id修改数据-->
<update id="updateUserById">
update demo_user set name=#{name} where id=#{id}
</update>
<!--5. 更据name删除表数据-->
<delete id="deleteUserByName">
delete from demo_user where name=#{name}
</delete>
<!--6. 更据id查询数据 单值传递-->
<select id="testFindUserById" resultType="com.huo.pojo.User">
select * from demo_user where id=#{id}
</select>
<!--7. map封装两个年龄值 查询符合年龄段的数据-->
<select id="findUserByMap" resultType="com.huo.pojo.User">
<![CDATA[select * from demo_user where age > #{minAge} and age < #{maxAge}]]>
</select>
<!--8. 随意的字段和值作为查询条件 查询数据-->
<select id="findUserByColumn" resultType="com.huo.pojo.User">
select * from demo_user where ${column}=#{age}
</select>
<!--9. 将传的多值 封装到map中 mybatis只能接受单值-->
<select id="findUserByMId" resultType="com.huo.pojo.User">
select * from demo_user where id>#{minId} and id < #{maxId}
</select>
<!--10. 模糊查询 like关键字使用-->
<select id="findUserByLike" resultType="User">
<include refid="selectDemoUser" /> where name like "%" #{name} "%"
</select>
<!--sql 标签 解决重复代码多次编辑问题 与include标签搭配使用-->
<sql id="selectDemoUser">
select id,name,age,sex from demo_user
</sql>
<!--11. 多值查询 使用集合类型 数组 in关键字使用
foreach 循环标签 collection: 数组array List集合List map集合key
open/close 开始结束标签 可以为null
item 定义取值变量 #{item的值} separator 分割符-->
<select id="findUserByIn" resultType="User">
select * from demo_user where id in
<foreach collection="array" open="(" close=")"
item="id" separator=",">#{id}</foreach>
</select>
<!--12. 多值查询 使用集合类型 list in关键字使用-->
<select id="findUserByIds" resultType="User">
select * from demo_user where id in
<foreach collection="list" open="(" close=")"
item="id" separator=",">#{id}</foreach>
</select>
<!--13. 多值查询 使用集合类型 map in关键字使用-->
<select id="findUserByIdMap" resultType="user">
<include refid="selectDemoUser" /> where id in(
<foreach collection="ids" item="id" separator=",">#{id}</foreach>
)
</select>
</mapper>
4. Mybatis—动态sql操作练习
4.1 TestMybatis2 测试类
package com.huo.mapper;
import com.huo.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface UserMapper2 {
//1. 更据对象中不为null的属性,查询数据 通用方法
List<User> testFindUser(User user);
//2. 更据对象中不为null的属性进行更新操作,id为唯一条件 通用方法
void updateUser(User user);
//3.如果name有值按照name查询,如果age有值按照age查询,否则按照sex查询
List<User> findUserChoose(User user);
}
4.2 UserMapper2 接口
package com.huo.mapper;
import com.huo.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface UserMapper2 {
//1. 更据对象中不为null的属性,查询数据 通用方法
List<User> testFindUser(User user);
//2. 更据对象中不为null的属性进行更新操作,id为唯一条件 通用方法
void updateUser(User user);
//3.如果name有值按照name查询,如果age有值按照age查询,否则按照sex查询
List<User> findUserChoose(User user);
}
4.3 UserMapper2.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="com.huo.mapper.UserMapper2">
<!--1. 更据对象中不为null的属性,查询数据 通用方法
if标签:如果判断为真 则拼接sql
where标签:去除where后边多余的1个and或or-->
<select id="testFindUser" resultType="User">
select * from demo_user
<where>
<if test="id!=null">id=#{id}</if>
<if test="name !=null">and name=#{name}</if>
<if test="age !=null">and age=#{age}</if>
<if test="sex !=null">and sex=#{sex}</if>
</where>
</select>
<!--2. 更据对象中不为null的属性进行更新操作,id为唯一条件 通用方法-->
<update id="updateUser">
update demo_user
<set>
<if test="name != null">name=#{name},</if>
<if test="age != null">age=#{age},</if>
<if test="sex != null">sex=#{sex}</if>
</set>
where id=#{id}
</update>
<!--3.如果name有值按照name查询,如果age有值按照age查询,否则按照sex查询
if elseif else-->
<select id="findUserChoose" resultType="User">
select * from demo_user where
<choose>
<when test="name!=null">name=#{name}</when>
<when test="age!=null">age=#{age}</when>
<otherwise>sex=#{sex}</otherwise>
</choose>
</select>
</mapper>
5. Mybatis—数据封装(resultMap)
5.1 TestMybatis3 测试类
如果结构集中的数据与pojo中的属性名字不对应,则使用restMap属性完成字段与属性的映射
@SpringBootTest
public class TestMybatis3 {
@Autowired
private UserMapper3 userMapper;
@Test
public void testResult(){
List<User> userList=userMapper.findAll();
System.out.println(userList);
}
}
5.2 UserMapper3 接口
@Mapper
public interface UserMapper3 {
List<User> findAll();
}
5.3 UserMapper3.xml 映射文件
<mapper namespace="com.huo.mapper.UserMapper3">
<!--resultType适用于 单表查询&结果集字段与属性一致;
如果resultType不满足要求,就用resultMap完成数据的映射-->
<select id="findAll" resultMap="resultUser">
select id user_id,name user_name,
age user_age,sex user_sex
from demo_user
</select>
<resultMap id="resultUser" type="User">
<!--id表示主键-->
<id column="user_id" property="id" />
<!--其它属性-->
<result column="user_name" property="name" />
<result column="user_age" property="age"/>
<result column="user_sex" property="sex"/>
</resultMap>
</mapper>
6. Mybatis—关联查询
6.1 创建表
员工表:emp表:
部门表:dept表:
6.2 编辑实体类
Emp对象pojo类
package com.huo.pojo;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@Accessors(chain = true)
public class Emp implements Serializable {
private Integer id;
private String name;
private Integer age;
private Dept dept; //部门对象 一对一
}
Dept对象pojo类
package com.huo.pojo;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.List;
@Data
@Accessors(chain = true)
public class Dept implements Serializable {
private Integer deptId;
private String deptName;
private List<Emp> emps; //员工对象 一对多
}
6.3 一对一数据封装
员工对象封装对应部门对象
6.3.1 TestMybatis4 测试类
package com.huo;
import com.huo.mapper.EmpMapper;
import com.huo.pojo.Emp;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
public class TestMybatis4 {
@Autowired
private EmpMapper empMapper;
@Test
public void findEmpAll(){
List<Emp> empList=empMapper.findEmpAll();
System.out.println(empList);
}
}
6.3.1 EmpMapper 接口
@Mapper
public interface EmpMapper {
List<Emp> findEmpAll();
}
6.3.1 EmpMapper.xml 映射文件
<mapper namespace="com.huo.mapper.EmpMapper">
<!--使用关联查询时,不能出现同名字段,否则映射报错-->
<select id="findEmpAll" resultMap="empRM">
select e.*,d.dept_name from emp e left join dept d on e.dept_id = d.dept_id
</select>
<!--autoMapping=“true” 字段名与属性名一致,则自动映射-->
<resultMap id="empRM" type="Emp" autoMapping="true">
<id column="id" property="id"/>
<!--association 一对一封装Dept对象 javaType 固定搭配 封装对象类型-->
<association property="dept" javaType="Dept" autoMapping="true">
<id column="dept_id" property="deptId"/>
<result column="dept_name" property="deptName"/>
</association>
</resultMap>
</mapper>
6.4 一对多数据封装
部门对象封装对应员工对象
6.4.1 TestMybatis4 测试类
package com.huo;
import com.huo.mapper.DeptMapper;
import com.huo.pojo.Dept;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
public class TestMybatis4 {
@Autowired
private DeptMapper deptMapper;
@Test
public void findDeptAll(){
List<Dept> deptList=deptMapper.findDeptAll();
System.out.println(deptList);
}
}
6.4.2 DeptMapper 接口
@Mapper
public interface DeptMapper {
List<Dept> findDeptAll();
}
6.4.3 DeptMapper.xml 映射文件
<mapper namespace="com.huo.mapper.DeptMapper">
<select id="findDeptAll" resultMap="deptRM">
select d.dept_name,e.* from dept d ,emp e where d.dept_id = e.dept_id
</select>
<resultMap id="deptRM" type="Dept" autoMapping="true">
<id column="dept_id" property="deptId" />
<!--开启Mybatis的驼峰映射规则,可以实现自动映射-->
<result column="dept_name" property="deptName"/>
<!-- 一对多封装 collection + ofType 固定搭配 -->
<collection property="emps" ofType="Emp" autoMapping="true">
<id column="id" property="id"/>
</collection>
</resultMap>
</mapper>
7. Mybatis补充
- SqlSessionFactory:作用在内部已经关联了数据库,该设计是工厂模式的一种,目的为了生产SqlSession
- SqlSession:用户利用SqlSession 实现数据库的CURD操作
- 一级缓存:由同一个SqlSession执行的重复的查询操作,则可以自动的实现数据的共享。默认条件下开启。执行重复操作时,一级缓存生效,查询一次数据库。如果查询期间执行更新操作,则一级缓存清空,保证数据都是新的。
- 二级缓存:在同一个SqlSessionFactory中生产的SqlSession内实现数据共享。默认条件下开启。二级缓存需要标记,cache标签。如果需要使用二级缓存,则应该关闭SqlSession。多线程条件下如果需要实现数据共享,则要求数据必须序列化。