MyBatis入门学习(五)
使用注解开发
1、面向接口编程
很多时候,我们会选择面向接口编程
- 根本原因:解耦,可拓展,提高复用,分层开发中,上层不用管具体的实现,大家都遵守共同的标准,使得开发变得容易,规范性更好
- 在一个面向对象的系统中,系统的各种功能是由许许多多的不同对象协作完成的,在这种情况下,各个对象内部是如何实现自己的,对系统设计人员来讲就不那么重要了;
- 而各个对象之间的协作关系则成为系统设计的关键,小到不同类之间的通信,大到各模块之间的交互,在系统设计之初都是要最重考虑的,这个也是系统设计的主要工作内容。面向接口编程就是指按照这种思想来编程。
关于接口的理解
-
接口从更深层次的理解,应该是定义(规范、约束)与实现的分离。
-
接口的本身反映了系统设计人员对系统的抽象理解。
-
接口有两类:
- 第一类是对一个个体的抽象,它可对应为一个抽象体(abstract class);
- 第二类是对一个个体某一方面的抽象,即形成一个抽象面(interface);
-
一个个体有可能有多个抽象面,抽象体与抽象面是有区别的。
三个面向区别
- 面向对象是指,我们考虑问题是,一对象为单位,考虑它的属性及方法;
- 面向过程是指,我们考虑问题时,一一个具体的流程(事务过程)为单位,考虑它的实现;
- 接口设计与非接口设计是针对复用技术而言,与面向对象(过程)不是一个问题,更对的体现就是对系统整体的架构;
2、使用注解开发
1、注解在接口上实现
@Select("select * from user")
List<User> getUserList();
2、需要在核心配置文件中绑定接口
<!--绑定接口-->
<mappers>
<mapper class="com.star.mapper.UserMapper"/>
</mappers>
3、测试
@Test
public void getUserList(){
SqlSession session = MybatisUtils.getSession();
UserMapper mapper = session.getMapper(UserMapper.class);
List<User> userList = mapper.getUserList();
for (User user : userList) {
System.out.println(user);
}
}
测试结果:
本质:反射机制实现
底层:动态代理
3、CRUD
我们可以在工具类创建的时候实现自动提交事务
public static SqlSession getSession(){
return getSession(false);
}
public static SqlSession getSession(boolean flag){
return sqlSessionFactory.openSession(flag);
}
编写接口,增加注解
package com.star.mapper;
import com.star.pojo.User;
import org.apache.ibatis.annotations.*;
import java.util.List;
public interface UserMapper {
@Select("select * from user")
List<User> getUserList();
@Select("select * from user where id = #{id}")
User selectById(@Param("id") int id);
@Select("select * from user where name=#{username} and pwd=#{pwd}")
User selectByUsernamePwd(@Param("username") String username, @Param("pwd") String pwd);
@Insert("insert into user(id,`name`,pwd) value (#{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 deleteUserById(@Param("id") int id);
}
测试类还和之前一样!
注意:我们必须要将接口注册绑定到我们的核心配置文件中!
关于@Param() 注解
- 基本类型的参数或者String类型,需要加上
- 引用类型不需要加
- 如果只有一个基本类型的话,可以忽略,但是建议大家都加上!
- 我们在SQL中引用的就是我们这里的 @Param() 中设定的属性名!
多对一处理
多对一:多个学生对应一个老师!
对于学生这边而言:多个学生关联一个老师【多对一】
首先创建一个数据库
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');
测试环境搭建
1、导入所需的依赖
2、新建实体类Teacher、Student
package com.star.pojo;
import lombok.Data;
@Data
public class Teacher {
private int id;
private String name;
}
package com.star.pojo;
import lombok.Data;
@Data
public class Student {
private int id;
private String name;
//学生关联老师
private Teacher teacher;
}
3、建立Mapper接口
package com.star.mapper;
import com.star.pojo.Student;
import java.util.List;
public interface StudentMapper {
//获取所有的学生及学生对应的老师的信息
List<Student> getStudents();
}
4、建立Mapper.xml
有两种方式
方式一:按照结果嵌套处理
<!--
获取所有的学生及学生对应老师的信息
1、获取所有的学生信息
2、获取所有的学生的tid,然后再去老师表中查询这个tid对应的老师
-->
<resultMap id="StudentMap" type="Student">
<id property="id" column="sid"/>
<result property="name" column="sname"/>
<!--这里存在一个问题,tid是一个字段,而teacher是一个对象-->
<!--使用关联标签 association javaType:对象的类型-->
<association property="teacher" javaType="Teacher">
<id property="id" column="tid"/>
<result property="name" column="tname"/>
</association>
</resultMap>
<!--
这个其实对应MySql中的联表查询;
查询的sql结果,可能来自多个对象,将多个对象关联;
需要考虑查询出来的字段到底是对象的哪个属性!
-->
<select id="getStudents" resultMap="StudentMap">
select s.id sid,s.name sname,t.name tname,t.id tid
from student s,teacher t
where s.tid = t.id;
</select>
方式二:按照查询嵌套处理
<select id="getStudents" resultMap="StudentTeacher">
select * from student
</select>
<!--连接子查询-->
<resultMap id="StudentTeacher" type="Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
</resultMap>
<!--自定义的子查询-->
<select id="getTeacher" resultType="Teacher">
select * from teacher where id = #{id}
</select>
5、在核心配置文件中绑定注册我们的Mapper接口或者文件!
<mappers>
<package name="com.star.mapper"/>
</mappers>
6、测试
package com.star.mapper;
import com.star.pojo.Student;
import com.star.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class StudentMapperTest {
@Test
public void getStudentsTest() {
SqlSession session = MybatisUtils.getSession();
StudentMapper mapper = session.getMapper(StudentMapper.class);
List<Student> students = mapper.getStudents();
for (Student student : students) {
System.out.println(student);
}
}
}
测试结果:
一对多处理
一对多:一个老师对应多个学生(集合)
对于老师而言,一个老师有很多学生【一对多】
1、实体类
package com.star.pojo;
import lombok.Data;
import java.util.List;
@Data
public class Teacher {
private int id;
private String name;
//老师对应的学生房子一个集合里
private List<Student> students;
}
package com.star.pojo;
import lombok.Data;
@Data
public class Student {
private int id;
private String name;
private int tid;
}
2、编写对应Mapper接口
package com.star.mapper;
import com.star.pojo.Teacher;
public interface TeacherMapper {
//通过老师的id查询该老师对应的所有学生的信息
public Teacher getTeacher(int id);
}
3、编写Mapeer.xml文件
有两种方式
方式一:按照结果嵌套处理
<resultMap id="TeacherMap" type="Teacher">
<id property="id" column="tid"/>
<result property="name" column="tname"/>
<!--
这里的字段students是一个集合(包含的关系) 使用collection标签
ofType:集合中的元素对应的Java类型
-->
<collection property="students" ofType="Student">
<id property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="stid"/>
</collection>
</resultMap>
<select id="getTeacher" resultMap="TeacherMap">
select t.id tid,t.name tname,s.id sid,s.name sname,s.tid stid
from student s,teacher t
where s.tid=t.id and tid=#{id};
</select>
方式二:按照查询嵌套处理
<select id="getTeacher" resultMap="TeacherMap">
select * from teacher where id = #{tid}
</select>
<!--连接子查询-->
<resultMap id="TeacherMap" type="Teacher">
<collection property="students" javaType="ArrayList" ofType="Student" select="getStudentByTeacherId" column="id"/>
</resultMap>
<!--自定义的一个子查询-->
<select id="getStudentByTeacherId" resultType="Student">
select * from student where tid = #{tid}
</select>
4、核心配置文件绑定Mapper.xml
<mappers>
<package name="com.star.mapper"/>
</mappers>
5、测试
package com.star.mapper;
import com.star.pojo.Teacher;
import com.star.utils.MybatisUtils;
import org.junit.Test;
public class TeacherMapperTest {
@Test
public void getTeacherTest(){
TeacherMapper mapper = MybatisUtils.getSession().getMapper(TeacherMapper.class);
Teacher teacher = mapper.getTeacher(1);
System.out.println(teacher);
}
}
测试结果:
结论:
- 关联 association【多对一】
- 集合 collection【一对多】
- javaType & ofType
- javaType 用来指定实体类中属性的类型
- ofType 用来指定映射到List或者集合中的pojo类型,泛型中的约束类型
注意:
- 保证SQL的可读性
- 注意一对多和多对一中,属性名和字段的问题
- 建议使用日志,LOG4J