Mybatis注解开发指北
Mybatis注解开发指北
目录
文章目录
- Mybatis注解开发指北
- @[toc]
- 0. Mybatis注解开发步骤
- 1. 导入相关配置文件
- 2. 配置数据库连接
- 3. 创建数据库对应的实体类(entity)
- 4. 创建实体类对应的Dao/Mapper实现增删改查
- 4.1 Select查询
- 4.1.1 立即加载EAGER和延迟加载LAZY
- 4.2 Insert插入
- 4.3Update更新
- 4.4Delete删除
- 5 创建相应的测试类
- 5.1 使用junit创建测试类
0. Mybatis注解开发步骤
- 导入Mybatis、Mysql及相关辅助包
- 配置数据库连接
- 创建数据库对应的实体类(entity)
- 创建实体类对应的Dao/Mapper实现增删改查
- 创建相应的测试类
1. 导入相关配置文件
- 用maven创建工程,在
pom.xml中的dependencies
中导入如下代码:
<dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.3</version>
</dependency>
- 同时可以导入mysql、log4j和junit用来测试和输出文档测试
<dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.12</version>
</dependency>
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.19</version>
</dependency>
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope>
</dependency>
- 在resources下新建
log4j.properties
文件将以下内容拷贝进去,用于输出日志等相关配置。
# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE debug info warn error fatal
log4j.rootCategory=debug, CONSOLE, LOGFILE# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=/axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
2. 配置数据库连接
配置数据库连接是为了连接数据库以便进行CRUD操作
配置数据库连接,在resources文件夹中新建
SqlMapConfig.xml
储存数据库相关配置,配置如下
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--mybatis主配置文件-->
<configuration>
<!-- 配置类型别名--><typeAliases><package name="com.database.mybatis.entity"/></typeAliases><!-- 配置环境--><environments default="mysql"><environment id="mysql">
<!-- 事务类型--><transactionManager type="JDBC"></transactionManager>
<!-- 配置数据源--><dataSource type="POOLED">
<!-- 配置连接数据库的基本信息--><!--Mysql 6.0之前driver 驱动写com.mysql.jdbc.Driver--><property name="driver" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/test"/><property name="username" value="root"/><property name="password" value="qwer123"/></dataSource></environment></environments><!-- 指定dao接口所在位置--><mappers><package name="com.database.mybatis.dao"></package></mappers>
</configuration>
类型别名的作用:
- 类型别名的作用是为Java类型折翼短的名字,至于xml配置有关,可以减少类完全限定名的冗余。单个配置的时候可以是:
<typeAliases><typeAlias alias="Student" type="com.database.mybatis.entity.Student"/> </typeAliases>
- 也可以进行批量配置,在如下方法中配置别名,Mybatis可以在entity下搜索需要的Java Bean的瘦子米小写的非限定类名作为他的别名,比如
com.database.mybatis.entity.Student
的别名是student
。
<typeAliases><package name="com.database.mybatis.entity"/> </typeAliases>
3. 创建数据库对应的实体类(entity)
创建实体类的作用是为了将存放数据库中返回的数据,以便于进行相应的操作。
创建实体类之前应先建立数据库相应的表,提供测试的数据库表有3个:Teacher、Class、Student。三个表是多对多的关系,EER图如下:
- sql语句如下:
CREATE DATABASE test;use test;CREATE TABLE student(id INT PRIMARY KEY,teacher_id INT,class_id INT,student_nub BIGINT NOT NULL,student_name VARCHAR(20) NOT NULL,student_sex VARCHAR(20) DEFAULT '男',student_phone VARCHAR(20)
);SELECT * FROM student;INSERT INTO student VALUES(1,1,1,1800300101,'一班一号','男',NULL);CREATE TABLE class(id INT PRIMARY KEY,teacher_id INT,student_id INT,class_nub BIGINT NOT NULL,class_name VARCHAR(20) NOT NULL,class_maxperson INT NOT NULL,class_haveperson INT NOT NULL,class_place INT NOT NULL
);INSERT INTO class VALUES(1,1,1,300101,'三院一年级一号课',80,0,17101);SELECT * FROM class;CREATE TABLE teacher(id INT PRIMARY KEY,student_id INT,class_id INT,teacher_nub BIGINT NOT NULL,teacher_name VARCHAR(20) NOT NULL,teacher_sex VARCHAR(20) DEFAULT '男',teacher_phone VARCHAR(20)
);INSERT INTO teacher VALUES(1,1,1,003001,'三院一号教师','男','13113311331');SELECT * FROM teacher;alter table student add foreign key(class_id) references class(id);
alter table student add foreign key(teacher_id) references teacher(id);
alter table teacher add foreign key(class_id) references class(id);
alter table teacher add foreign key(student_id) references student(id);
alter table class add foreign key(teacher_id) references teacher(id);
alter table class add foreign key(student_id) references student(id);
创建实体类一般放入entiy包下,目录结构如下:
实体类创建时尽量遵循阿里巴巴java开发手册命名规则,养成良好习惯。数据库中表的字段类型需要与Java类型相对应,Java变量名以表字段名全称命名,例如表字段为student_id,则Java变量名应为StudentId。
sql变量类型与Java变量对照表如下:
Java类型 | SQL类型 |
---|---|
boolean | BIT |
byte | TINYINT |
short | SMALLINT |
int | INTEGER |
long | BIGINT |
String | CHAR,VARCHAR,LONGVARCHAR |
java.sql.Date | DATE |
java.sql.Time | TIME |
java.sql.Timestamp | TIMESTAMP |
- Class实体类如下:
public class Class implements Serializable {private Integer id;private Integer teacherId;private Integer studentId;private BigInteger classNub;private String className;private Integer classMaxPerson;private Integer classHavePerson;private Integer classPlace;
}
- 然后创建实体类对应的getter、setter和toString。完整的Class实体类如下:
package com.database.mybatis.entity;import java.io.Serializable;
import java.math.BigInteger;
import java.util.List;/*** @author linxi* @function* @project database* @package com.database.mybatis.model* @date 2020/5/8-1:37 下午*/
public class Class implements Serializable {private Integer id;private Integer teacherId;private Integer studentId;private BigInteger classNub;private String className;private Integer classMaxPerson;private Integer classHavePerson;private Integer classPlace;@Overridepublic String toString() {return "Class{" +"id=" + id +", teacher_id=" + teacherId +", student_id=" + studentId +", class_nub=" + classNub +", class_name='" + className + '\'' +", class_maxperson=" + classMaxPerson +", class_haveperson=" + classHavePerson +", class_place=" + classPlace +'}';}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public Integer getTeacherId() {return teacherId;}public void setTeacherId(Integer teacherId) {this.teacherId = teacherId;}public Integer getStudentId() {return studentId;}public void setStudentId(Integer studentId) {this.studentId = studentId;}public BigInteger getClassNub() {return classNub;}public void setClassNub(BigInteger classNub) {this.classNub = classNub;}public String getClassName() {return className;}public void setClassName(String className) {this.className = className;}public Integer getClassMaxPerson() {return classMaxPerson;}public void setClassMaxPerson(Integer classMaxPerson) {this.classMaxPerson = classMaxPerson;}public Integer getClassHavePerson() {return classHavePerson;}public void setClassHavePerson(Integer classHavePerson) {this.classHavePerson = classHavePerson;}public Integer getClassPlace() {return classPlace;}public void setClassPlace(Integer classPlace) {this.classPlace = classPlace;}
}
4. 创建实体类对应的Dao/Mapper实现增删改查
- Dao和Mapper在注解开发中已经没有明显区别,所以不作区分。在Mybatis注解开发中,只要定义好对应的接口并加上合适的注解即可直接使用,不需要再编写Dao的具体实现类。
- 因为我们实体类中的变量名与数据库表中的字段名不一致,所以我们需要任意一个用@Results注解使变量名与字段名进行统一,在再其他借口上使用@Resultmap()调用统一关系,代码如下。
/*** results的ID用于定义此对应的名称,在其他接口中直接使用@Resultmap("ID")来使用此对应关系,无需重写。* 表中主键需要在@Result()中的id属性设为true(默认为false)* @resylt() 的column属性为表中字段名,property为实体类变量名*/
@Results(id = "classDao", value = {@Result(id = true,column = "id",property = "id"),@Result(column = "teacher_id",property = "teacherId"),@Result(column = "student_id",property = "studentId"),@Result(column = "class_nub",property = "classNub"),@Result(column = "class_name",property = "className"),@Result(column = "class_maxperson",property = "classMaxPerson"),@Result(column = "class_haveperson",property = "classHavePerson"),@Result(column = "class_place",property = "classPlace")
})
4.1 Select查询
接口例子:
- 查询Class所有内容,返回值为Class类型的List
/*** results的ID用于定义此对应的名称,在其他接口中直接使用@Resultmap("ID")来使用此对应关系,无需重写。* 表中主键需要在@Result()中的id属性设为true(默认为false)* @resylt() 的column属性为表中字段名,property为实体类变量名*/@Results(id = "classDao", value = {@Result(id = true,column = "id",property = "id"),@Result(column = "teacher_id",property = "teacherId"),@Result(column = "student_id",property = "studentId"),@Result(column = "class_nub",property = "classNub"),@Result(column = "class_name",property = "className"),@Result(column = "class_maxperson",property = "classMaxPerson"),@Result(column = "class_haveperson",property = "classHavePerson"),@Result(column = "class_place",property = "classPlace")}) @Select("select * from class") List<Class> findAllClass();
- 通过id查询
@ResultMap("classDao") @Select("select * from class where id=#{id}") List<Class> findClassById(Integer classId);
模糊查询
- 方式一:
@Select("select * from class where class_name like '%${value}%'")
这种方式直接传送参数进来就可,不需要加
%
号。例如传送张三作为value即相当于:select * from class where class_name like %张三%。\例子:
@ResultMap("classDao") @Select("select * from class where class_name like '%${value}%'") List<Class> findClassByClassName(String className);
- 方式二:
@Select("select * from class where class_name like #{username}")
这种方式传送参数时需要带
%
,例如传送%张三%
作为value即相当于:select * from class where class_name like %张三%。例子:
@ResultMap("classDao")@Select("select * from class where class_name like #{username}")List<Class> findClassByClassName(String className);
多表查询:多表对应关系有两种:一对一和一对多。
一对一:假设有表A,B;A表中有字段id和b_id,b_id对应B表的id(id为唯一值),所以A表的每一列都有唯一一个B与其对应,则此关系为一对一。一对一关系需要用@one注解映射。
- 假设查询某节课及其对应的老师,因为每个课程只有一个老师,所以关系为一对一。
- 首先需要在Class实体类中建立Teacher类型变量用于存储老师信息,并建立相应的gettter和setter。
private Teacher teacher;public Teacher getTeacher() {return teacher; }public void setTeacher(Teacher teacher) {this.teacher = teacher; }
- 第二步,需要在TeacherDao中建立通过classID查询teacher的接口。
@Select("select * from teacher where class_id=#{class_id}") Teacher findTeacherByClassId(Integer classId);
- 第三步,在ClassDao中建立通过classId查询课程及其对应老师的接口。实质上是查询class但是class实体类中的Teacher中要包含课程对应的老师。多表查询的@one注解是属于@result的参数。
@Results(value = {@Result(id = true, column = "id", property = "id"),@Result(column = "teacher_id", property = "teacherId"),@Result(column = "student_id", property = "studentId"),@Result(column = "class_nub", property = "classNub"),@Result(column = "class_name", property = "className"),@Result(column = "class_maxperson", property = "classMaxPerson"),@Result(column = "class_haveperson", property = "classHavePerson"),@Result(column = "class_place", property = "classPlace"),@Result(property = "teacher", column = "teacherId",one = @One(select ="com.database.mybatis.dao.TeacherDao.findTeacherByClassId",fetchType = FetchType.EAGER)) }) @Select("select * from class where id = #{id}") Class findClassAndTeacherByClassId(Integer classId);
一对多:假设有表A,B;A表中有字段id和b_room,b_room对应B表的room(room不唯一),所以A表的每一列都有多个B与其对应,则此关系为一对多。一对多关系需要用@many注解映射
- 假设查询上某节课的所有学生,因为一个课程有多名学生,所以关系为一对多。
- 首先需要在Class实体类中建立List类型变量用于存储老师信息,并建立相应的gettter和setter。
private List<Student> students;public List<Student> getStudents() {return students; }public void setStudents(List<Student> students) {this.students = students; }
- 第二步,需要在StudentDao中建立通过classID查询student的接口。
@Select("select * from student where class_id=#{class_id}") List<Student> findStudentByClassId(Integer classId);
- 第三步,在ClassDao中建立通过classId查询课程及其对应学生的接口。实质上是查询class但是class实体类中List中要包含课程对应的学生。多表查询的@many注解是属于@result的参数。
@Select("select * from class where id=#{id}") @Results(value = {@Result(id = true,column = "id",property = "id"),@Result(column = "teacher_id",property = "teacherId"),@Result(column = "student_id",property = "studentId"),@Result(column = "class_nub",property = "classNub"),@Result(column = "class_name",property = "className"),@Result(column = "class_maxperson",property = "classMaxPerson"),@Result(column = "class_haveperson",property = "classHavePerson"),@Result(column = "class_place",property = "classPlace"),@Result(property = "students", column = "id",many = @Many(select ="com.database.mybatis.dao.StudentDao.findStudentByClassId",fetchType = FetchType.LAZY)) }) List<Class> findClassAndStudentsByClassId(Integer classId);
4.1.1 立即加载EAGER和延迟加载LAZY
- 延迟加载和立即加载的区别:
- 顾名思义,立即加载就是在sql语句执行的时候直接从数据库取出数据,而延迟加载就是虽然sql语句执行,但是只有在用到相应的数据的时候才从数据库加载出来。
- 什么时候用延迟加载和立即加载:
- 延迟加载多用于查询一对多的时候,立即加载多用于查询一对一的时候,但并不绝对。
- 为什么要用延迟加载:
- 使用延迟加载的目的是为了减少系统资源的消耗,例如查询课程和选择此课程的学生的时候,当一个课程中只有几十个学生的时候,我们使用延迟加载和立即加载对系统资源的消耗并不明显,但是当一个课程有几千万个学生的时候,同时我们并不是立刻使用所有学生的信息。我们如果使用立即加载就会造成大量浪费系统资源,此时使用延迟加载的随用随取模式就会有很大的优势。
4.2 Insert插入
- 插入数据到表中要使用@Insert注解
例子:
@ResultMap("classDao")
@Insert("insert into class(id,teacher_id,student_id,class_nub,class_name,class_maxperson,class_haveperson,class_place) values(#{id},#{teacher_id},#{student_id},#{class_nub},#{class_name},#{class_maxperson},#{class_haveperson},#{class_place})")
void insertClass(Class aClass);
此中的所有字段都在Class实体类中,只要在#{}
中填入对应的字段名或者别名并将Class作为参数传入,Mybatis就会在Class中自动查找对应的关系。
4.3Update更新
- 更新数据到表中要使用@Update注解
例子:
@ResultMap("classDao")
@Update("update class set teacher_id=#{teacher_id},student_id=#{student_id},class_nub=#{class_nub},class_name=#{class_name},class_maxperson=#{class_maxperson},class_haveperson=#{class_haveperson},class_place=#{class_place} where id=#{id}")
void updateClassById(Class aClass);
4.4Delete删除
- 从表中删除数据使用@Delete注解
例子:
@ResultMap("classDao")
@Delete("delete from class where id=#{id}")
void deleteClassById(Integer classId);
5 创建相应的测试类
- text.java下创建测试类,测试类的目录结构最好与项目结构相同。所以我们在text.java.com.database.mybatis下创建测试类
testClass.java
。
- 想要能够使用我们创建好的接口操作数据库需要如下几个步骤:
- 读取数据库配置文件:用于连接数据库及其相关配置
- 使用建造者模式创建SqlSessionFactory工厂:使用建造者模式可以隐藏创建工厂的细节,直接将我们需要的工厂的“图纸”传入即可建造出我们想要的工厂。
- 使用工厂模式创建SqlSession对象:使用工厂模式创建SqlSession对象可以解耦,可以在不改变源码的方式进行操作
- 使用SqlSession创建Dao接口的代理对象执行方法:在不修改源码的基础上对已有方法增强,可是已实现不写Dao的实现类,就可以实现功能。
- 释放资源
例子:
//读取数据库配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//建造者模式创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//使用工厂模式生产SqlSession对象
SqlSession session = factory.openSession();
//使用SqlSession创建Dao接口的代理对象执行方法
ClassDao classDao = session.getMapper(ClassDao.class);
//使用代理对象执行方法
List<Class> aClass = classDao.findAll();
for (Class aClass1 : aClass) {System.out.println(aClass1);System.out.println(aClass1.getStudents());
}
- 但是在实际生产环境中我们可以更简单的进行操作:
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml").getMapper(ClassDao.class);List<Class> aClass = classDao.findAll();
for (Class aClass1 : aClass) {System.out.println(aClass1);System.out.println(aClass1.getStudents());
}
5.1 使用junit创建测试类
- 创建TestClass.java
- 在进行测试前我们需要进行上述配置拿到Dao的代理对象
public class TestClass {private InputStream in;private SqlSessionFactory factory;private SqlSession session;private ClassDao classDao;@Beforepublic void init() throws IOException {in = Resources.getResourceAsStream("SqlMapConfig.xml");factory = new SqlSessionFactoryBuilder().build(in);session = factory.openSession();classDao = session.getMapper(ClassDao.class);}
- 在测试结束后我们需要释放资源,所以增加如下方法:
@After
public void destroy() throws IOException {session.commit();session.close();in.close();
}
- 以通过id查询课程为例创建测试类。
- 创建testFindClassById方法。
- 通过代理对象调用findClassById方法并传入参数。
- 打印查询结果。
@Test
public void testFindClassById(){List<Class> classes = classDao.findClassById(1);for (Class aClass : classes) {System.out.println(aClass);}
}
Mybatis注解开发指北相关推荐
- MyBatis-学习笔记12【12.Mybatis注解开发】
Java后端 学习路线 笔记汇总表[黑马程序员] MyBatis-学习笔记01[01.Mybatis课程介绍及环境搭建][day01] MyBatis-学习笔记02[02.Mybatis入门案例] M ...
- Mybatis注解开发笔记
Mybatis注解开发(笔记) 欢迎来到菜鸟研究所 创建新的Maven项目 配置文件 prom.xml log4j.properties jdbcConfig.properties SqlMapCom ...
- Mybatis注解开发(超详细)
Mybatis注解开发 mybatis的常用注解 使用 Mybatis 注解实现基本 CRUD 项目目录结构 编写实体类 使用注解方式开发持久层接口 编写 SqlMapConfig.xml 配置文件 ...
- Mybatis 注解开发 + 动态SQL
Hello 大家好我是橙子同学,今天分享注解Mybatis注解开发+动态sql 目录 每文一铺垫(今天有小插曲哦) 注解开发 添加 @Insert 删除 @Delete 查询 @Select 修改 @ ...
- Mybatis注解开发(一对一)
其他代码访问:Mybatis注解开发基础操作 1.添加OrderMapper接口 public interface OrderMapper {// @Select("select *,o.i ...
- java day56【 Mybatis 延迟加载策略 、 Mybatis 缓存、Mybatis 注解开发 】
第1章 Mybatis 延迟加载策略 1.1 何为延迟加载? 1.2 实现需求 1.3 使用 assocation 实现延迟加载 1.3.1 账户的持久层 DAO 接口 1.3.2 账户的持久层映射文 ...
- Mybatis注解开发出现Type interface Mapper.StudentMapper is not known to the MapperRegistry异常解决办法
Mybatis注解开发出现Type interface Mapper.StudentMapper is not known to the MapperRegistry异常解决办法 在核心配置文件中,配 ...
- mybatis注解开发动态sql
mybatis注解开发动态sql 本篇来讲一下如何使用mybatis注解模式中的动态sql 先来讲一下什么是动态sql 在我们实际开发的时候可能会出现很多方法需要一条很相似的sql语句来进行增删改查, ...
- (软件工程)GPU并行软件开发指北
事先声明,本篇博文中不涉及任何技术,原理和代码.如果想知道GPU开发实践方法,请直接查阅OpenCL与CUDA开发手册. 在"GPU并行软件开发指北"这篇博文中,我仅仅是想谈论一下 ...
最新文章
- python中label组件参数_Python tkinter(六) 标签(Label)组件的属性说明及示例
- python语言学了有用吗-转行学习Python开发有什么优势
- Java 14 发布了,再也不怕 NullPointerException 了!
- Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.
- Android:Eclipse+ADT+Android SDK 搭建安卓开发环境
- php object 对象不存在。增加对象_《相亲者女》:找一个匹配的对象,但永远不存在...
- java实现串口通信 485协议
- 如何理解原码一位乘法的计算过程
- java的第十一章总结(枚举,泛型)
- JavaScript系列之条件运算符
- Multipass中文文档-教程
- 云端守望者(下):十八般武艺
- 【OpenCV+Qt】实现简易视频播放器——支持进度条拖动
- QT项目练习--砍多多校园二手交易平台(C++)
- 网上酒店客房预定系统数据库设计
- CAD二次开发 关于BlockTable、BlockTableRecord和BlockReference的一丢丢理解
- 小吴的《机器学习 周志华》学习笔记 第一章 绪论
- 论文阅读_音频压缩_Encodec
- 淘沙河 - 清凉解暑之电风扇
- graph embedding 论文及源码阅读 deepwalk line node2vec bine