MyBatis的纯注解方式去掉了原来的mapper文件,不用写实体类的配置文件,直接在接口里面写查询语句,在SqlMapperConfig.xml只需要指定接口所在的包即可。接下来就用一个案例部门和员工来实现纯注解开发。
(1)创建maven工程,导入jar包。
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.25</version>
</dependency>
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
(2)数据库文件的准备。
t_dept文件:
CREATE TABLE `t_dept` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`dept_name` varchar(20) DEFAULT NULL,
`dept_desc` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
);
insert into t_dept(dept_name, dept_age) values("开发部","软件开发");
insert into t_dept(dept_name, dept_age) values("测试部","软件测试");
insert into t_dept(dept_name, dept_age) values("财务部","发放钱财");
insert into t_dept(dept_name, dept_age) values("人事部","招聘员工");
t_emp文件:
CREATE TABLE `t_emp` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`emp_name` varchar(20) DEFAULT NULL,
`emp_age` int(11) DEFAULT NULL,
`dept_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `dept_id` (`dept_id`),
CONSTRAINT `t_emp_ibfk_1` FOREIGN KEY (`dept_id`) REFERENCES `t_dept` (`id`)
);
INSERT INTO `t_emp` VALUES (1,'张倩',22,2),(2,'杨帆',24,1),(3,'章飞',21,3),(4,'李冰',51,4),(5,'王猛',36,3),(6,'康生',26,1),(7,'刘婷',20,3),(8,'刘羽',22,2);
(3)在dao包下创建实体类员工类和部门类。
部门类:
public class Department {
private Integer id;
private String deptName;
private String deptDesc;
private List<Emp> empList;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public String getDeptDesc() {
return deptDesc;
}
public void setDeptDesc(String deptDesc) {
this.deptDesc = deptDesc;
}
public List<Emp> getEmpList() {
return empList;
}
public void setEmpList(List<Emp> empList) {
this.empList = empList;
}
@Override
public String toString() {
return "Department{" +
"id=" + id +
", deptName='" + deptName + '\'' +
", deptDesc='" + deptDesc + '\'' +
", empList=" + empList +
'}';
}
}
员工类:
public class Emp {
private Integer id;
private String empName;
private Integer empAge;
private Integer deptId;
public Emp() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public Integer getEmpAge() {
return empAge;
}
public void setEmpAge(Integer empAge) {
this.empAge = empAge;
}
public Integer getDeptId() {
return deptId;
}
public void setDeptId(Integer deptId) {
this.deptId = deptId;
}
@Override
public String toString() {
return "Staff{" +
"id=" + id +
", empName='" + empName + '\'' +
", empAge=" + empAge +
", deptId=" + deptId +
'}';
}
}
(4)在dao包下创建IDepartmentDao和IEmpDao。
IDepartmentDao:
public interface IDepartmentDao {
@Select(value = "select * from t_dept")
@Results(value = {
@Result(id=true, column = "id", property = "id"),
@Result(column = "dept_name", property = "deptName"),
@Result(column = "dept_desc", property = "deptDesc"),
@Result(column = "id", property = "empList", javaType = List.class,many = @Many(select = "com.dao.IEmpDao.findByDeptId"))
})
List<Department> findAll();
@Select(value = "select * from t_dept where id = #{id}")
@Results(value = {
@Result(id=true, column = "id", property = "id"),
@Result(column = "dept_name", property = "deptName"),
@Result(column = "dept_desc", property = "deptDesc")
})
List<Department> findById(int id);
}
IEmpDao:
public interface IEmpDao {
@Select("select * from t_emp")
@Results(id = "empMap",value={
@Result(id=true, column = "id", property = "id"),
@Result(column = "emp_name", property = "empName"),
@Result(column = "emp_age", property = "empAge"),
@Result(property = "department", column = "dept_id", one = @One(select = "com.dao.IDepartmentDao.findById", fetchType = FetchType.EAGER))
})
List<Emp> findDepartment();
@Select("select * from t_emp where id = #{id}")
@Results(value={
@Result(id=true, column = "id", property = "id"),
@Result(column = "emp_name", property = "empName"),
@Result(column = "emp_age", property = "empAge"),
})
List<Emp> findByDeptId(int id);
}
(5)在resources目录下引入log4j.properties和SqlMapperConfig.xml。
log4j.properties:
### 设置###
log4j.rootLogger = debug,stdout
### 输出信息到控制抬 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
pender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
SqlMapperConfig.xml:
<?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>
<!-- 配置环境 -->
<environments default="mysql">
<!-- 配置MySQL的环境 -->
<environment id="mysql">
<!-- 配置事务的类型 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置数据源(连接池) -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///universaldb"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--接口的注册-->
<!--之前是配置实体类的映射文件,现在没有了,直接配置接口-->
<mappers>
<package name="com.dao"/>
</mappers>
</configuration>
(6)创建测试类
package com;
import com.dao.IDepartmentDao;
import com.dao.IEmpDao;
import com.entity.Department;
import com.entity.Emp;
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 org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
* 功能描述:
*
* @Author: aaa
* @Date: 2021/2/18 11:33
*/
public class TestAnno {
InputStream in = null;
SqlSessionFactoryBuilder builder = null;
SqlSessionFactory factory = null;
SqlSession sqlSession = null;
@Before
public void init() throws IOException {
//1、读取配置文件
in = Resources.getResourceAsStream("SqlMapperConfig.xml");
//2、创建SqlSessionFactory工厂
builder = new SqlSessionFactoryBuilder();
factory = builder.build(in);
//3、使用工厂生产SqlSession对象
sqlSession = factory.openSession();
}
@After
public void destory() throws IOException {
sqlSession.commit();
sqlSession.close();
in.close();
}
@Test
public void testDeptAll(){
IDepartmentDao departmentDao = sqlSession.getMapper(IDepartmentDao.class);
List<Department> departmentList = departmentDao.findAll();
System.out.println(departmentList);
}
@Test
public void testeMPAll(){
IEmpDao staffAnnoDao = sqlSession.getMapper(IEmpDao.class);
List<Emp> empList = staffAnnoDao.findDepartment();
System.out.println(empList);
}
}
MyBatis多参数查询的注解开发方式如下:
@Select("select * from t_people where name=#{name} and address=#{address}")
List<People> findByMorePara(@Param("name") String name, @Param("address") String address);
以上就是MyBatis注解开发的案例。
总结:
1、@Results各个属性的含义
(1)id为当前结果集声明唯一标识。
(2)value值为结果集映射关系。
(3)@Result代表一个字段的映射关系。
- column指定数据库字段的名称。
- property指定实体类属性的名称。
- dbcType数据库字段类型,@Result里的id值为true表明主键,默认false;
(4)使用@ResultMap来引用映射结果集,其中value可省略。当这段@Results代码需要在多个方法用到时,为了提高代码复用性,可以为这个@Results注解设置id,然后使用@ResultMap注解来复用这段代码。
(5)案例:
@Select(value = "select * from t_dept")
@Results(value = {
@Result(id=true, column = "id", property = "id"),
@Result(column = "dept_name", property = "deptName"),
@Result(column = "dept_desc", property = "deptDesc")
})
List<Department> findAll();
2、one和Many的用法
(1)One的用法
当我们需要通过查询到的一个字段值作为参数,去执行另外一个方法来查询关联的内容,而且两者是一对一关系时,可以使用@One注解来便捷的实现。比如当我们需要查询学生信息以及其所属班级信息时,需要以查询到的class_id为参数,来执行ClassesMapper中的selectById方法,从而获得学生所属的班级信息.
案例:
@Select("select * from t_emp")
@Results(id = "empMap",value={
@Result(id=true, column = "id", property = "id"),
@Result(column = "emp_name", property = "empName"),
@Result(column = "emp_age", property = "empAge"),
@Result(property = "department", column = "dept_id", one = @One(select = "com.dao.IDepartmentDao.findById", fetchType = FetchType.EAGER))
})
List<Emp> findDepartment();
(2)Many的用法
与@One类似,只不过如果使用@One查询到的结果是多行,会抛出TooManyResultException异常,这种时候应该使用的是@Many注解,实现一对多的查询。比如在需要查询学生信息和每次考试的成绩信息时.
案例:
@Select(value = "select * from t_dept")
@Results(value = {
@Result(id=true, column = "id", property = "id"),
@Result(column = "dept_name", property = "deptName"),
@Result(column = "dept_desc", property = "deptDesc"),
@Result(column = "id", property = "empList", javaType = List.class,many = @Many(select = "com.dao.IEmpDao.findByDeptId"))
})
List<Department> findAll();
错误总结:
问题一:Result Maps collection already contains value for com.dao.IEmpDao.empMap。
原因:在IEmpDao中存在id为"empMap"的resultMap值
问题二:MyBatis一对多只显示一个结果的问题。
原因:在一对多操作中的两张表,它们的主键名称相同引发的问题,只要设置为不同的主键名称就可以了。即:实体类的属性名可以相同,数据库的列名要不同。例如:员工表的主键为id,部门表的主键也为id,就会引发上面的问题。如果员工表的主键改为emp_id,部门表的主键改为dept_id,则不会触发此问题。