Mybatis教程
快速入门
核心配置文件
<?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>
<!--配置日志输出,可以查看底层的sql-->
<settings>
<!--配置mybatis自带的标注日志输出-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!--配置别名,一定要配置在前面-->
<typeAliases>
<typeAlias type="com.yangyi.entity.Monster" alias="Monster"/>
</typeAliases>
<!--配置环境-->
<environments default="development">
<environment id="development">
<!--配置事务管理器-->
<transactionManager type="JDBC"/>
<!--配置数据源-->
<dataSource type="POOLED">
<!--配置驱动-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<!--配置连接mysql-url
老韩解读:
1. jdbc:mysql 协议
2. 127.0.0.1:3306 : 指定连接mysql的ip+port
3. mybatis: 连接的DB
4. useSSL=true 表示使用安全连接
5. & 表示 & 防止解析错误
6. useUnicode=true : 使用unicode 作用是防止编码错误
7. characterEncoding=UTF-8 指定使用utf-8, 防止中文乱码
8. 老韩温馨提示:不要背,直接使用即可
-->
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="hsp"/>
</dataSource>
</environment>
</environments>
<!--配置映射文件-->
<mappers>
<!--配置映射文件路径-->
<mapper resource="com/yangyi/mapper/MonsterMapper.xml"/>
</mappers>
</configuration>
配置接口映射文件
mapper
标签的namespace
属性设置为接口的全类名
- SQL语句标签的id属性配置接口的具体方法,parameterType属性配置方法的形参,resultType属性配置方法的返回值类型,都要与接口中的形参和返回值类型保持一致
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTP Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--mapper映射文件,该文件指定实现接口的方法-->
<!--namespace属性指定该xml文件与接口对应-->
<mapper namespace="com.yangyi.mapper.MonsterMapper">
<!--insert标签表示实现方法的方式,标签内写SQL语句-->
<!--id属性指定实现接口中的方法名-->
<!--parameterType属性表示接口形参的类型-->
<!--resultType属性表示接口的返回类型-->
<!--useGeneratedKeys="true"与 keyProperty="id"配合使用可以获取自增长的id-->
<insert id="addMonster" parameterType="com.yangyi.entity.Monster" useGeneratedKeys="true" keyProperty="id">
insert into monster (age, birthday, email, gender, name, salary) value
(#{age},#{birthday},#{email},#{gender},#{name},#{salary})
</insert>
<delete id="deleteMonster" parameterType="java.lang.Integer">
delete from monster where id = #{id}
</delete>
<!--查询一个monster的接口-->
<select id="selectMonster" parameterType="java.lang.Integer" resultType="com.yangyi.entity.Monster">
select * from monster where id = #{id}
</select>
<!--查询所有monster的接口,返回类型仍然是Monster类型,而不是List类型-->
<select id="selectAllMonster" resultType="Monster">
select * from monster
</select>
<update id="updateMonster" parameterType="Monster">
update monster set age = #{age},birthday = #{birthday},email = #{email},gender = #{gender},name = #{name},salary = #{salary} where id = #{id}
</update>
</mapper>
Monster接口
package com.yangyi.mapper;
import com.yangyi.entity.Monster;
import java.util.List;
/**
* @Projectname: mybatis
* @Filename: MonsterMapper
* @Author: 杨逸
* @Data:2023/9/14 9:52
* @Description: 操作monster表的接口
*/
public interface MonsterMapper {
//添加monster
void addMonster(Monster monster);
//删除
void deleteMonster(Integer id);
//查询一个monster
Monster selectMonster(Integer id);
//查询所有monster
List<Monster> selectAllMonster();
//更新
void updateMonster(Monster monster);
}
使用Mybatis的程序
- mybatis工具类
- 通过Resource对象获取核心配置文件的输入流
- 通过SqlSessionFactory对象获取与数据库通信的session对象
- 通过Session对象获取mapper映射借口的代理对象
- 通过mapper映射代理对象进行对数据库的操作
package com.yangyi.util;
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;
/**
* @Projectname: mybatis
* @Filename: MybatisUtils
* @Author: 杨逸
* @Data:2023/9/14 10:34
* @Description: 工具类
*/
public class MybatisUtils {
public static SqlSessionFactory sqlSessionFactory;
//静态代码块初始化
static {
String resource = "mybatis-config.xml";
try {
InputStream resourceAsStream = Resources.getResourceAsStream(resource);
//获取会话工厂
sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
package com.yangyi.mapper;
import com.yangyi.entity.Monster;
import com.yangyi.util.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Before;
import org.junit.Test;
import java.util.Date;
import java.util.List;
import static org.junit.Assert.*;
/**
* @Projectname: mybatis
* @Filename: MonsterMapperTest
* @Author: 杨逸
* @Data:2023/9/14 10:41
* @Description: 测试方法
*/
public class MonsterMapperTest {
private SqlSession session = null;
private MonsterMapper mapper = null;
/**
* 初始化
*/
@Before
public void init(){
session = MybatisUtils.getSqlSession();
System.out.println("会话对象初始化");
//获取映射对象
mapper = session.getMapper(MonsterMapper.class);
}
/**
* 插入数据
*/
@Test
public void addMonster() {
Monster monster = new Monster(null,888,"kk1","1231@163.com",new Date(),9899,1);
//插入一条数据
mapper.addMonster(monster);
System.out.println("插入一条数据");
//获取插入数据的子增长id
System.out.println("monster.getId() = " + monster.getId());
//提交事务,默认是不提交的
session.commit();
session.close();
}
/**
* 删除
*/
@Test
public void deleteMonster(){
System.out.println("删除monster");
mapper.deleteMonster(1);
session.commit();
session.close();
}
/**
* 查询一个monster
*/
@Test
public void selectMonster(){
Monster monster = mapper.selectMonster(3);
System.out.println("查询");
System.out.println("monster = " + monster);
session.close();
}
/**
* 查询所有monster
*/
@Test
public void selectAllMonster(){
List<Monster> monsters = mapper.selectAllMonster();
System.out.println("查询所有monster");
for (Monster monster : monsters) {
System.out.println(monster);
}
}
/**
* 更新
*/
@Test
public void updateMonster(){
Monster monster = new Monster(3,988,"jjj","123123@163.com",new Date(),98939,0);
System.out.println("数据更新");
mapper.updateMonster(monster);
session.commit();
session.close();
}
}
启用mybatis的日志
<!--配置日志输出,可以查看底层的sql-->
<settings>
<!--配置mybatis自带的标注日志输出-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
通过SqlSession
操作数据库,调用Mybatis原生API
- 调用时,第一个参数是接口方法的完整名称,第二参数是接口方法的形参列表
package com.yangyi.NavicatAPI;
import com.yangyi.entity.Monster;
import com.yangyi.util.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import java.util.Date;
import java.util.List;
/**
* @Projectname: mybatis
* @Filename: NavicatAPI
* @Author: 杨逸
* @Data:2023/9/19 14:33
* @Description: 演示Mybatis原生curd API的使用
*/
public class NavicatAPI {
private SqlSession session = MybatisUtils.getSqlSession();
public void insert(){
//准备数据
Monster monster = new Monster(null,88,"yy","1231@163.com",new Date(),90899,1);
//第一个参数是映射接口的完整方法名,第二个参数是方法的形参列表
session.insert("com.yangyi.mapper.MonsterMapper.addMonster",monster);
session.commit();
System.out.println("使用Mybatis原生API插入数据成功");
}
public void delete(){
int id = 3;
//第一个参数是映射接口的完整方法名,第二参数是接口方法的形参列表
session.delete("com.yangyi.mapper.MonsterMapper.deleteMonster",id);
session.commit();
System.out.println("使用Mybatis原生API删除数据成功");
}
public void update(){
Monster monster = new Monster(5,88,"yy","1231@163.com",new Date(),90899,1);
session.delete("com.yangyi.mapper.MonsterMapper.updateMonster",monster);
session.commit();
System.out.println("使用Mybatis原生API更新数据成功");
}
public void select(){
List<Object> objects = session.selectList("com.yangyi.mapper.MonsterMapper.selectAllMonster");
for (Object object : objects) {
System.out.println("object = " + object);
}
System.out.println("使用Mybatis原生API查询数据成功");
}
}
Mybatis-config.xml
配置文件的详解
properties
标签
setting
标签
TypeAliases
标签
<typeAliases>
<!--只设置一个别名-->
<typeAlias type="com.yangyi.entity.Monster" alias="Monster"/>
<!--为整个包的类设置别名-->
<package name="com.yangyi.entity"/>
</typeAliases>
typeHandler
类型处理器
- 用于将数据库数据的数据类型转换为java中的数据类型
- 涉及的不多,Mybatis默认的基本够用
environments
环境
SQL映射文件详解
parameterType
:形参的类型,如果形参类型是Map类型,则直接写map即可,不需要写全类名
resultType
:返回值的类型,如果返回的是集合,则设置的集合内元素的类型
- 模糊查询需要使用
${}
进行取出实体中的属性
resultMap
:可以处理实体属性和表字段不一致的问题,在配置文件中直接给表字段设置别名
- 案例
- 映射接口文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTP Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--mapper映射文件,该文件指定实现接口的方法-->
<!--namespace属性指定该xml文件与接口对应-->
<mapper namespace="com.yangyi.mapper.MonsterMapper">
<select id="findMonsterByIdOrByName" parameterType="Monster" resultType="Monster">
select * from monster where id = #{id} or name = #{name}
</select>
<!--模糊查询,查询名字包含指定参数的数据,使用模糊查询的时候,取值需要使用${}-->
<select id="findMonsterByName" resultType="Monster" parameterType="java.lang.String">
select * from monster where name like '%${name}%';
</select>
<!--形参是Map类型,parameterType直接写map即可-->
<select id="findMonsterByIdOrByName_map" parameterType="map" resultType="Monster">
select * from monster where id = #{id} or name = #{name }
</select>
<!--形参和返回类型是Map类型,直接写map即可-->
<select id="findMonster_paramMap_resultMap" parameterType="map" resultType="map">
select * from monster where id = #{id} or name = #{name }
</select>
</mapper>
package com.yangyi.mapper;
import com.yangyi.entity.Monster;
import com.yangyi.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.BeforeClass;
import org.junit.Test;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.*;
/**
* @Projectname: mybatis
* @Filename: MonsterMapperTest
* @Author: 杨逸
* @Data:2023/9/19 16:59
* @Description: 测试类
*/
public class MonsterMapperTest {
private static SqlSession session = null;
private static MonsterMapper mapper = null;
@BeforeClass
public static void init(){
session = MybatisUtils.getSqlSession();
mapper = session.getMapper(MonsterMapper.class);
}
@Test
public void findMonsterByIdOrByName() {
Monster monster = new Monster();
monster.setId(5);
monster.setName("kk");
List<Monster> monsters = mapper.findMonsterByIdOrByName(monster);
for (Monster monster1 : monsters) {
System.out.println("monster1 = " + monster1);
}
System.out.println("按照id或者名称查询数据成功");
}
@Test
public void findMonsterByName() {
List<Monster> k = mapper.findMonsterByName("k");
for (Monster monster : k) {
System.out.println("monster = " + monster);
}
System.out.println("按名称模糊查询成功");
}
@Test
public void findMonsterByIdOrByName_map(){
Map<String,Object> map = new HashMap<>();
map.put("id",5);
map.put("name","kk");
List<Monster> monsters = mapper.findMonsterByIdOrByName_map(map);
for (Monster monster : monsters) {
System.out.println("monster = " + monster);
}
System.out.println("按map查询成功");
}
@Test
public void findMonster_paramMap_resultMap(){
Map<String,Object> map = new HashMap<>();
map.put("id",5);
map.put("name","kk");
List<Map<String, Object>> map1 = mapper.findMonster_paramMap_resultMap(map);
for (Map<String, Object> objectMap : map1) {
for (String s : objectMap.keySet()) {
System.out.println(s + "-->" + objectMap.get(s));
}
}
System.out.println("查询成功");
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTP Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--mapper映射文件,该文件指定实现接口的方法-->
<!--namespace属性指定该xml文件与接口对应-->
<mapper namespace="com.yangyi.mapper.UserMapper">
<!--插入数据时,实体的属性名与表的字段名不一致时,只需要注意引用时使用实体类的属性名即可-->
<insert id="insertUser" parameterType="com.yangyi.entity.User">
insert into users (user_name,user_email) value (#{userName},#{userEmail});
</insert>
<!--配置返回字段的别名与实体类的属性名一致-->
<resultMap id="selectMap" type="com.yangyi.entity.User">
<result column="user_name" property="userName"></result>
<result column="user_email" property="userEmail"></result>
</resultMap>
<!--引用配置的表字段别名-->
<select id="selectAllUser" resultMap="selectMap">
select * from users
</select>
</mapper>
package com.yangyi.entity;
/**
* @Projectname: mybatis
* @Filename: User
* @Author: 杨逸
* @Data:2023/9/20 10:00
* @Description: 实体类-演示实体类与表的字段名不一致的问题
*/
public class User {
private Integer userId;
private String userName;
private String userEmail;
public User() {
}
public User(Integer userId, String userName, String userEmail) {
this.userId = userId;
this.userName = userName;
this.userEmail = userEmail;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserEmail() {
return userEmail;
}
public void setUserEmail(String userEmail) {
this.userEmail = userEmail;
}
@Override
public String toString() {
return "User{" +
"userId=" + userId +
", userName='" + userName + '\'' +
", userEmail='" + userEmail + '\'' +
'}';
}
}
package com.yangyi.mapper;
import com.yangyi.entity.User;
import com.yangyi.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import java.util.List;
import static org.junit.Assert.*;
/**
* @Projectname: mybatis
* @Filename: UserMapperTest
* @Author: 杨逸
* @Data:2023/9/20 10:18
* @Description: 测试
*/
public class UserMapperTest {
private static SqlSession session = null;
private static UserMapper mapper = null;
@BeforeClass
public static void init(){
session = MybatisUtils.getSqlSession();
mapper = session.getMapper(UserMapper.class);
}
@AfterClass
public static void destroy(){
session.close();
}
@Test
public void insertUser() {
User user = new User();
user.setUserName("kk");
user.setUserEmail("kk@163.com");
mapper.insertUser(user);
session.commit();
System.out.println("插入数据成功");
}
@Test
public void selectAllUser() {
List<User> users = mapper.selectAllUser();
for (User user : users) {
System.out.println("user = " + user);
}
System.out.println("实体属性名与表字段名不一致处理,查询成功");
}
}
动态SQL
package com.yangyi.mapper;
import com.yangyi.entity.Monster;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
* @Projectname: mybatis
* @Filename: MonsterMapper
* @Author: 杨逸
* @Data:2023/9/14 9:52
* @Description: 操作monster表的接口
*/
public interface MonsterMapper {
//演示if标签的使用,类似单分支
//查询年龄大于age的数据,如果age为负数,则查询所有数据
//注解@Param的value属性的设置要与映射文件里test里的值保持一致,动态SQL的if标签的test才能取值
List<Monster> selectMonsterByAge(@Param(value = "age") Integer age);
//演示where标签的使用
//形参是对象时,不需要使用@Param注解
List<Monster> selectMonsterByIdAndByName(Monster monster);
//演示choose标签的使用,类似多分支
//如果name不空,就使用name进行查询
//如果id>0,就使用id进行查询
//否则使用salary>1000进行查询
List<Monster> selectMonsterByIdOrName(Map<String,Object> map);
//演示foreach标签的使用
List<Monster> selectMonsterById_foreach(Map<String,Object> map);
//演示trim标签的使用
List<Monster> selectMonsterByIdAndName_trim(Map<String,Object> map);
//演示set标签的使用
void updateMonster_set(Map<String,Object> map);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTP Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--mapper映射文件,该文件指定实现接口的方法-->
<!--namespace属性指定该xml文件与接口对应-->
<mapper namespace="com.yangyi.mapper.MonsterMapper">
<!--if标签的使用-->
<select id="selectMonsterByAge" parameterType="java.lang.Integer" resultType="Monster">
select * from monster where 1=1 <if test="age >= 10"> and age > #{age}</if>
</select>
<!--where标签的使用-->
<!--where标签会自动带上where关键字,不需要我们手动添加,标签内if标签的and关键字一定要加,最后拼接SQL的时候Mybatis会将多余的and关键字去掉-->
<select id="selectMonsterByIdAndByName" resultType="Monster" parameterType="Monster">
select * from monster
<where>
<if test="id > 4">AND id > #{id}</if>
<if test="name != null and name != ''">AND name = #{name}</if>
</where>
</select>
<!--choose标签的使用,配置when标签和otherwise标签使用-->
<select id="selectMonsterByIdOrName" parameterType="map" resultType="Monster">
select * from monster
<choose>
<when test="name != null and name != ''">WHERE name = #{name}</when>
<when test="id > 0">WHERE id = #{id}</when>
<otherwise>WHERE salary > 1000</otherwise>
</choose>
</select>
<!--演示foreach标签的使用-->
<!--collection表示集合的名称,item表示遍历是元素的名称,open表示拼接开始字符,close表示拼接结束的字符,separator表示拼接的分割字符-->
<select id="selectMonsterById_foreach" parameterType="map" resultType="Monster">
select * from monster
<if test="ids != null and ids != '' ">
<where>
id IN <foreach collection="ids" open="(" close=")" separator="," item="id">#{id}</foreach>
</where>
</if>
</select>
<!--演示trim标签的使用,使用trim可以实现定制where标签,用的比较少-->
<select id="selectMonsterByIdAndName_trim" resultType="Monster" parameterType="map">
select * from monster
<trim prefix="WHERE" prefixOverrides="and|or|hsp">
<!--前缀替换,当前缀是and或者or或者hsp时,替换为WHERE,也可以使用后缀替换.与前缀替换类似-->
<!--如果该标签内的SQL的拼接后,第一个关键字是and或者or或者hsp时,会将第一个关键字替换为WHERE-->
<if test="id > 4">AND id > #{id}</if>
<if test="name != null and name != ''">AND name = #{name}</if>
</trim>
</select>
<!--演示set标签的使用,注意最后要带上逗号分割-->
<update id="updateMonster_set" parameterType="map">
update monster
<set>
<if test="age != null and age != '' ">
age = #{age},
</if>
<if test="birthday != null and birthday != '' ">
birthday = #{birthday},
</if>
<if test="email != null and email != '' ">
email = #{email},
</if>
<if test="gender != null and gender != '' ">
gender = #{gender},
</if>
<if test="name != null and name != '' ">
name = #{name},
</if>
<if test="salary != null and salary != '' ">
salary = #{salary},
</if>
</set>
WHERE id = #{id}
</update>
</mapper>
package com.yangyi.mapper;
import com.yangyi.entity.Monster;
import com.yangyi.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.BeforeClass;
import org.junit.Test;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import static org.junit.Assert.*;
/**
* @Projectname: mybatis
* @Filename: MonsterMapperTest
* @Author: 杨逸
* @Data:2023/9/20 10:55
* @Description: 测试
*/
public class MonsterMapperTest {
private static SqlSession session = null;
private static MonsterMapper mapper = null;
@BeforeClass
public static void init(){
session = MybatisUtils.getSqlSession();
mapper = session.getMapper(MonsterMapper.class);
}
@Test
public void selectMonsterByAge() {
List<Monster> monsters = mapper.selectMonsterByAge(10);
for (Monster monster : monsters) {
System.out.println("monster = " + monster);
}
System.out.println("使用动态SQL查询成功");
}
@Test
public void selectMonsterByIdAndByName(){
Monster monster = new Monster();
monster.setId(5);
monster.setName("杨逸");
List<Monster> monsters = mapper.selectMonsterByIdAndByName(monster);
for (Monster m : monsters) {
System.out.println("m = " + m);
}
System.out.println("演示where标签查询数据成功");
}
@Test
public void selectMonsterByIdOrName(){
HashMap<String, Object> map = new HashMap<>();
map.put("name","杨逸");
List<Monster> monsters = mapper.selectMonsterByIdOrName(map);
for (Monster monster : monsters) {
System.out.println("monster = " + monster);
}
System.out.println("使用choose标签查询成功");
}
@Test
public void selectMonsterById_foreach(){
HashMap<String, Object> map = new HashMap<>();
map.put("ids",new int[]{4,7});
List<Monster> monsters = mapper.selectMonsterById_foreach(map);
for (Monster monster : monsters) {
System.out.println("monster = " + monster);
}
System.out.println("使用foreach标签查询成功");
}
@Test
public void selectMonsterByIdAndName_trim(){
HashMap<String, Object> map = new HashMap<>();
map.put("name","杨逸");
map.put("id",4);
List<Monster> monsters = mapper.selectMonsterByIdAndName_trim(map);
for (Monster monster : monsters) {
System.out.println("monster = " + monster);
}
System.out.println("使用trim标签查询成功");
}
@Test
public void updateMonster_set(){
HashMap<String, Object> map = new HashMap<>();
map.put("id",8);
map.put("birthday","2022-09-11");
mapper.updateMonster_set(map);
session.commit();
System.out.println("使用set标签更新数据成功");
}
}
映射关系
一对一映射关系
package com.yangyi.entity;
/**
* @Projectname: mybatis
* @Filename: Person
* @Author: 杨逸
* @Data:2023/9/21 9:44
* @Description: 实体类
*/
public class Person {
private Integer id;
//对应的card实体,后面通过映射实现赋值
private IdentityCard card;
private String name;
public Person() {
}
public Person(Integer id, IdentityCard card, String name) {
this.id = id;
this.card = card;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public IdentityCard getCard() {
return card;
}
public void setCard(IdentityCard card) {
this.card = card;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", card=" + card +
", name='" + name + '\'' +
'}';
}
}
package com.yangyi.entity;
/**
* @Projectname: mybatis
* @Filename: IdentityCard
* @Author: 杨逸
* @Data:2023/9/21 9:43
* @Description: 实体类
*/
public class IdentityCard {
private Integer id;
private String card_sn;
public IdentityCard() {
}
public IdentityCard(Integer id, String card_sn) {
this.id = id;
this.card_sn = card_sn;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getCard_sn() {
return card_sn;
}
public void setCard_sn(String card_sn) {
this.card_sn = card_sn;
}
@Override
public String toString() {
return "IdentityCard{" +
"id=" + id +
", card_sn='" + card_sn + '\'' +
'}';
}
}
public interface IdentityCardMapper {
IdentityCard getIdentityCardById(Integer id);
}
public interface PersonMapper {
//第一种配置级联查询
Person selectPersonById1(Integer id);
//第二种配置级联查询
Person selectPersonById2(Integer id);
}
package com.yangyi.mapper;
import com.yangyi.entity.Person;
import org.apache.ibatis.annotations.One;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
/**
* @Projectname: mybatis
* @Filename: PersonMapperAnnotation
* @Author: 杨逸
* @Data:2023/9/21 11:16
* @Description: 通过注解的形式实现级联查询
*/
public interface PersonMapperAnnotation {
//注解本质就是对映射xml文件的体现
@Select(value = "select * from person where id = #{id}")
//通过@Results配置resultMap
@Results(value = {
@Result(id = true,property = "id",column = "id"),
@Result(property = "name",column = "name"),
//one指定返回一个数据,select指定查询数据的映射接口
@Result(property = "card",column = "card_id",one = @One(select = "com.yangyi.mapper.IdentityCardMapper.getIdentityCardById"))
})
Person selectPersonById(Integer id);
}
- 映射配置文件
IdentityCradMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTP Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--mapper映射文件,该文件指定实现接口的方法-->
<!--namespace属性指定该xml文件与接口对应-->
<mapper namespace="com.yangyi.mapper.IdentityCardMapper">
<select id="getIdentityCardById" parameterType="java.lang.Integer" resultType="IdentityCard">
select * from identity_card where id = #{id}
</select>
</mapper>
PersonMapper.xml
- 通过标签
association
配置级联属性的查询映射
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTP Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yangyi.mapper.PersonMapper">
<!--级联查询的第一种配置方式-->
<resultMap id="PersonMap1" type="Person">
<!--id标签一般使用在映射主键上-->
<id property="id" column="id"></id>
<!--result用在一般字段上-->
<result property="name" column="name"></result>
<!--association标签用在映射级联属性,property指定级联属性的名称,javaType指定级联属性的类型-->
<association property="card" javaType="IdentityCard">
<result property="id" column="id"></result>
<result property="card_sn" column="card_sn"></result>
</association>
</resultMap>
<!--级联属性查询,封装-->
<select id="selectPersonById1" parameterType="java.lang.Integer" resultMap="PersonMap1">
select * from person,identity_card where card_id = identity_card.id and person.id = #{id};
</select>
<!--第二种配置级联查询,将多表查询,拆解为单表查询,提高复用性-->
<resultMap id="PersonMap2" type="Person">
<id property="id" column="id"></id>
<result property="name" column="name"></result>
<!--将联机属性通过另一个映射接口查询出来,column指定将查询出的字段作为参数传入另一个查询接口,select指定将要调用的映射接口的完整名称-->
<association property="card" column="card_id" select="com.yangyi.mapper.IdentityCardMapper.getIdentityCardById"></association>
</resultMap>
<select id="selectPersonById2" parameterType="java.lang.Integer" resultMap="PersonMap2">
select * from person where id = #{id}
</select>
</mapper>
- 测试
IdentityCardMapper
接口的测试
package com.yangyi.mapper;
import com.yangyi.entity.IdentityCard;
import com.yangyi.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* @Projectname: mybatis
* @Filename: IdentityCardMapperTest
* @Author: 杨逸
* @Data:2023/9/21 10:48
* @Description: 测试
*/
public class IdentityCardMapperTest {
private static SqlSession session = null;
private static IdentityCardMapper mapper = null;
@BeforeClass
public static void init(){
session = MybatisUtils.getSqlSession();
mapper = session.getMapper(IdentityCardMapper.class);
}
@AfterClass
public static void destroy(){
session.close();
}
@Test
public void getIdentityCardById() {
int id = 1;
IdentityCard identityCardById = mapper.getIdentityCardById(id);
System.out.println("identityCardById = " + identityCardById);
System.out.println("查询成功");
}
}
package com.yangyi.mapper;
import com.yangyi.entity.Person;
import com.yangyi.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* @Projectname: mybatis
* @Filename: PersonMapperTest
* @Author: 杨逸
* @Data:2023/9/21 11:08
* @Description: 测试
*/
public class PersonMapperTest {
private static SqlSession session = null;
private static PersonMapper mapper = null;
@BeforeClass
public static void init(){
session = MybatisUtils.getSqlSession();
mapper = session.getMapper(PersonMapper.class);
}
@AfterClass
public static void destroy(){
session.close();
}
@Test
public void selectPersonById1() {
int id = 1;
Person person = mapper.selectPersonById1(id);
System.out.println("person = " + person);
System.out.println("第一种配置级联查询成功");
}
@Test
public void selectPersonById2() {
int id = 1;
Person person = mapper.selectPersonById2(id);
System.out.println("person = " + person);
System.out.println("第二种级联查询成功");
}
}
PersonMapperAnnotation
使用注解的接口测试
package com.yangyi.mapper;
import com.yangyi.entity.Person;
import com.yangyi.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* @Projectname: mybatis
* @Filename: PersonMapperAnnotationTest
* @Author: 杨逸
* @Data:2023/9/21 11:24
* @Description: 注解测试
*/
public class PersonMapperAnnotationTest {
private static SqlSession session = null;
private static PersonMapperAnnotation mapper = null;
@BeforeClass
public static void init(){
session = MybatisUtils.getSqlSession();
mapper = session.getMapper(PersonMapperAnnotation.class);
}
@AfterClass
public static void destroy(){
session.close();
}
@Test
public void selectPersonById() {
int id = 1;
Person person = mapper.selectPersonById(id);
System.out.println("person = " + person);
System.out.println("通过注解查询级联属性成功");
}
}
一对多映射关系
package com.yangyi.entity;
import java.util.List;
/**
* @Projectname: mybatis
* @Filename: User
* @Author: 杨逸
* @Data:2023/9/21 15:48
* @Description: 实体类
*/
public class User {
private Integer id;
private String name;
private List<Pet> pets;
public User() {
}
public User(Integer id, String name, List<Pet> pets) {
this.id = id;
this.name = name;
this.pets = pets;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Pet> getPets() {
return pets;
}
public void setPets(List<Pet> pets) {
this.pets = pets;
}
}
package com.yangyi.entity;
/**
* @Projectname: mybatis
* @Filename: Pet
* @Author: 杨逸
* @Data:2023/9/21 15:59
* @Description: 实体类
*/
public class Pet {
private Integer id;
private String nickname;
private User user;
public Pet() {
}
public Pet(Integer id, String nickname, User user) {
this.id = id;
this.nickname = nickname;
this.user = user;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
public interface PetMapper {
List<Pet> selectPetByUserId(Integer id);
Pet selectPetById(Integer id);
}
public interface UserMapper {
User selectUserById(Integer id);
}
package com.yangyi.mapper;
import com.yangyi.entity.Pet;
import org.apache.ibatis.annotations.*;
import java.util.List;
/**
* @Projectname: mybatis
* @Filename: PetMapperAnnotation
* @Author: 杨逸
* @Data:2023/9/21 16:59
* @Description: 使用注解实现一对多级联查询
*/
public interface PetMapperAnnotation {
@Select(value = "select * from pet where user_id = #{id}")
//使用id属性设置ResultMap的名称,可以进行复用
@Results(id = "PetMap",value = {
@Result(id = true,property = "id",column = "id"),
@Result(property = "nickname",column = "nickname"),
@Result(property = "user",column = "user_id",one = @One(select = "com.yangyi.mapper.UserMapperAnnotation.selectUserById"))
})
List<Pet> selectPetByUserId(Integer id);
@Select(value = "select * from pet where id = #{id}")
//使用@ResultMap注解复用以前定义的ResultMap
@ResultMap(value = "PetMap")
Pet selectPetById(Integer id);
}
package com.yangyi.mapper;
import com.yangyi.entity.User;
import org.apache.ibatis.annotations.*;
/**
* @Projectname: mybatis
* @Filename: UserMapperAnnotation
* @Author: 杨逸
* @Data:2023/9/21 16:54
* @Description: 演示通过注解实现一对多的级联查询
*/
public interface UserMapperAnnotation {
@Select(value = "select * from user where id = #{id}")
@Results(value = {
@Result(id = true,property = "id",column = "id"),
@Result(property = "name",column = "name"),
//返回的集合类型使用的是many属性
@Result(property = "pets",column = "id",many = @Many(select = "com.yangyi.mapper.PetMapperAnnotation.selectPetByUserId"))
})
User selectUserById(Integer id);
}
- 映射配置文件
- 使用
collection
标签进行一对多的级联映射,ofType
属性表示集合元素的类型
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTP Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yangyi.mapper.PetMapper">
<!--演示一对多的级联查询-->
<resultMap id="PetMap" type="Pet">
<id property="id" column="id"/>
<result property="nickname" column="nickname"/>
<association property="user" column="user_id" select="com.yangyi.mapper.UserMapper.selectUserById"/>
</resultMap>
<select id="selectPetByUserId" parameterType="Integer" resultMap="PetMap">
select * from pet where user_id = #{id}
</select>
<select id="selectPetById" parameterType="Integer" resultMap="PetMap">
select * from pet where id = #{id}
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTP Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yangyi.mapper.UserMapper">
<!--演示一对多的级联查询-->
<resultMap id="UserMap" type="User">
<id property="id" column="id"/>
<result property="name" column="name"/>
<!--使用collection标签进行一对多的级联映射,ofType属性表示集合元素的类型-->
<collection property="pets" column="id" ofType="Pet" select="com.yangyi.mapper.PetMapper.selectPetByUserId"/>
</resultMap>
<select id="selectUserById" parameterType="Integer" resultMap="UserMap">
select * from user where id = #{id}
</select>
</mapper>
缓存
- 缓存是将从数据库查询到的数据保存到内存中,避免重复操作数据库,减少数据库的开销
- 缓存中有目标数据时,mybatis就不会向数据库发起查询请求
缓存的全局配置
- 配置缓存的全局开关,默认true,如果关闭了则所有缓存都失效
<settings>
<!--配置缓存的全局开关,默认true,如果关闭了则所有缓存都失效-->
<setting name="cacheEnabled" value="true"/>
</settings>
一级缓存
- 一级缓存默认开启,一级缓存是Session会话级别的,同一个会话,会有一级缓存的效果
- 当会话关闭后,一级缓存会失效
- 使用
session.clearCache()
手动清空缓存后,一级缓存也会失效
- 当修改了同一个对象时,一级缓存也会失效
二级缓存
- 二级缓存和一级缓存都是为了提高检索效率的技术
- 最大的区别就是作用域的范围不一样,一级缓存的作用域是sqlSession会话级别,在一次会话有效,而二级缓存作用域是全局范围,针对不同的会话都有效
- 启用二级缓存时,实体推荐实现
Serializable
可序列化接口,因为有些缓存策略会讲数据进行序列化,实现可序列化能避免出现异常
- 当session关闭时,一级缓存的数据会放到二级缓存,如果二级缓存开启的话
- 不会出现一级缓存和二级缓存中有同一个数据。因为二级缓存是在一级缓存关闭之后才有的
在映射配置文件中开启二级缓存
- size表示最多保存数据引用的数量
- readOnly表示缓存只读不能被修改,默认是false
- flushInterval表示缓存刷新的时间,单位是毫秒
- eviction表示缓存刷新的策略,LRU表示最近最少使用
<!--开启二级缓存,size表示最多保存数据引用的数量,readOnly表示缓存只读不能被修改,默认是false,
flushInterval表示缓存刷新的时间,单位是毫秒,eviction表示缓存刷新的策略,LRU表示最近最少使用-->
<cache size="1024" readOnly="true" flushInterval="60000" eviction="LRU"></cache>
<select useCache="false" flush="true"></select>