SSM之MyBatis 01 —— 第一个MyBatis程序、增删改查(模糊查询)
SSM之MyBatis 02 —— 配置文件说明、日志工厂、分页(Limit和RowBounds)
SSM之MyBatis 03 —— 使用注解开发、Lombok、多对一&一对多处理
SSM之MyBatis 04 —— 动态SQL、缓存Cache
关于接口的理解
三个面向的区别
本质:反射机制
我另外有讲注解与反射的博客:Java 注解与反射 01 —— 注解、Java 注解与反射 02 —— 反射
底层:动态代理(前面Java基础的多线程讲过,后面Spring也会详细讲)
1、注解在接口上实现
package com.zcy.dao;
import com.zcy.pojo.User;
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface UserMapper {
@Select("select * from user")
public List<User> getAllUser();
}
2、在核心配置文件中绑定接口
注意这里是用的class方式,因为用注解就不需要用mapper.xml,也就没用resource方式。
<mappers>
<mapper class="com.zcy.dao.UserMapper"/>
mappers>
3、测试
package dao;
import com.zcy.dao.UserMapper;
import com.zcy.pojo.User;
import com.zcy.utils.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class UserMapperTest {
@Test
public void getAllUser(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = userMapper.getAllUser();
for (User user : userList)
System.out.println(user);
sqlSession.close();
}
}
结果:
可以发现,由于实体类User的成员变量和数据库中user表的字段名不一致,导致username和pwd为空,而使用注解方式显然不能用resultMap来解决,官方也说明了注解方式可以让代码更加简介,但那是在比较简单的场景下,大多数复杂情况使用注解只会更加麻烦。
MyBatis详细执行流程(了解)
public class MyBatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
String resource = "mybatis-config.xml";
try {
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
在MyBatisUtils工具类中,通过将文件mybatis-config.xml转为流,然后调用SqlSessionFactoryBuilder的build方法,而在build方法中会调用重载的build,将环境、配置文件等作为XMLConfigBuilder对象封装好,最后在Configuration对象里。
接着才是我们看见的,得到SqlSessionFactory对象,而在我们得到SqlSession对象前,还有事务以及执行器。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UyAQbbmk-1614038856245)(MyBatis2.assets/1613979082099.png)]
关于@Param()注解
1、编写接口,增加注解,注意基本类型的参数需要添加Param注解
package com.zcy.dao;
import com.zcy.pojo.User;
import org.apache.ibatis.annotations.*;
import java.util.List;
public interface UserMapper {
@Select("select * from user")
public List<User> getAllUser();
//如果是基本类型的参数,前面需要用Param注解,注解里的值就是SQL中引用的变量
@Delete("delete from user where id = #{uid}")
public int deleteUser(@Param("uid") int id);
@Insert("insert into user (id, name, password) values(#{id}, #{username}, #{pwd})")
public int addUser(User user);
@Update("update user set name=#{username}, password=#{pwd} where id=#{id}")
public int updateUser(User user);
}
2、测试(之前已经注册过接口了)
@Test
public void updateUser(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = new User(4, "小天", "10101010");
userMapper.updateUser(user);
sqlSession.close();
}
结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fVAoahqj-1614038856250)(MyBatis2.assets/1613980400352.png)]
当我们写POJO,即实体类的时候,常常会写大量毫无营养的代码,例如get、set、toString等等,而Lombok可以使我们通过注解方式跳过这种步骤。
优点:
缺点:
1、IDEA安装Lombok插件
2、maven导入依赖(或者自己导入jar包)
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.12version>
<scope>providedscope>
dependency>
3、常用注解说明
4、使用示例,修改User类
如果用了@Data注解,就不会包含有参构造方法,而加上有参构造注解,就会覆盖无参注解,所以需要都写上,才能同时有有参和无参构造方法。
数据库中的多对一,我们通常有两种方式:联表查询或者子查询。这里也是两种方式,如果我们仅仅直接查询学生或者老师,那么它们的属性类型是对象的值都会为null,这是由属性名和字段不一致造成的。因此解决方法都需要利用到结果集。
现在创建老师、学生表:
CREATE TABLE `teacher` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO teacher(`id`, `name`) VALUES (1, '秦老师');
CREATE TABLE `student` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
`tid` INT(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fktid` (`tid`),
CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', '小明', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', '小红', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '小张', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '小李', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小王', '1');
新建一个模块,先搭建好基本的测试环境(db.properties、mybatis-config.xml)。
1、编写MyBatis工具类,并导入Lombok,方便后面简化实体类编写
2、新建实体类 Teacher、Student
//多对一:每个学生有一个老师
@Data
public class Student {
private int id;
private String name;
//这里不用tid,这是Java 组合,用Teacher更好将学生和老师绑定
private Teacher teacher;
}
//一对多:一个老师会有多个学生
@Data
public class Teacher {
private int id;
private String name;
private List<Student> students;
}
3、新建接口
package com.zcy.dao;
import com.zcy.pojo.Student;
import java.util.List;
public interface StudentMapper {
//按照查询嵌套处理
public List<Student> getStudent1();
//按照结果嵌套处理
public List<Student> getStudent2();
}
4、新建StudentMapper.xml
5、通过mybatis-config.xml注册mapper
6、测试
查出每个学生以及他们每人对应的老师,这就需要联表查询(查两个表),光靠以之前学的方法是无法完成的。
<mapper namespace="com.zcy.dao.StudentMapper">
<select id="getStudent1" resultMap="StudentTeacher">
select * from student
select>
<resultMap id="StudentTeacher" type="Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<association property="teacher" javaType="Teacher" column="tid" select="getTeacher"/>
resultMap>
<select id="getTeacher" resultType="Teacher">
select * from teacher where id = #{tid}
select>
mapper>
<select id="getStudent2" resultMap="StudentTeacher2">
select s.id sid, s.name sname, t.name tname
from student s, teacher t
where s.tid = t.id
select>
<resultMap id="StudentTeacher2" type="Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<association property="teacher" javaType="Teacher">
<result property="name" column="tname"/>
association>
resultMap>
大部分和多对一的环境一样,实体类、MyBatis工具类等等…
1、接口编写
public interface TeacherMapper {
//基本类型,指定参数。后面在TeacherMapper.xml中也就使用tid为参数
public Teacher getTeacherById1(@Param("tid") int id);
public Teacher getTeacherById2(@Param("tid") int id);
}
2、新建TeacherMapper.xml
3、通过mybatis-config.xml注册mapper
<mapper namespace="com.zcy.dao.TeacherMapper">
<select id="getTeacherById1" resultMap="TeacherStudent1">
select t.id tid, t.name tname, s.id sid, s.name sname
from teacher t, student s
where t.id = s.tid
select>
<resultMap id="TeacherStudent1" type="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<collection property="students" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
collection>
resultMap>
mapper>
<mapper namespace="com.zcy.dao.TeacherMapper">
<select id="getTeacherById2" resultMap="TeacherStudent2">
select * from teacher where id = #{tid}
select>
<resultMap id="TeacherStudent2" type="Teacher">
<collection property="students" javaType="ArrayList" ofType="Student" select="getTeacherById"/>
resultMap>
<select id="getTeacherById" resultType="Student">
select * from student where tid = #{tid}
select>
mapper>