mybatis从0到1
前沿
本文主要介绍mybatis的学习,用惯了springboot的快速搭建,似乎都忘了mybatis的一开始的原始搭建。这边重新学习一下,主要为了给自己巩固,为了更好的理解springboot到底帮你做了啥,能够更好的理解springboot的底层源码。如果是初学的你,也希望给你一个指引。
基础: 至少了解过maven
准备工作
-
使用idea,点击file->new->project->maven项目
结果:
2.必须加载jar包
mysql-connector-java: 下载合适版本
mybatis
辅助工具包:
lombok: 实体类友好
junit: 测试包
个人的下载版本: 可以做参考
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.duncan</groupId>
<artifactId>mybatis-myself</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
入门
关键网址: mybatis中文网
配置文件
- 在resources的目录下创建SqlMapperConfig.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>
<environments default="development">
<environment id="development">
<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>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/> <!-- 映射的文件,这个之后都不是手动添加,这里一定记得改,而且是 / -->
</mappers>
</configuration>
数据库准备
现有数据库表 Teacher: id name(数据库方面不会的话可以去看mysql的教程)
创建pojo
package com.duncan.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {
private Integer id;
private String name;
}
创建查询xml
目录:
上面的目录,最好逐级创建,不要直接 com.duncan.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="aaa">
<select id="selectTeacher" resultType="com.duncan.pojo.Teacher">
select `id`,`name` from teacher
</select>
</mapper>
测试查询
利用junit测试类,和sqlsession进行测试(以后不用手动写sqlsession)
- 编写测试类
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class MybatisTestDemo1 {
@Before
public void init() {
// 获取sql_session
}
@Test
public void selectTeacher() {
// 具体逻辑
}
@After
public void release() {
// 释放
}
}
- 编写测试代码
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class MybatisTestDemo1 {
private SqlSession session = null;
@Before
public void init() throws IOException {
// 获取sql_session
// 创建一个工厂
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
InputStream inputStream = null;
inputStream = Resources.getResourceAsStream("SqlMapperConfig.xml"); // 加载配置文件 // 需要抛出异常
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream); // 流加载,将配置加载
session = sqlSessionFactory.openSession();
}
@Test
public void selectTeacher() {
// 具体逻辑
List<Teacher> list = session.selectList("selectTeacher"); // 配置文件中的id
for(Teacher l : list) {
System.out.println(l.getId() + ": " + l.getName());
}
}
@After
public void release() {
// 释放
session.close();
}
}
测试结果:
日志
日志配置-log4j
1.log4j1
maven的配置文件
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
- 在resources的目录下配置log4j.properties(必须这么命名)
# 日志的级别 error,warn,info,debug
log4j.rootLogger=debug,stdout
#log4j.rootLogger=debug,logfile 日志输出到文件
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=/duncan/mybatis.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %l %F %p %m%n
- 测试结果(红色的就是日志的输出)
2.log4j2
maven的配置文件
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.1</version>
</dependency>
- 在resources的目录下配置log4j2.xml
<?xml version="1.0" encoding="UTF-8" ?>
<configuration status="debug" monitorInterval="5">
<properties>
<property name="LOG_HOME">/duncan</property>
</properties>
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] [%-5level] %c{36}:%L --- %m%n" />
</Console>
<!-- <File name="file" fileName="${LOG_HOME}/myfile.log">-->
<!-- <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %m%n" />-->
<!-- </File>-->
<!-- <RandomAccessFile name="accessFile" fileName="${LOG_HOME}/myAcclog.log">-->
<!-- <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %m%n" />-->
<!-- </RandomAccessFile>-->
<!-- <RollingFile name="rollingFile" fileName="${LOG_HOME}/myrollog.log"-->
<!-- filePattern="E:/logs/$${date:yyyy-MM-dd}/myrollog-%d{yyyy-MM-dd-HH-mm}-%i.log">-->
<!-- <ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY" />-->
<!-- <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %msg%n" />-->
<!-- <Policies>-->
<!-- <OnStartupTriggeringPolicy />-->
<!-- <SizeBasedTriggeringPolicy size="10 MB" />-->
<!-- <TimeBasedTriggeringPolicy />-->
<!-- </Policies>-->
<!-- <DefaultRolloverStrategy max="30" />-->
<!-- </RollingFile>-->
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="Console" />
<!-- 这边可以修改输出的类型选择 -->
</Root>
</Loggers>
</configuration>
- 测试结果
制定日志类型
- 在SqlMapperConfig.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="LOG4J2"/>
</settings>
<!-- =============== -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:8889/health?useSSL=false&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/duncan/mapper/TeacherMapper.xml"/>
</mappers>
</configuration>
事务的配置
<!-- 这个type的类型还包括 JDBC -->
<transactionManager type="MANAGED">
<property name="closeConnection" value="false"/>
</transactionManager>
类型别名的配置
<typeAliases>
<typeAlias alias="teacher" type="com.duncan.pojo.Teacher"/>
<typeAlias alias="blog" type="com.duncan.pojo.Blog"/>
</typeAliases>
如果实体的类特别多可以用 的标签
<typeAliases>
<package name="com.duncan.pojo"/>
</typeAliases>
外部链接配置
为了对某些配置解偶,增强模块的内聚性: 例如springboot中我们直接在yml配置数据库的信息
- 已数据库链接为例:在resources目录下创建 jdbc.properties
mysql_driver=com.mysql.jdbc.Driver
mysql_url=jdbc:mysql://localhost:8889/health?useSSL=false&useUnicode=true&characterEncoding=UTF-8
mysql_username=root
mysql_password=root
- 在SqlMapperConfig.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>
<!-- 加的这个 也可以在这边直接定义,但是就没有解偶,所以不建议 -->
<properties resource="jdbc.properties"/>
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${mysql_driver}"/>
<property name="url" value="${mysql_url}"/>
<property name="username" value="${mysql_username}"/>
<property name="password" value="${mysql_password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/duncan/mapper/TeacherMapper.xml"/>
</mappers>
</configuration>
普通模式
查询,有参,无参
这个部分结果图就不贴了,可以自行测试
xml的配置,resultType: 定义返回的类型,parameterType: 定义传入的参数,多个参数可以用map和对象的方式
<select id="selectTeacher" resultType="Teacher">
select `id`,`name` from teacher
</select>
<select id="selectTeacherToMap" resultType="map">
select `id`,`name` from teacher
</select>
<select id="selectOneTeacher" resultType="Teacher">
select `id`,`name` from teacher LIMIT 1
</select>
<select id="selectOneTeacherById" resultType="Teacher" parameterType="Long">
select `id`,`name` from teacher where id = #{id}
</select>
<select id="selectOneTeacherByMapId" resultType="Teacher" parameterType="map">
select `id`,`name` from teacher where id = #{id}
</select>
<select id="selectOneTeacherByObjectId" resultType="Teacher" parameterType="Teacher">
select `id`,`name` from teacher where id = ${id}
</select>
测试代码(接着之前的sqlsession写的)
@Test
public void selectTeacher() {
// 具体逻辑
List<Teacher> list = session.selectList("selectTeacher"); // 配置文件中的id
for(Teacher l : list) {
System.out.println(l.getId() + ": " + l.getName());
}
}
@Test
public void selectOneTeacher() {
Teacher teacher = session.selectOne("selectOneTeacher");
System.out.println("selectOneTeacher --> " + teacher.getName());
}
@Test
public void selectTeacherToMap() {
Map<Long, Teacher> map = session.selectMap("selectTeacherToMap", "id");
Iterator<Map.Entry<Long, Teacher>> iterator = map.entrySet().iterator();
System.out.println();
while (iterator.hasNext()) {
Map.Entry<Long, Teacher> m = iterator.next();
System.out.println(m.getKey() + ": " + m.getValue());
}
// Set<Map.Entry<Long, Teacher>> entrySet = map.entrySet();
// for(Map.Entry<Long, Teacher> entry : entrySet) {
// System.out.println(entry.getKey() + ": " + entry.getValue());
// }
//
// /**
// * 这种形式有些版本不支持
// */
// map.forEach((key, value) -> {
// System.out.println(key + ":" + value);
// });
}
@Test
public void selectOneTeacherById() {
Teacher t = session.selectOne("selectOneTeacherById", (long)9);
System.out.println("selectOneTeacherById: " + t);
}
@Test
public void selectOneTeacherByMapId() {
Map<String, Long> map = new HashMap();
map.put("id", (long)9);
Teacher t = session.selectOne("selectOneTeacherByMapId", map);
System.out.println("selectOneTeacherByMapId: " + t);
}
@Test
public void selectOneTeacherByObjectId() {
Teacher param = new Teacher();
param.setId(9l);
Teacher t = session.selectOne("selectOneTeacherByObjectId", param);
System.out.println("selectOneTeacherByObjectId: " + t);
}
插入,删除,更新
xml的配置,增删改,返回值都是int
<!-- 插入数据 -->
<insert id="addTeacher" parameterType="teacher">
insert into teacher (`id`, `name`) values(#{id}, #{name})
</insert>
<!-- 更新数据 -->
<update id="updateTeacher" parameterType="teacher">
update teacher set `name`=#{name} where `id`=#{id}
</update>
<!-- 删除数据 -->
<delete id="deleteTeacher" parameterType="long">
delete from teacher where id=#{id}
</delete>
Java测试代码
@Test
public void addTeacher() {
Teacher teacher = new Teacher(null, "test");
int rows = session.insert("addTeacher", teacher);
System.out.println(rows);
// 这边mybatis默认不是自动提交的,如果需要自动提交,session = sqlSessionFactory.openSession(true); 初始化的时候加 true
session.commit();
}
@Test
public void updateTeacher() {
Teacher teacher = new Teacher(11l, "test_update");
int rows = session.update("updateTeacher", teacher);
System.out.println(rows);
// 这边mybatis默认不是自动提交的,如果需要自动提交,session = sqlSessionFactory.openSession(true); 初始化的时候加 true
session.commit();
}
@Test
public void delTeacher() {
int rows = session.delete("deleteTeacher", 11l);
System.out.println(rows);
// 这边mybatis默认不是自动提交的,如果需要自动提交,session = sqlSessionFactory.openSession(true); 初始化的时候加 true
session.commit();
}
代理模式开发
为了进一步的解偶,减少sqlsession的使用,不用区使用sqlsession.update,selectOne,insert等,这边使用接口去代替,用代理模式,如果你有一些反射的基础,将更好的理解这个开发,而且这个模式更加符合我们现在常用的的开发模式,后面还会进一步的解偶
- 创建接口文件
2.接口文件的代码
package com.duncan.mapper;
import com.duncan.pojo.Teacher;
import java.util.List;
public interface TeacherMapper {
// 这个方法名字必须和底下的那个id名字一致,因为反射通过这个id去获取方法
// package 和 底下的namespace必须保持一致
public List<Teacher> selectTeacher();
}
3.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.duncan.mapper.TeacherMapper">
<select id="selectTeacher" resultType="Teacher">
select `id`,`name` from teacher
</select>
</mapper>
- 编写测试代码使用
@Test
public void getTeachers() {
TeacherMapper mapper = session.getMapper(TeacherMapper.class); // 这边代理会去自动实现这个接口
List<Teacher> ts = mapper.selectTeacher(); // 直接使用我们定义好的方法就行,就不需要去sqlsession.select/update...
ts.forEach(System.out::println);
}
- 测试的结果
这边其实主要是文件的一致性弄对就可以了
查询的参数传递
- 通过arg*获取
xml的代码
<!-- 0,1代表的是索引值 -->
<select id="getTeacherByArgs" resultType="Teacher">
select `id`,`name` from teacher where `id`=#{arg0} AND `name`=#{arg1}
</select>
java的代码
public Teacher getTeacherByArgs(long id,String name);
测试代码
@Test
public void getTeacher() {
TeacherMapper mapper = session.getMapper(TeacherMapper.class); // 自己会去实现这个接口
Teacher ts = mapper.getTeacherByArgs(9l, "sun");
System.out.println(ts);
}
- 通过param*获取
xml的代码
<select id="getTeacherByParam" resultType="Teacher">
select `id`,`name` from teacher where `id`=#{param1} AND `name`=#{param2}
</select>
java的代码
public Teacher getTeacherByParam(long id,String name);
测试代码
public void getTeacher() {
TeacherMapper mapper = session.getMapper(TeacherMapper.class); // 自己会去实现这个接口
Teacher ts = mapper.getTeacherByParam(9l, "sun");
System.out.println(ts);
}
- 通过@param别名获取
xml代码
<select id="getTeacherByParams" resultType="Teacher">
select `id`,`name` from teacher where `id`=#{id} AND `name`=#{name}
</select>
java代码
public Teacher getTeacherByParams(@Param("id") long id, @Param("name") String name);
测试代码
@Test
public void getTeacher() {
TeacherMapper mapper = session.getMapper(TeacherMapper.class); // 自己会去实现这个接口
Teacher ts = mapper.getTeacherByParams(9l, "sun");
System.out.println(ts);
}
以上就是三种传值的方式,如果是对象,object.property 这种方式获取
需要回传自增的id
xml的配置
<insert id="addTeacherHasId" keyProperty="id" useGeneratedKeys="true">
insert into teacher (`name`) values (#{name})
</insert>
动态sql
IF
主要是不确定查询条件是有的时候
<select id="getDairys" resultType="dairy">
select `id`,`text`,`sleephour`,`mood`,`cigarette`, `weight`,`pressure`,`bphigh`,`bplow`,`bs`,`teacher_id` from `dairy`
where 1 = 1
<if test="id != null">
and `id`=#{id}
</if>
<if test="mood != null and mood != ''">
and `mood`=#{mood}
</if>
<if test="pressure != null">
and `pressure` like concat('%', #{pressure}, '%')
</if>
</select>
where/when
- where标签主要是为了减少1=1的操作,如果只有一个查询条件会自动把and去掉
xml的使用,和上面的结果一样
<select id="getDairys1" resultType="dairy">
select `id`,`text`,`sleephour`,`mood`,`cigarette`, `weight`,`pressure`,`bphigh`,`bplow`,`bs`,`teacher_id` from `dairy`
<where>
<if test="id != null">
and `id`=#{id}
</if>
<if test="mood != null and mood != ''">
and `mood`=#{mood}
</if>
<if test="pressure != null">
and `pressure` like concat('%', #{pressure}, '%')
</if>
</where>
</select>
- when标签,这个一般配合着choose这个标签一起用,其实可以理解为switch case,不过需要注意的是,它只会满足一个条件,就会直接break
<select id="getDairys2" resultType="dairy">
select `id`,`text`,`sleephour`,`mood`,`cigarette`, `weight`,`pressure`,`bphigh`,`bplow`,`bs`,`teacher_id` from `dairy`
<where>
<choose>
<when test="id != null">
and `id`=#{id}
</when>
<when test="mood != null and mood != ''">
and `mood`=#{mood}
</when>
<when test="pressure != null">
and `pressure` like concat('%', #{pressure}, '%')
</when>
</choose>
</where>
</select>
set
- 这个set标签主要是用于数据更新的时候用法类似于where主要是用于自己不知道需要更新啥的做一个统一的配置
具体的配置问津啊
<update id="updateByset" parameterType="dairy">
update `dairy`
<set>
<if test="mood != null and mood != ''">
,`mood`=#{mood}
</if>
<if test="pressure != null">
,`pressure`=#{pressure}
</if>
</set>
where id=#{id}
</update>
trim
- 这个标签其实是可以进行整个拼接字符串的前缀后缀的替换,比如可以替换set
<!-- 语法 -->
<trim prefix="" prefixOverrides="" suffix="" suffixOverrides></trim>
<update id="updateByTrim" parameterType="dairy">
update `dairy`
<trim prefix="set" prefixOverrides=",">
<if test="mood != null and mood != ''">
,`mood`=#{mood}
</if>
<if test="pressure != null">
,`pressure`=#{pressure}
</if>
</trim>
where id=#{id}
</update>
sql片段
- 秉持着多次使用就封装的原则/提取原则这边可以将常用的sql语句进行提取
xml的例子
<!-- 定义 -->
<sql id="columnDairy">`id`,`text`,`sleephour`,`mood`,`cigarette`, `weight`,`pressure`,`bphigh`,`bplow`,`bs`,`teacher_id`</sql>
<!-- 使用 <include refid=""></include> -->
<select id="getDairys2" resultType="dairy">
select <include refid="columnDairy"></include> from `dairy`
<where>
<choose>
<when test="id != null">
and `id`=#{id}
</when>
<when test="mood != null and mood != ''">
and `mood`=#{mood}
</when>
<when test="pressure != null">
and `pressure` like concat('%', #{pressure}, '%')
</when>
</choose>
</where>
</select>
foreach
- 这个标签一般用于in语句中,可以支持array,list
具体的语法
<select id="selectDairyByForeach">
<!-- 类似于 select ... from dairy where `id` in (1,2,3) -->
select <include refid="columnDairy"></include> from `dairy` WHERE `id` in
<foreach collection="array" separator="," open="(" close=")" item="id">
#{id}
</foreach>
<!-- collection 还可以等于 list -->
</select>
多表查询
手动映射
- 如果实体类的属性值和那个mysql的字段值不一致,这个时候可以使用 resultMap做一个配置
具体语法
<resultMap id="dairyMap" type="dairy">
<id column="id" property="id"></id>
<result column="name" property="javaName"/>
</resultMap>
<select id="getDairyInfo" resultMap="dairyMap">
select id,name from dairy
</select>
一对一
- 这个是表示在java实体类中有另外的一个实体类怎么办,可以用association,进行关联
<resultMap id="dairyMap" type="dairy">
<id column="id" property="id"></id>
<result column="name" property="javaName"/>
<association property="teacher" javaType="com.duncan.pojo.Teacher">
<result column="tname" property="name"></result>
</association>
</resultMap>
<select id="getDairyInfoJoinTeacher" resultMap="dairyMap">
select a.id,a.`name`,b.`name` as `tname` from dairy a left join teacher b on a.teacher_id=b.id
</select>
Dairy的实体类修改
public class Dairy {
private Long id;
private String text;
private Double sleephour;
private String mood;
private Integer cigarette;
private Double weight;
private String pressure;
private Double bphigh;
private Double bplow;
private Double bs;
private Long teacherId;
//新增加属性
private Teacher teacher;
}
### 一对多
在java中一对多怎么体现,多其实就是一个集合,所以说只要在实体里面加个集合就好,这边用classroom和teacher来表示,一个教室对应多个老师
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Classroom {
private Long id;
private String name;
private List<Teacher> teachers;
}
那么在xml中如何表示呢?和之前的resultMap是一样的,这边用的标签用的是集合标签 collection,具体案例
<resultMap id="classroomTeacherMap" type="classroom">
<id column="id" property="id"></id>
<result column="name" property="name"/>
<collection property="teachers" ofType="com.duncan.pojo.Teacher">
<id column="t_id" property="id"/>
<result column="tname" property="name"></result>
</collection>
</resultMap>
<select id="classroomJoinTeacher" resultMap="classroomTeacherMap">
select a.id,a.`name`,b.id as t_id ,b.`name` as `tname` from classroom a left join teacher b on b.class_id=a.id where a.id = 1
</select>
结果
多对多
其实多对多是一对一和一对多的集大成,只要记住 1对1 用的就是association,1对多就可以用collection(这里用的是ofType)
如果实在不知道的话,可以联系我
级联查询
这边其实完成的也是一个多表的查询,但是级联查询有个延迟加载,这个时候可以有效的减少一些资源的开销,主要的控制参数其实就是fetchType
<resultMap id="getTeachersByClassId" type="classroom">
<id column="id" property="id"/>
<result property="name" column="name"/>
<!--
select: 需要关联的数据库语言
fetchType: 获取的方式
jdbcType: 参数的类型
column: 需要传的值,和上面的列想对应
-->
<collection property="teachers" select="com.duncan.mapper.TeacherMapper.getTeachersByClassId" fetchType="eager"
jdbcType="INTEGER"
javaType="list"
column="id"
></collection>
</resultMap>
- 延迟加载
这边需要fetchType要变为lazy,同时需要开启这个延迟加载,具体的xml的配置是
<resultMap id="getTeachersByClassId" type="classroom">
<id column="id" property="id"/>
<result property="name" column="name"/>
<collection property="teachers" select="com.duncan.mapper.TeacherMapper.getTeachersByClassId" fetchType="lazy"
jdbcType="INTEGER"
javaType="list"
column="id"
></collection>
</resultMap>
一级缓存
这个是默认开启的,其实这个和mysql底层默认的是一样的,假如两条sql语句是一模一样的,且没有被修改过row, 那么会直接用走缓存,增加效率,它是属于内存级的缓存。其中sqlsession和namespace是一致的
二级缓存
这个不是默认的缓存,不是默认开启的。这里的粒度只要namespace一致就行了,不过这个必须实例化
开启二级缓存
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
在mapper中要开启两个
<mapper namespace="com.duncan.mapper.ClassroomMapper">
<cache/> <!-- 这边一个 -->
<select id="classroomJoinTeacher" resultMap="classroomTeacherMap" useCache="true"> <!-- 这边一个 -->
select a.id,a.`name`,b.id as t_id ,b.`name` as `tname` from classroom a left join teacher b on b.class_id=a.id where a.id = 1
</select>
</mapper>