MyBatis框架 Mapper代理

2022-08-14 13:56:42

1.文件目录标准结构

  • 项目包结构

控制层 com.system.controiler
逻辑业务层 com.system.service(接口类所放的包名)com.system.service.impl(实现类所放的包名)
数据访问层 com.system.dao(接口类所放的包名)com.system.dao.impl(实现类所放的包名)

  • Mapper命名要求
  • 要求1:Mapper接口类中命名规则为:***Mapper.xml,接口中声明的是对数据库操作的方法
  • 要求2: 实体映射文件的命名要与所定义的接口名字一致!!namespace属性值必须是对应Mapper接口的全路径!!SQL查询的id和参数也要与接口中的方法一致!!(使得该xml文件与对应的接口类建立联系

2.优化配置文件格式

  • 优化1:优化主配置文件SqlMapConfig.xml中的映射器结构
    未优化前:
    <mappers><mapperresource="com/system/mapper/EmpMapper.xml"/><mapperresource="com/system/mapper/DeptMapper.xml"/></mappers>
    优化后:让系统自动扫描该包下的xml文件
    <mappers><packagename="com.system.mapper"/></mappers>
  • 优化2:优化映射文件中接口类名字的书写
    通过在主配置文件SqlMapConfig.xml中,定义实体类的别名,即不用在映射文件中写实体类的全路径名(让系统自动扫描并命别名,别名即为实体类命,首字符大小写均可)
    <typeAliases><packagename="com.system.entity"/></typeAliases>
  • 优化3:数据库配置的优化(让数据库配置信息与xml文件分离)
    • 让数据库的配置信息配置在独立文件:db.properties (该后缀名配置文件以键值对的形式,建=值)例如:
    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://127.0.0.1:3306/empdb?characterEncoding=utf8
    jdbc.username=root
    jdbc.password=设置的密码
    • 然后在主配置文件SqlMapConfig.xml中导入db.properties
    <!-- 导入db.properties --><propertiesresource="db.properties"></properties>
    • 数据源的配置,使用${键}的形式来引用properties文件中的值
    <dataSourcetype="POOLED"><propertyname="driver"value="${jdbc.driver}"/><propertyname="url"value="${jdbc.url}"/><propertyname="username"value="${jdbc.username}"/><propertyname="password"value="${jdbc.password}"/></dataSource>

3.创建Mapper代理

  • Mapper代理通俗来说就是通过调用所定义好的接口中的方法来实现相关业务。而方法的实现则在XML文件中定义(或使用注解定义)
//创建SqlSessionFactory工厂类可封装成一个Util类try{InputStream input=Resources.getResourceAsStream("SqlMapConfig.xml");SqlSessionFactory sqlSessionFactory=newSqlSessionFactoryBuilder().build(input);SqlSession sqlSession= sqlSessionFactory.openSession();//获得会话对象//使用Mapper代理DeptMapper deptMapper= sqlSession.getMapper(DeptMapper.class);//获得了DeptMapper接口类的代理}catch(IOException e){
	e.printStackTrace();}

4.利用Mapper代理进行增、删、改、查

1)增

  • 在对应接口的映射文件中
<insertid="insertDept"parameterType="com.system.entity.Dept">
		insert into dept (dname,loc) values (#{dname},#{loc})</insert>
  • 也可以在接口类中用注解的方式(注解的方式适合简单的单表查询!!)
@Insert("insert into dept (dname,loc) values (#{dname},#{loc})")//只需将SQL语句写入,参数与返回值会自动与接口参数匹配!@Options(useGeneratedKeys=true, keyProperty="deptno")//其他参数publicvoidinsertDept(Dept dept);

2)删

  • 在对应接口的映射文件中
<deleteid="deleteDept"parameterType="Integer">
	delete from dept where deptno = #{deptno}</delete>
  • 也可以在接口类中用注解的方式(注解的方式适合简单的单表查询!!)
@Delete("delete from dept where deptno = #{deptno}")publicintdeleteDept(Integer deptno);

3)改

  • 在对应接口的映射文件中
<updateid="updateDept"parameterType="com.system.entity.Dept">
	update dept set dname=#{dname},loc=#{loc} where deptno = #{deptno}</update>
  • 也可以在接口类中用注解的方式(注解的方式适合简单的单表查询!!)
@Update("update dept set dname=#{dname},loc=#{loc} where deptno = #{deptno}")publicintupdateDept(Dept dept);

4)查

a)单表查询

  • 在对应接口的映射文件中
<selectid="getDeptAll"resulType="com.system.entity.Dept">
	select * from dept</select>
  • 也可以在接口类中用注解的方式(注解的方式适合简单的单表查询!!)
@Select("select * from dept")publicList<Dept>getDeptAll();

b)多表查询

通过修改实体类来表示数据库中表与表之间的关系(一对多、一对一、多对多,在实体类中定义另一个实体类的对象),以一对多(两个实体类之间的表达该关系有些许差异)举例

//实体类中表示一对多的关系,一个员工从属于一个部门,一个部门下有多个员工//部门类publicclassDept{privateInteger deptno;//部门编号privateString dname;//部门名称privateString loc;//所在城市privateList<Emp> empList;//定义集合,一个部门下有多个员工,一对多}//员工类publicclassEmp{privateInteger empno;//员工编号privateString ename;//员工姓名privateString job;//职位privatedouble sal;//工资privatedouble comm;//奖金privateInteger deptno;//部门编号//属于某个部门privateDept dept;}

