Java(Mybatis02)
参考视频:13. Limit实现分页(狂神)
7. 分页
- 思考:为啥要分页?
- 减少数据的处理量
7.1 使用Limit分页
-- 语法
select * from `user` limit startIndex,pageSize;
select * from `user` limit 2;
-- 相当于
select * from `user` limit 0,2;
select * from `user` limit 0,-1;//原来可以查,但其实是一个bug,目前已被修复。(-1应该“代表”:到最后)
- 使用mybatis实现分页,核心SQL
- 接口
//分页
List<User> getUserByLimit(Map<String,Integer> map);
- UserMapper.xml
<!--分页-->
<select id="getUserByLimit" parameterType="map" resultMap="UserMap">
select *
from mybatis.user
limit #{startIndex},#{pageSize};
</select>
- 测试
//分页
@Test
public void getUserByLimit(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
HashMap<String,Integer> map = new HashMap<>();
map.put("startIndex",0);
map.put("pageSize",4);
List<User> userList = mapper.getUserByLimit(map);
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
7.2 RowBounds分页(不重要)
- 不再使用SQL实现分页
- 接口
//分页2
List<User> getUserByRowBounds();
- UserMapper.xml
<!--分页2-->
<select id="getUserByRowBounds" resultMap="UserMap">
select *
from mybatis.user;
</select>
- 测试
//分页
@Test
public void getUserByLimit(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
HashMap<String,Integer> map = new HashMap<>();
map.put("startIndex",0);
map.put("pageSize",4);
List<User> userList = mapper.getUserByLimit(map);
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
//分页2
public void getUserByRowBounds(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//RowBounds实现
RowBounds rowBounds = new RowBounds(0, 4);
//通过Java代码层面实现分页
List<User> userList = sqlSession.selectList("com.zach.UserMapper.getUserByRowBounds", null, rowBounds);
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
7.3 分页插件
- 了解,知道是什么东西即可。
8. 使用注解开发
8.1 面向接口编程
- 大家之前都学过面向对象编程,也学习过接口。实际上,在真正的开发中,很多时候我们会选择面向接口编程。
- 根本原因:解耦, 可拓展,提高复用,分层开发中,上层不用管具体的实现,大家都遵守共同的标准,使得开发变得容易,规范性更好。
- 在一个面向对象的系统中,系统的各种功能是由许许多多的不同对象协作完成的。在这种情况下,各个对象内部是如何实现自己的,对系统设计人员来讲就不用那么重要了。
- 而各个对象之前的协作关系则成为系统设计的关键。小到不同类之前的通讯,大到各模块之间的交互,在系统设计之初都是要着重要考虑的,这也是系统设计的主要工作内容。面向接口编程就是指按照这种思想来编程。
- 关于接口的理解:
- 接口从更深层次的理解,应是定义(规范,约束)与实现(名实分离的原则)的分离。
- 接口的本身反映了系统设计人员对系统的抽象理解。
- 接口应有两类:
- 第一类是对一个个体的抽象,它对应为一个抽象体(abstract class)。
- 第二类是对一个个体某一方便的抽象,即形成一个抽象面(interface)。
- 一个个体有可能有多个抽象面。抽象体和抽象面是有区别的。
- 三个面向区别:
- 面向对象,我们考虑问题时,以对象为单位,考虑它的属性及方法。
- 面向过程,我们考虑问题时,以一个具体的流程(事务过程)为单位,考虑它的实现。
- 接口设计与非接口设计是针对复用技术而言的,与面向对象(过程)不是一个问题。更多的体现就是对系统整体的架构。
8.2 使用注解开发
- 注解在接口上实现
@Select("select * from user")
List<User> getUsers();
- 需要在核心配置文件中绑定接口!
- mybatis-config.xml
<!--绑定接口-->
<mappers>
<mapper class="com.zach.dao.UserMapper"/>
</mappers>
- 测试
@Test
public void test(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.getUsers();
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
- 本质:反射机制实现
- 底层:动态代理!
8.2.* Mybatis的详细的执行流程!
- 通过源码,分析原理!
- 暂时跳过。。。 16. Mybatis执行流程剖析(狂神)
8.3 CRUD(注解版)
- 我们可以在工具类创建的时候实现自动提交事务!
- MybatisUtils (在最后)
package com.zach.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;
//sqlSessionFactory --> sqlSession
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
//使用Mybatis的第一步:获取sqlSessionFactory对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession(true);//自动提交事务为true
}
}
- 编写接口,增加注解
- UserMapper
package com.zach.dao;
import com.zach.pojo.User;
import org.apache.ibatis.annotations.*;
import java.util.List;
public interface UserMapper {
@Select("select * from user")
List<User> getUsers();
//方法存在多个参数时,所有的参数前面必须加上 @Param("id")注解
@Select("select * from user where id = #{id}")
User getUserById(@Param("id") int id);
@Insert("insert into user(id,name,pwd) values(#{id},#{name},#{password});")
int addUser(User user);
@Update("update user set name=#{name},pwd=#{password} where id=#{id}")
int updateUser(User user);
@Delete("delete from user where id=#{id}")
int deleteUser(@Param("id") int id);
}
- 测试类
- UserDaoTest
package com.zach.dao;
import com.zach.pojo.User;
import com.zach.utils.MybatisUtils;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
import org.junit.Test;
import java.util.HashMap;
import java.util.List;
public class UserDaoTest {
@Test
public void test(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//底层主要应用反射
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//1. @Select("select * from user")
// List<User> userList = mapper.getUsers();
// for (User user : userList) {
// System.out.println(user);
// }
//2. @Select("select * from user where id = #{id}")
// User userById = mapper.getUserById(1);
// System.out.println(userById);
//3. @Insert("insert into user(id,name,pwd) values(#{id},#{name},#{password});")
// mapper.addUser(new User(4, "张天道", "123456"));
//4. @Update("update user set name=#{name},pwd=#{password} where id=#{id}")
// mapper.updateUser(new User(4,"张酬勤","654321"));
//5. @Delete("delete from user where id=#{id}")
mapper.deleteUser(5);
sqlSession.close();
}
}
- 注意: 我们必须要把接口注册绑定到我们的核心配置文件中!
- mybatis-config.xml
<!--绑定接口-->
<mappers>
<mapper class="com.zach.dao.UserMapper"/>
</mappers>
- 关于
@Param()
注解- 基本类型的参数 或者 String类型的参数,需要加。
- 引用类型 不加。
- 如果只有一个基本类型,可不加,但建议加。
- 我们在SQL中引用的就是这里的
@Param()
中设定的属性名!
- Tip:
#{}
和${}
的区别- 都能取值, 但常用
#{}
,因为相对于后者,#{}
能更好的防止SQL注入问题! - …
- 都能取值, 但常用
9. Lombok
9.1 什么是Lombok
- 官网原文:
- Project Lombok is a java library that automatically plugs into your editor and build tools, spicing up your java.
- Never write another getter or equals method again, with one annotation your class has a fully featured builder, Automate your logging variables, and much more.
- 中文翻译:
- Project Lombok 是一个 java 库,可自动插入您的编辑器和构建工具,为您的 java 增添趣味。
- 永远不要再编写另一个 getter 或 equals 方法,使用一个 注解 ,您的类就有一个功能齐全的构建器、自动化您的日志变量等等。
- 关键词:
- java library
- plugs
- build tools
- with one annotation
9.2 使用步骤
- 在IDEA中安装Lombok插件!
- 但IDEA2021.2版本自带(大概2020版本以后都内置了)
- 在项目中导入lombok的jar包。
- 在pom.xml中添加依赖
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
- 各种注解
@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data
@Builder
@SuperBuilder
@Singular
@Delegate
@Value
@Accessors
@Wither
@With
@SneakyThrows
... ...
- 在实体类上加注解即可。
//实体类
@Data//无参构造(可能不是它生成的?),get、set、toString、hashcode、equals
@AllArgsConstructor//有参构造
@NoArgsConstructor//无参构造
@EqualsAndHashCode
@ToString
@Getter
//...
public class User {
private int id;
private String name;
private String password;
}
- 评价:除非必须,否则不用。
10. 多对一处理
10.1 分析
多对一:
- 多个学生,对应一个老师。
- 对于学生而言, 关联: 多个学生 关联 一个老师【多对一】
- 对于老师而言, 集合: 一个老师 拥有 多个学生【一对多】
- SQL
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');
10.2 测试环境搭建
- 导入lombok(依赖)
- 新建实体类 Teacher,Student(用lombok方式)
- 建立Mapper接口
package com.zach.dao;
import com.zach.pojo.Teacher;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
public interface TeacherMapper {
@Select("select * from teacher where id = #{tid}")
Teacher getTeacher(@Param("tid") int id);
}
- 建立Mapper.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zach.dao.TeacherMapper">
</mapper>
- 在核心配置文件中绑定注册我们的Mapper接口或者文件!【方式随意】
- 主要是最后的
mappers
标签
<?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核心配置文件-->
<configuration>
<!--引入外部配置文件-->
<properties resource="db.properties"/>
<!--日志-->
<settings>
<!--标准的日志工厂实现-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!--可以给实体类起别名-->
<typeAliases>
<package name="com.zach.pojo"/>
</typeAliases>
<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 class="com.zach.dao.TeacherMapper"/>
<mapper class="com.zach.dao.StudentMapper"/>
</mappers>
</configuration>
- 测试查询是否能够成功!
package com.zach.dao;
import com.zach.pojo.Teacher;
import com.zach.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
public class MyTest {
public static void main(String[] args) {
SqlSession sqlSession = MybatisUtils.getSqlSession();
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
Teacher teacher = mapper.getTeacher(1);
System.out.println(teacher);
sqlSession.close();
}
}
10.3 按照查询嵌套处理
- StudentMapper.xml
<!--按照查询嵌套处理(类似子查询)
思路:
1. 查询所有的学生信息
2. 根据查询出来的学生的tid,寻找对应的老师!
-->
<!--select-->
<select id="getStudent" resultMap="StudentTeacher">
select * from student;
</select>
<resultMap id="StudentTeacher" type="Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<!--复杂的属性,我们需要单独处理 对象:association 集合:collection-->
<association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="Teacher">
select * from teacher where id = #{id};
</select>
- testStudent
@Test
public void testStudent(){//查出来teacher=Teacher(id=1, name=秦老师))
SqlSession sqlSession = MybatisUtils.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> studentList = mapper.getStudent();
for (Student student : studentList) {
System.out.println(student);
}
sqlSession.close();
}
10.4 按照结果嵌套处理
- StudentMapper.xml
<!--按照结果嵌套处理(类似连表查询)-->
<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="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="Teacher">
<result property="name" column="tname"/>
</association>
</resultMap>
- testStudent2
@Test
public void testStudent2(){//查出来teacher=Teacher(id=0, name=秦老师))
SqlSession sqlSession = MybatisUtils.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> studentList = mapper.getStudent2();
for (Student student : studentList) {
System.out.println(student);
}
sqlSession.close();
}
- 回顾Mysql多对一查询方式:
- 子查询
- 连表查询
11. 一对多处理
- 比如:一个老师拥有多个学生!
- 对于老师而言,就是一对多的关系!
11.1 环境搭建
-
和前面的一样。
-
改变:
- 实体类:
@Data
public class Student {
private int id;
private String name;
private int tid;
}
@Data
public class Teacher {
private int id;
private String name;
//老师拥有多个学生
private List<Student> students;
}
11.2 按照结果嵌套处理
- TeacherMapper.xml
<!--按照结果嵌套查询-->
<!--select-->
<select id="getTeacher" resultMap="TeacherStudent">
select s.id sid, s.name sname, t.name tname, t.id tid
from student s, teacher t
where s.tid = t.id and t.id = #{tid}
</select>
<resultMap id="TeacherStudent" type="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<!--复杂的属性,我们需要单独处理 对象:association 集合:collection
javaType="" 制定属性的类型!
集合中的泛型信息,我们使用ofType获取
-->
<collection property="students" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
- test
@Test
public void test(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
Teacher teacher = mapper.getTeacher(1);
System.out.println(teacher);
//Teacher(id=1, name=秦老师,
// students=
// [Student(id=1, name=小明, tid=1),
// Student(id=2, name=小红, tid=1),
// Student(id=3, name=小张, tid=1),
// Student(id=4, name=小李, tid=1),
// Student(id=5, name=小王, tid=1)]
// )
sqlSession.close();
}
11.3 按照查询嵌套处理
- TeacherMapper.xml
<select id="getTeacher2" resultMap="TeacherStudent2">
select *
from teacher
where id = #{tid};
</select>
<resultMap id="TeacherStudent2" type="Teacher">
<!--相同的可以不写-->
<!--但是去掉id,id将=0-->
<result property="id" column="id"/>
<!--但是去掉name,name不会=null-->
<!-- <result property="name" column="name"/>-->
<!--javaType不写结果一样-->
<collection property="students" javaType="ArrayList" column="id" ofType="Student" select="getStudentByTeacherId"/>
</resultMap>
<select id="getStudentByTeacherId" resultType="Student">
select *
from student
where tid = #{随便写什么都可以,id或者tid,甚至这句话本身};
</select>
- test
@Test
public void test2(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
Teacher teacher2 = mapper.getTeacher2(1);
System.out.println(teacher2);
//Teacher(id=1, name=秦老师, students=
// [Student(id=1, name=小明, tid=1),
// Student(id=2, name=小红, tid=1),
// Student(id=3, name=小张, tid=1),
// Student(id=4, name=小李, tid=1),
// Student(id=5, name=小王, tid=1)]
// )
sqlSession.close();
}
11.4 小结
- 关联 - association 【多对一】
- 集合 - collection 【一对多】
- javaType & ofType
- javaType :用来指定实体类中属性的类型
- ofType :用来指定映射到List或者集合中pojo类型,即泛型中的约束类型。
- 注意点:
- 保证sql的可读性,尽量保证通俗易懂
- 注意一对多和多对一中,属性和字段的问题
- 如果问题不好排查错误,可以使用日志,建议使用Log4j
- 面试高频:
- mysql引擎
- innoDB底层原理
- 索引
- 索引优化!