第一节 复习
初识mybatis
使用步骤 :
(1)导入jar包(11个 1个核心,9个依赖,1个数据库)
(2)准备文件(数据库的属性文件,log4j的属性文件) 【位置位于src下】
(3)编写xml文件
(4)编写实体类 (对应的是数据库中的表)
(5)编写mapper.xml文件
(6)关联
(7)测试
出现问题的原因:字段名称与属性名称不一致,导致mybatis的自动映射失败
解决方案:使用手动映射, 修 改mapper.xml文件
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="abc.a">
<select id="query" resultMap="rm">
select * from dept
</select>
<resultMap id="rm" type="dept">
<!--开始字段与属性的手动映射-->
<!---主键列使用id-->
<id column="deptno" property="deptNo"></id>
<!--普通列使用result-->
<result column="dname" property="deptName"></result>
<result column="loc" property="deptLoc"></result>
</resultMap>
</mapper>
需要在mybatis中再添加上这个mapper标签,这里省略。
package com.bjsxt.test;
import com.bjsxt.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 java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
*测试类
*/
public class Test {
public static void main(String[] args) throws IOException {
InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = build.openSession();
List<Dept> list = sqlSession.selectList("abc.a.query");
System.out.println(list);
sqlSession.close();
}
}
第二节 Mybatis中的代理
为什么需要使用mybatis的动态代理
因为有利于程序的扩展和维护
mybatis使用动态代理的步骤
(1)编写实体类
(2)编写接口
package com.bjsxt.mapper;
import com.bjsxt.entity.Dept2;
import java.util.List;
public interface Dept2Mapper {
public List<Dept2> queryAll();
public Dept2 selectByNo(int deptNo);
public int insertDept2(Dept2 dept2);
}
(3)编写mapper.xml文件 (要求:命名空间的名称为接口的全路径)
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjsxt.mapper.Dept2Mapper"> <!---接口如何与xml关联,就是xml的命名空间为接口的全路径-->
<select id="queryAll" resultType="dept2"> <!--id的值为接口中方法的名称-->
select * from dept
</select>
<select id="selectByNo" resultType="dept2">
select * from dept where deptNo=#{0} <!--这里面的0可以换成a、para 亲测>
</select>
<insert id="insertDept2">
insert into dept values (#{deptNo},#{dname},#{loc})
</insert>
</mapper>
(4)关联
(5)测试类
package com.bjsxt.test;
import com.bjsxt.entity.Dept;
import com.bjsxt.entity.Dept2;
import com.bjsxt.mapper.Dept2Mapper;
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 java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class Test2 {
public static void main(String[] args) throws IOException {
//(1)解析
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");
//(2)
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
//(3)
SqlSession sqlSession = build.openSession();
//(4) 多态,接口 "new 实现类() " 使用反射
// = 的左侧为接口类型 , =右侧, 实际为接口的实现类,
Dept2Mapper mapper = sqlSession.getMapper(Dept2Mapper.class);
//对象名.方法名
List<Dept2> dept2s = mapper.queryAll();
System.out.println(dept2s);
System.out.println("------------------------------------");
Dept2 dept2 = mapper.selectByNo(20);
System.out.println(dept2);
System.out.println("-----------------------------");
int i = mapper.insertDept2(new Dept2(50, "fda", "fdsa"));
System.out.println(i);
sqlSession.commit();
//(5)
sqlSession.close();
}
}
第三节 多表查询
一、业务方式
(1)一对一关系 一个员工只能在一个部门
需求: 查询员工及员工所在部门的信息
SQL语句
a)select * from emp ; -->查询出所有员工信息
b)select * from dept where deptno=?
业务代码实现
a)查询出所有的员工存放到集合中 public List<Emp> queryAll(){}
b)遍历集合,可以得到每个员工的部门编号
c)根据部门编号查询对应的部门信息 public Dept queryByNo(int deptNo)
d)Emp的实体中增加Dept类型的属性,用于存储对应的员工的部门信息
(1)查询所有的员工信息
package com.bjsxt.mapper;
import com.bjsxt.entity.Emp;
import java.util.List;
public interface EmpMapper {
public List<Emp> queryAll();
}
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjsxt.mapper.EmpMapper">
<select id="queryAll" resultType="emp">
select * from emp
</select>
</mapper>
(2)根据部门编号查询部门信息
package com.bjsxt.mapper;
import com.bjsxt.entity.Dept;
public interface DeptMapper {
public Dept selectByNo(int deptNo);
}
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjsxt.mapper.DeptMapper">
<select id="selectByNo" resultType="dept">
select * from dept where deptno=#{0}
</select>
</mapper>
(3)测试,使用java代码进行“组合”
package com.bjsxt.test;
import com.bjsxt.entity.Dept;
import com.bjsxt.entity.Emp;
import com.bjsxt.mapper.DeptMapper;
import com.bjsxt.mapper.EmpMapper;
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 java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class TestOne {
public static void main(String[] args) throws IOException {
//(1)解析xml
InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
//(2)获取工厂对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//(3)获取session对象
SqlSession sqlSession = factory.openSession();
//(4)业务的方法实现一对一的查询,使用java代码去组织,实现表连查的效果
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);
List<Emp> list = mapper.queryAll(); // 查询出所有的员工信息
for(Emp emp:list){
//获取每个员工的部门编号
int deptNo = emp.getDeptNo();
//调用根据编号查询部门信息的方法
Dept dept = deptMapper.selectByNo(deptNo);
//将查询到的部门信息使用set方法为Emp中的dept属性赋值
emp.setDept(dept);
}
System.out.println("---------------遍历每一个员工及部门信息---------------------");
System.out.println(list.size());
for(Emp emp:list){
System.out.println(emp);
}
//(5)关闭
sqlSession.close();
}
}
(2)一对多的关系 一个部门(有)对应多个员工
SQL语句 : select * from dept 查询所有部门 public List<Dept> selectAll()
select * from emp where deptno=? public List<Emp> selectByNo(int deptNo);
业务代码 :
a) 查询出所有的部门信息,放到集合里
b)遍历集合得到每个部门编号
c)在员工表中根据部门编号查询
d)在Dept类中增加List类型的属性,用于存储部门所对应的员工信息
public interface DeptMapper {
public List<Dept> selectAll();
}
<select id="selectAll" resultType="dept">
select * from dept
</select>
public interface EmpMapper {
public List<Emp> selectByNo(int deptNo);
}
<select id="selectByNo" resultType="emp">
select * from emp where deptno=#{0}
</select>
测试
package com.bjsxt.test;
import com.bjsxt.entity.Dept;
import com.bjsxt.entity.Emp;
import com.bjsxt.mapper.DeptMapper;
import com.bjsxt.mapper.EmpMapper;
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 java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class TestOneMore {
public static void main(String[] args) throws IOException {
//(1)解析xml
InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
//(2)获取工厂对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//(3)获取session对象
SqlSession sqlSession = factory.openSession();
//(4)业务的方法实现一对一的查询,使用java代码去组织,实现表连查的效果
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);
List<Dept> list = deptMapper.selectAll();//查询所有的部门信息
//遍历部门
for(Dept dept:list){
int deptNo = dept.getDeptNo();
//根据部门编号查询员工信息
List<Emp> list1 = mapper.selectByNo(deptNo);
//将员工信息添加到Dept类中的List<Emp>类型的属性
dept.setEmpList(list1);
}
System.out.println("------------遍历list集合----------------");
for(Dept dept:list){
System.out.println(dept);
}
//(5)关闭
sqlSession.close();
}
}
业务方式实现多表查询的效果,实际上底层是两 个单表的查询,使用java代码,"组织"成多表查询的效果
二、N+1方式
业务方式:实际上是两个单表的查询,使用java进行“组合”成两表连查的效果
优点:简单,容易理解
缺点:书写的代码比较麻烦
业务方式的缺点可以使用N+1解决
N +1 :N +1是指执行的sql语句的条数是N+1条,底层也是两个单表的查询,是使用"xml"文件进行配置来实现的
(1)一对一 :一个员工对应一个部门
需求:查询所有员工及员工所对应的部门信息
sql: select * from emp ;
select * from dept where deptno=?
配置XML文件,mapper.xml文件
使用一个名称为标签来实现
EmpMapper接口
public List<Emp>queryAllN();
DeptMapper接口
public Dept selectByNoN(int deptNo);
xml文件
DeptMapper.xml
<select id="selectByNoN" resultType="dept">
select * from dept where deptno=#{0}
</select>
EmpMapper.xml
<select id="queryAllN" resultMap="rm">
select * from emp
</select>
<resultMap id="rm" type="emp">
<!---emp表中的id,和result-->
<id column="empno" property="empNo"></id>
<result column="ename" property="ename"></result>
<result column="job" property="job"></result>
<!--需要执行哪个sql语句了 一对一-->
<association property="dept" select="com.bjsxt.mapper.DeptMapper.selectByNoN"
javaType="dept" column="deptno"></association>
</resultMap>
package com.bjsxt.test;
import com.bjsxt.entity.Dept;
import com.bjsxt.entity.Emp;
import com.bjsxt.mapper.DeptMapper;
import com.bjsxt.mapper.EmpMapper;
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 java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class TestOneN {
public static void main(String[] args) throws IOException {
//(1)解析xml
InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
//(2)获取工厂对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//(3)获取session对象
SqlSession sqlSession = factory.openSession();
//(4)业务的方法实现一对一的查询,使用java代码去组织,实现表连查的效果
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
List<Emp> list = mapper.queryAllN();
for(Emp emp:list){
System.out.println(emp);
}
//(5)关闭
sqlSession.close();
}
}
需要使用标签
association标签的常用的4个属性
a)select : 指明要”调用“sql语句
举例select=“com.bjsxt.mapper.DeptMapper.selectByNoN”
属性值 ;要执行的sql语句所在xml文件的命名空间+select标签的id值
b)javaType: select 查询语句的返回值的类型 selectByNoN查询的返回值类型
c)property: select 查询结果存储在Emp这个类的哪个属性里
d)column: 根据表中的哪个列查询
(1)一对多 :一个部门对应多个员工
SQL : select * from dept
select * from emp where deptno=?
N+1方法:配置mapper.xml文件
EmpMapper接口
public List<Emp> selectByNoN(int deptNo);
DeptMapper接口
public List<Dept> selectAllN();
EmpMapper.xml
<select id="selectByNoN" resultType="emp">
select * from emp where deptno=#{0}
</select>
DeptMapper.xml
<select id="selectAllN" resultMap="rm">
select * from dept
</select>
<resultMap id="rm" type="dept">
<!---dept表的主键列和其它列-->
<id column="deptno" property="deptNo"></id>
<result column="dname" property="dname"></result>
<result column="loc" property="loc"></result>
<!--多,由于查询的一个部门的员工有很多,所以使用的标签为collection-->
<collection select="com.bjsxt.mapper.EmpMapper.selectByNoN" property="empList"
ofType="emp" column="deptno"></collection>
</resultMap>
测试类
package com.bjsxt.test;
import com.bjsxt.entity.Dept;
import com.bjsxt.entity.Emp;
import com.bjsxt.mapper.DeptMapper;
import com.bjsxt.mapper.EmpMapper;
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 java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class TestOneMoreN {
public static void main(String[] args) throws IOException {
//(1)解析xml
InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
//(2)获取工厂对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//(3)获取session对象
SqlSession sqlSession = factory.openSession();
//(4)业务的方法实现一对一的查询,使用java代码去组织,实现表连查的效果
DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);
List<Dept> list = deptMapper.selectAllN();
for(Dept dept:list){
System.out.println(dept);
}
//(5)关闭
sqlSession.close();
}
}
一对多查询,使用到<collection标签>该标签有4个常用属性
a) select : 指要执行的sql语句
b)property:查询结果放到实体中的哪个属性存储
c)ofType :select 查询的返回值的类型
d)column: 根据哪个列进行查询
三、表连接查询
N+1的优点:不需要写业务代码
缺点:执行的sql语句的数量比较多,效率比较低
为什么表连接方式?
(1)不用写业务代码(java代码不用写太多)
(2) 只需要执行一个表连接查询即可 (sql只有一句)
一对一 :一个员工对应一个部门
SQL: select * from emp e ,dept d where e.deptno=d.deptno
通过mapper.xml文件的配置来实现
依然使用的是resultMap标签
接口中的方法
public List<Emp> queryAllTable();
配置xml文件
<!--表连接查询-->
<select id="queryAllTable" resultMap="rm1">
select * from emp e ,dept d where e.deptno=d.deptno
</select>
<resultMap id="rm1" type="emp">
<!--查询结果中只有这三个列有值-->
<id column="empno" property="empNo"></id>
<result column="ename" property="ename"></result>
<result column="job" property="job"></result>
<!--连接的dept表的中列-->
<association property="dept" javaType="dept">
<id column="deptno" property="deptNo"></id>
<result column="dname" property="dname"></result>
<result column="loc" property="loc"></result>
</association>
</resultMap>
一对一,使用
一对多 一个部门对应N多个员工
SQL :select * from emp e ,dept d where e.deptno=d.deptno
配置mapper.xml文件来实现
接口中的方法
public List<Dept> selectAllTable();
配置xml文件
<!--表连接查询-->
<select id="queryAllTable" resultMap="rm1">
select * from emp e ,dept d where e.deptno=d.deptno
</select>
<resultMap id="rm1" type="emp">
<!--查询结果中只有这三个列有值-->
<id column="empno" property="empNo"></id>
<result column="ename" property="ename"></result>
<result column="job" property="job"></result>
<!--连接的dept表的中列-->
<association property="dept" javaType="dept">
<id column="deptno" property="deptNo"></id>
<result column="dname" property="dname"></result>
<result column="loc" property="loc"></result>
</association>
</resultMap>
一对一,使用
一对多 一个部门对应N多个员工
SQL :select * from emp e ,dept d where e.deptno=d.deptno
配置mapper.xml文件来实现
public List<Dept> selectAllTable();
<select id="selectAllTable" resultMap="rm1">
select * from emp e right join dept d on e.deptno=d.deptno
</select>
<resultMap id="rm1" type="dept">
<id column="deptno" property="deptNo"></id>
<result column="dname" property="dname"></result>
<result column="loc" property="loc"></result>
<!--连接emp表-->
<collection property="empList" ofType="emp">
<id column="empno" property="empNo"></id>
<result column="ename" property="ename"></result>
</collection>
</resultMap>
一对多,使用标签
resultMap标签的作用
(1)手动映射
(2)n+1方式的果询
(3)表连接查询