自定义返回类型

多表查询中,其返回结果“类中有类”,因此需要自定义返回类型,本质就是自定义属性匹配规则!!

  • 一对多 :查询所有员工的员工信息以及对应的部门信息
    在映射文件中自定义返回值类型
<!-- 自定义返回值类型  --><resultMapid="EmpDeptResultMap"type="Emp"><!-- id为返回值的类型名,type为“类中有类”的“外类”名 --><idproperty="empno"column="empno"></id><!--  property为类中的属性名,column为对应数据库中的列名 --><resultproperty="ename"column="ename"></result><resultproperty="job"column="job"></result><resultproperty="sal"column="sal"></result><resultproperty="comm"column="comm"></result><resultproperty="deptno"column="deptno"></result><associationproperty="dept"javaType="Dept"><idproperty="deptno"column="deptno"></id><resultproperty="dname"column="dname"></result><resultproperty="loc"column="loc"></result></association></resultMap><!-- 一次性查询 --><selectid="allEmpDept"resultMap="EmpDeptResultMap"><!-- 返回值为自定义类型 -->
       select * from emp left join dept on emp.deptno=dept.deptno</select>
  • 多对一:查询所有部门信息以及每个部门下对应的员工信息
<!-- 自定义返回值类型 --><resultMapid="DeptEmpResultMap"type="Dept"><idproperty="deptno"column="deptno"></id><resultproperty="dname"column="dname"></result><resultproperty="loc"column="loc"></result><collectionproperty="empList"ofType="Emp"><!-- 这里对应的是一个list集合 --><idproperty="empno"column="empno"></id><resultproperty="ename"column="ename"></result><resultproperty="job"column="job"></result><resultproperty="sal"column="sal"></result><resultproperty="comm"column="comm"></result><resultproperty="deptno"column="deptno"></result></collection></resultMap><selectid="allDeptEmp"resultMap="DeptEmpResultMap">
       select * from dept left join emp on emp.deptno=dept.deptno</select>

分步查询

  • 日志输出
    可在主配置文件中添加以下配置,用于日志输出,观察SQL语句的执行情况
<!-- 日志输出 --><settings><settingname="logImpl"value="STDOUT_LOGGING"/></settings>
  • 一对多:查询所有员工的员工信息以及对应的部门信息(step1-查询员工信息、step2-根据员工信息中的部门编号查询对应的部门信息)

step1: 修改association标签,增加select、colum属性,select的值为SQL语句所在的映射文件的方法名,colum为传递参数,可理解为“外键”值,这里为部门编号

<!-- 分步查询 --><resultMapid="EmpDeptResultMap"type="Emp"><idproperty="empno"column="empno"></id><resultproperty="ename"column="ename"></result><resultproperty="job"column="job"></result><resultproperty="sal"column="sal"></result><resultproperty="comm"column="comm"></result><resultproperty="deptno"column="deptno"></result><associationproperty="dept"javaType="Dept"select="com.system.mapper.DeptMapper.getDeptByDeptno"column="deptno"></association></resultMap><selectid="allEmpDept"resultMap="EmpDeptResultMap">
       select * from emp</select>

step2: 在部门的映射文件中定义根据部门编号查询部门信息的方法,注意不可以用注解的方式实现!!

<selectid="getDeptByDeptno"resultType="Dept"parameterType="Integer">
      select * from dept where deptno = #{deptno}</select>
  • 多对一:查询所有部门信息以及每个部门下对应的员工信息(step1-查询部门信息、step2-根据部门信息中的部门编号查询对应的员工信息)

step1: 修改collection标签,也是增加select、colum属性,意义与上同

<!-- 分步查询 --><resultMapid="DeptEmpResultMap"type="Dept"><idproperty="deptno"column="deptno"></id><resultproperty="dname"column="dname"></result><resultproperty="loc"column="loc"></result><collectionproperty="empList"ofType="Emp"select="com.system.mapper.EmpMapper.empByDeptno"column="deptno"fetchType="eager"></collection></resultMap><!-- fetchType属性可以设置该步查询是否使用延时加载,eager为不使用延时加载 lazy为使用 --><selectid="allDeptEmp"resultMap="DeptEmpResultMap">
        select * from dept</select>

step2: 在员工的映射文件下定义根据部门编号查询员工信息的方法

<selectid="empByDeptno"resultType="Emp"parameterType="Integer">
    select * from emp where deptno=#{deptno}</select>

colum属性传入多参数

  • 在< collection >标签中的colum属性,可以传递多个参数,格式如下所示
  • = 的左边为实体类映射的属性名,= 的右边为数据库列字段名
  • 注意:在empByDeptno方法中,parameterType属性一定要" parameterType=“java.util.Map” ",否则无法传递多个参数,会报错
<resultMapid="DeptEmpResultMap"type="Dept"><idproperty="deptno"column="deptno"></id><resultproperty="dname"column="dname"></result><resultproperty="loc"column="loc"></result><!-- column="{属性名=数据库列名,属性名=数据库列名,...}" --><collectionproperty="empList"ofType="Emp"select="com.system.mapper.EmpMapper.empByDeptno"column="deptno"></collection></resultMap>

延时加载

延时加载是分步查询的一种“显示策略”

  • 作者:EnjoyFailure
  • 原文链接:https://blog.csdn.net/S_5922/article/details/125397963
    更新时间:2022-08-14 13:56:42