目录
一、项目框架搭建
二、在实体类中添加额外属性实现多表查询
1、mybatis两表关联查询
(1)实体类类型映射规则
(2)代码演示
2、分步查询
(1)autoMapping开启自动映射
(2)封装SQL语句
(2)懒加载
三、MyBatis对一对多关系的处理
1、collection配置集合映射
2、代码演示
3、规范mapper映射文件
(1)准备两个数据库表:员工表和部门表
CREATE DATABASE mybatisdatabase;
USE mybatisdatabase;
CREATE TABLE emp(
id INT PRIMARY KEY AUTO_INCREMENT COMMENT '员工编号',
ename VARCHAR(20) NOT NULL COMMENT '员工姓名',
age INT NOT NULL COMMENT '年龄',
deptno INT NOT NULL COMMENT '部门编号'
);
INSERT INTO emp(ename,age,deptno) VALUES
('tom',18,1),
('jack',20,1),
('小黑',19,2),
('老默',31,2),
('启强',24,2);
CREATE TABLE dept(
id INT PRIMARY KEY AUTO_INCREMENT COMMENT '部门编号',
dept_name VARCHAR(20) NOT NULL COMMENT '部门名称',
`local` VARCHAR(20) NOT NULL COMMENT '部门地址'
);
INSERT INTO dept(dept_name,`local`) VALUES
('市场部','安徽合肥'),
('财务部','江苏南京'),
('生产部','安徽芜湖');
(2)新建module--->java框架Maven工程--->完善工程目录
(3)在pom.xml中添加需要使用的依赖
4.0.0
com.mybatis
mybatis04
1.0-SNAPSHOT
jar
mybatis04
http://maven.apache.org
UTF-8
junit
junit
4.12
test
org.mybatis
mybatis
3.5.11
mysql
mysql-connector-java
5.1.48
org.projectlombok
lombok
1.18.24
log4j
log4j
1.2.17
(4)创建实体类和Mapper接口
package com.mybatis.entity;
import lombok.Data;
@Data
public class Emp {
private long id;
private String ename;
private long age;
private long deptno;
}
package com.mybatis.entity;
import lombok.Data;
@Data
public class Dept {
private long id;
private String deptName;
private String local;
}
(5)在resources目录下新建config文件,存放mybatis全局配置文件和外部数据源
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/mybatisdatabase
jdbc.username=root
jdbc.password=123456
(6)在resources目录下新建与Mapper接口层级相同的文件夹存放Mapper映射文件
(7)在resources目录下添加日志配置文件log4j.properties
#打印日志的级别:可控制打印信息,哪些打印,哪些不打印
#Console:打印窗口
log4j.rootLogger=DEBUG,Console
#Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target=System.out
#设置打印格式
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
#设置打印信息
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
#打印日志级别:设置打印级别只要不是ERROR级别就不打印
log4j.logger.org.apache=ERROR
log4j.logger.org.mybatis=ERROR
log4j.logger.org.springframework=ERROR
#这个需要
log4j.logger.log4jdbc.debug=ERROR
log4j.logger.com.gk.mapper=ERROR
log4j.logger.jdbc.audit=ERROR
log4j.logger.jdbc.resultset=ERROR
#这个打印SQL语句非常重要
log4j.logger.jdbc.sqlonly=DEBUG
log4j.logger.jdbc.sqltiming=ERROR
log4j.logger.jdbc.connection=FATAL
package com.mybatis.entity;
import lombok.Data;
@Data
public class Emp {
private long id;
private String ename;
private long age;
private long deptno;
//添加额外属性
private Dept dept;
}
package com.mybatis.mapper;
import com.mybatis.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.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import static org.junit.Assert.*;
public class EmpMapperTest {
SqlSessionFactory sqlSessionFactory = null;
@Before
public void init(){
System.out.println("init()被执行");
InputStream resourceAsStream = null;
try {
resourceAsStream = Resources.getResourceAsStream("config/mybatis-config.xml");
} catch (IOException e) {
e.printStackTrace();
}
sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
}
@Test
public void select() {
//创建SqlSession会话
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取EmpMapper接口的动态代理对象
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
//通过接口调用方法
List select = empMapper.select();
for (Emp emp:select){
System.out.println("emp = " + emp);
}
//关闭资源
sqlSession.close();
}
}
dept是空的,因为目前只查询了员工表(emp)
查询的结果只有员工表(emp)的数据,deft依旧为空,dept为实体类对象,mybatis目前还不能自动赋值
association标签:连接两个表,获取多个表中的信息,以及在一对一、多对多的关系中获取相关数据
property:实体类对象
package com.mybatis.mapper;
import com.mybatis.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.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import static org.junit.Assert.*;
public class EmpMapperTest {
//创建SqlSessionFactory工厂对象
SqlSessionFactory sqlSessionFactory = null;
@Before
public void init(){
System.out.println("init()");
InputStream resourceAsStream;
try {
resourceAsStream = Resources.getResourceAsStream("config/mybatis-config.xml");
} catch (IOException e) {
throw new RuntimeException(e);
}
sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
}
@Test
public void selectByEmpJoinDept() {
//创建SqlSession会话
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取EmpMapper动态代理对象
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
//通过接口调用方法
List empList = empMapper.selectByEmpJoinDept();
for (Emp emp:empList){
System.out.println("emp = " + emp);
}
//关闭资源
sqlSession.close();
}
}
在做多表查询时,有时我们不需要所有表的数据,但一条SQL语句会查询出所有表的数据,大大降低了数据库的性能,我们可根据分步查询解决这个弊端
自动映射默认是关闭的(但代码运行时也会自动开启),可以通过设置autoMapping的属性值为“true”开启自动映射,不能够完成自动映射的字段,会按照已设置的映射规则进行映射
我们可通过封装从表数据的方式,在需要从表的数据时查询从表,以此来实现分步查询。
在association标签中使用select属性和column属性:
select:指定一条SQL语句;
column:指定主表的哪一字段作为参数传递
上面我们使用的SQL语句无论你是否需要关联表(dept)中的数据,都会去查询关联表中的数据,当我们只需要emp表中的数据时也会去查询dept表,降低了数据库的性能
按需加载,先从表单查询,需要时再从关联表去关联查询,能大大提升数据库性能
在association标签中设置fetchType属性值为"lazy"开启懒加载,分步查询正式完成
package com.mybatis.mapper;
import com.mybatis.entity.Emp;
import java.util.List;
public interface EmpMapper {
List select();
}
package com.mybatis.mapper;
import com.mybatis.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.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import static org.junit.Assert.*;
public class EmpMapperTest {
//创建SqlSessionFactory工厂对象
SqlSessionFactory sqlSessionFactory = null;
@Before
public void init(){
System.out.println("init()");
InputStream resourceAsStream;
try {
resourceAsStream = Resources.getResourceAsStream("config/mybatis-config.xml");
} catch (IOException e) {
throw new RuntimeException(e);
}
sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
}
@Test
public void select() {
//创建SqlSession会话
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取EmpMapper动态代理对象
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
//通过接口调用方法
List select = empMapper.select();
for (Emp emp:select){
System.out.println("ename:"+emp.getEname());
}
//关闭资源
sqlSession.close();
}
}
一对一关系:一个员工只属于一个部门
一对多关系:一个部门有多个员工
以dept为主表,查询每个部门中的所有员工
一个部门对应的员工查询结果是一个Emp对象的集合,MyBatis中提供了对集合配置映射的标签:collection
--->ofType:指定集合中的数据类型
package com.mybatis.entity;
import lombok.Data;
import java.util.List;
@Data
public class Dept {
private long id;
private String deptName;
private String local;
//添加额外属性
private List emps;
}
package com.mybatis.mapper;
import com.mybatis.entity.Dept;
import java.util.List;
public interface DeptMapper {
List select();
}
package com.mybatis.mapper;
import com.mybatis.entity.Dept;
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.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import static org.junit.Assert.*;
public class DeptMapperTest {
//创建SqlSessionFactory工厂对象
SqlSessionFactory sqlSessionFactory = null;
@Before
public void init(){
System.out.println("init()");
InputStream resourceAsStream;
try {
resourceAsStream = Resources.getResourceAsStream("config/mybatis-config.xml");
} catch (IOException e) {
throw new RuntimeException(e);
}
sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
}
@Test
public void select() {
//创建SqlSession会话
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取DeptMapper动态代理对象
DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);
//通过接口调用方法
List select = deptMapper.select();
for (Dept dept:select){
System.out.println("dept = " + dept.getDeptName());
}
sqlSession.close();
}
}
每个表的查询语句应该在自己的mapper文件下,我们以上使用的对两个表查询的SQL语句定义在了一个mapper文件中,
两个mapper文件的SQL语句可通过nameSpace属性值调用