开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第7天,点击查看活动详情
使用注解开发
1.面向接口编程
真正的开发中,很多时候我们会选择面向接口编程
根本原因:解耦,可拓展,提高利用,分层开发中,上层不用管具体的实现,大家都遵守共同的标准,使得开发变得容易,规范性更好
关于接口的理解
-
接口从更深层次的理解,就是定义(规范,约束)与实现(名实分离的原则)的分离。
-
接口的本身反映了系统设计人员对系统的抽象理解。
-
接口就有两类:
- 第一类是对一个个体的抽象,它可对应为一个抽象体(abstract class)
- 第二类是对一个个体某一方面的抽象,即形成一个抽象面(interface)
-
一个体有可能 有多个抽象面。抽象体与抽象面是有区别的
2.使用注解开发
新建项目mybatis-05
复制如下包:
mybatis-config.xml中删除mapper,setting改成标准的日志工厂实现
-
注解在接口上实现
@Select("select * from user") List<User> getUsers(); -
需要在核心配置文件中绑定接口
<mappers> <mapper class="com.isabella.dao.UserMapper"></mapper> </mappers> -
测试
@Test public void test(){ SqlSession sqlsession = MybatisUtils.getSqlsession(); //底层主要应用反射 UserMapper mapper = sqlsession.getMapper(UserMapper.class); List<User> users = mapper.getUsers(); for (User user : users) { System.out.println(user); } sqlsession.close(); }
本质:反射机制实现
底层:动态代理
Mybatis执行流程剖析
注解增删改查
我们可以在工具类创建的时候实现自动提交事务
MybatisUtils.java(修改):
return sqlSessionFactory.openSession(true);
编写接口,增加注解
UserMapper.java:
package com.isabella.dao;
import com.isabella.pojo.User;
import org.apache.ibatis.annotations.*;
import java.util.List;
public interface UserMapper {
@Select("select * from user")
List<User> getUsers();
@Select("select * from user where id = #{id}")
User getUserById(@Param("id")int id);
@Insert("insert into user (id,name,pwd) values (#{id},#{name},#{pwd})")
int addUser(User user);
@Update("update user set name=#{name},pwd=#{pwd} where id=#{id}")
int updateUser(User user);
@Delete("delete from user where id=#{id}")
int deleteUser(@Param("id") int id);
}
测试类注意:我们必须要将接口注册绑定到我们的核心配置文件中
UserMapperTest.java:
//查询所有用户
List<User> users = mapper.getUsers();
for (User user : users) {
System.out.println(user);
}
//根据id查询用户
User user = mapper.getUserById(1);
System.out.println(user);
//添加用户
mapper.addUser(new User(7,"Hello","12345"));
//修改用户
mapper.updateUser(new User(7,"World","12333"));
//删除用户
mapper.deleteUser(7);
关于@Param()注解
- 基本类型的参数或者String类型,需要加上
- 引用类型不需要加
- 如果 只有一个基本类型的话,可以忽略,但是建议加上
- 我们在SQL中引用的就是我们这里的@Param()中设定的属性名
#{} 与 ${} 的区别
#{}可以防止注入
复杂查询环境搭建
多对一:
- 多个学生,对应一个老师
- 对于学生而言,多个学生关联一个老师【多对一】
- 对于老师而言,集合,一个老师,有很多学生【一对多】
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);
测试环境搭建
-
新建实体类Teacher,Student
Teacher.java:
package com.isabella.pojo; public class Teacher { private int id; private String name; public Teacher() { } public Teacher(int id, String name) { this.id = id; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Teacher{" + "id=" + id + ", name='" + name + ''' + '}'; } } Student.java:
package com.isabella.pojo; public class Student { private int id; private String name; //学生需要关联一个老师 private Teacher teacher; public Student() { } public Student(int id, String name, Teacher teacher) { this.id = id; this.name = name; this.teacher = teacher; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Teacher getTeacher() { return teacher; } public void setTeacher(Teacher teacher) { this.teacher = teacher; } @Override public String toString() { return "Student{" + "id=" + id + ", name='" + name + ''' + ", teacher=" + teacher + '}'; } } -
建立Mapper接口
TeacherMapper.java:
package com.isabella.dao; import com.isabella.pojo.Teacher; public interface TeacherMapper { Teacher getTeacher(int id); } StudentMapper.java:
package com.isabella.dao; public interface StudentMapper { } -
建立 Mapper.xml文件
TeacherMapper.xml:
```
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.isabella.dao.TeacherMapper">
<select id="getTeacher" parameterType="int" resultType="com.isabella.pojo.Teacher">
select * from mybatis.teacher where id = #{id};
</select>
</mapper>
```
StudentMapper.xml:
```
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.isabella.dao.StudentMapper">
</mapper>
```
0. 在核心配置文件中绑定注册我们的Mapper接口或文件【方式很多,随心选】
```
<mappers>
<mapper resource="com/isabella/dao/TeacherMapper.xml"/>
</mappers>
```
0. 测试查询是否成功
TeacherMapperTest.java:
```
package com.isabella.dao;
import com.isabella.pojo.Teacher;
import com.isabella.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
public class TeacherMapperTest {
@Test
public void test(){
SqlSession sqlsession = MybatisUtils.getSqlsession();
TeacherMapper mapper = sqlsession.getMapper(TeacherMapper.class);
Teacher teacher = mapper.getTeacher(1);
System.out.println(teacher);
sqlsession.close();
}
}
```
# 多对一的处理
SQL中联表查询
select s.id,s.name , t.name from student s, teacher t where s.tid=t.id;
按照查询嵌套处理
StudentMapper.xml:
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.isabella.dao.StudentMapper">
<!--
思路:
1.查询所有的学生信息
2.根据查询出来的学生的tid,寻找对应的老师
-->
<select id="getStudent" resultMap="StudentTeacher">
select * from mybatis.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="getTeacherById"/>
</resultMap>
<select id="getTeacherById" resultType="Teacher">
select * from mybatis.teacher where id = #{tid}
</select>
</mapper>
测试类:
@Test
public void testStudent(){
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();
}
按照结果嵌套处理
StudentMapper.java:
List<Student> getStudent2();
StudentMapper.xml
<!--按照结果嵌套处理-->
<select id="getStudent2" resultMap="StudentTeacher2">
select s.id sid,s.name sname,t.name tname
from mybatis.student s , mybatis.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>
测试类:
@Test
public void testStudent(){
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();
}
一对多的处理
比如:一个老师拥有多个学生
对于老师而言,就是一对多的关系
环境搭建
Student.java:
package com.isabella.pojo;
public class Student {
private int id;
private String name;
//学生需要关联一个老师
private int tid;
public Student() {
}
public Student(int id, String name, int tid) {
this.id = id;
this.name = name;
this.tid = tid;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getTid() {
return tid;
}
public void setTid(int tid) {
this.tid = tid;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + ''' +
", tid=" + tid +
'}';
}
}
Teacher.java:
package com.isabella.pojo;
import java.util.List;
public class Teacher {
private int id;
private String name;
//一个老师拥有多个学生
private List<Student> students;
public Teacher() {
}
public Teacher(int id, String name, List<Student> students) {
this.id = id;
this.name = name;
this.students = students;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Student> getStudents() {
return students;
}
public void setStudents(List<Student> students) {
this.students = students;
}
@Override
public String toString() {
return "Teacher{" +
"id=" + id +
", name='" + name + ''' +
", students=" + students +
'}';
}
}
按照结果嵌套处理
TeacherMapper.java:
//获取指定老师下的所有学生及老师的信息
Teacher getTeacher(int tid);
TeacherMapper.xml:
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.isabella.dao.TeacherMapper">
<!--按结果嵌套查询-->
<select id="getTeacher" resultMap="TeacherStudent">
select s.id sid,s.name sname,t.name tname, t.id tid
from mybatis.student s,mybatis.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"/>
<!--
javaType=""指定属性的类型
集合中的泛型信息,我们使用ofType获取
-->
<collection property="students" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
</mapper>
-
测试类
MyTest.java:
@Test public void testTeacher(){ SqlSession sqlsession = MybatisUtils.getSqlsession(); TeacherMapper mapper = sqlsession.getMapper(TeacherMapper.class); Teacher teacher = mapper.getTeacher(1); System.out.println(teacher); sqlsession.close(); }
按照查询嵌套处理
TeacherMapper.java:
Teacher getTeacher2(int tid);
TeacherMapper.xml:
<select id="getTeacher2" resultMap="TeacherStudent2">
select * from mybatis.teacher where id = #{tid}
</select>
<resultMap id="TeacherStudent2" type="Teacher">
<result property="id" column="id"/>
<result property="name" column="name"/>
<collection property="students" column="id" javaType="ArrayList" ofType="Student" select="getStudentByTid"/>
</resultMap>
<select id="getStudentByTid" resultType="Student">
select * from mybatis.student where tid = #{id}
</select>
MyTest.java:
@Test
public void testTeacher(){
SqlSession sqlsession = MybatisUtils.getSqlsession();
TeacherMapper mapper = sqlsession.getMapper(TeacherMapper.class);
Teacher teacher = mapper.getTeacher2(1);
System.out.println(teacher);
sqlsession.close();
}
小结
-
关联 - association 【多对一】
-
集合 - collection 【一对多】
-
javaType & ofType
- javaType用来指定实体类中属性的类型
- ofType用来指定映射到List或集合中的pojo类型,泛型中的约束类型
注意点:
- 保证SQL的可读性,尽量保证通俗易懂
- 注意一对多和多对一中,属性名和字段的问题
- 如果问题不好排查错误,可以使用日志,建议使用Log4j
尽量避免慢SQL
面试高频
- Mysql引擎
- InnoDB底层原理
- 索引
- 索引优化