Spring 学习小记(九)

67 篇文章 0 订阅
MyBatis映射文件
 
    本小记学习目标
        1.MyBatis的核心配置文件(全局配置文件)的介绍
        2.掌握MyBatis的SQL映射文件(重点掌握)
        3.掌握MyBatis的级联查询实现方法
 
一、MyBatis核心配置文件
    MyBatis核心配置文件,配置了很多影响MyBatis行为的信息,这些信息通常来说也只会配置在一个文件中,并且一般是不会去轻易改变的,当它与Spring整合后,这些配置信息会配置到Spring的配置文件中,在实际的开发过程中需要去编写或修改这个配置文件的情况不多。
MyBatis核心配置文件的模板如下:
<? 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 >
       <!-- 属性 -->
       < properties />
       <!-- 设置 -->
       < settings >
             < setting name= "" value= "" />
       </ settings >
       <!-- 类型命名(别名) -->
       < typeAliases />
       <!-- 类型处理器 -->
       < typeHandlers />
       <!-- 对象工厂 -->
       < objectFactory type= "" />
       <!-- 插件 -->
       < plugins >
             < plugin interceptor= "" ></ plugin >
       </ plugins >
       <!-- 配置环境 -->
       < environments default= "" >
             <!-- 环境变量 -->
             < environment id= "" >
                   <!-- 事务管理器 -->
                   < transactionManager type= "" />
                   <!-- 数据源 -->
                   < dataSource type= "" />
             </ environment >
       </ environments >
       <!-- 数据库厂商标识 -->
       < databaseIdProvider type= "" />
       <!-- 映射器,通知MyBatis去哪里去找映射文件 -->
       < mappers >
             < mapper resource= "com/XXX/XXX/XXXMapper.xml" />
       </ mappers >
</ configuration >
 
二、MyBatis映射文件
MyBatis映射器介绍
    映射器,它是MyBatis中最为重要的组件,它是由接口加上Xml文件(sql映射文件)组成。MyBatis也可以由注解来完成,但是一般来说不常用注解做Sql映射
Sql映射文件的常用配置元素有如下一些:
    select        查询语句    可以自定义参数、返回结果集……
    insert        插入语句    执行后返回一个整数,表示插入的记录行数
    update        更新语句    执行后返回一个整数,表示更新的记录行数
    delete        删除语句    执行后返回一个整数,表示删除的记录行数
    sql           定义一部分sql
    resultMap     用来描述由数据库结果集来加载对象
 
select元素
<select>元素用来映射SQL的select语句。例如:
<!-- 根据id查询一条记录 -->
< select id= "selectStudentById" parameterType= "Integer" resultType= "com.xiaoxie.pojo.Student" >
    select id,name,age from student where 1=1 and id=#{id}
</ select >
在上面的配置中parameterType指定为Integer,表明参数是一个Integer类型
resultType指定为com.xiaoxie.pojo.Student,表明返回的是一个Student类的对象
sql语句中#{id},表示传入的参数是id属性的值
select元素的常用属性
id:它与Mapper的命名空间组合使用,是一个唯一的标识符,供MyBatis调用
parameterType:它表示传入sql语句的参数类型的全限定名或别名。它是一个可选属性,MyBatis可以推断出具体传入语句的参数
resultType:指定返回的类型(全限定名或别名)如果是集合类型,返回的是集合元素的类型,返回时可以使用resultType或resultMap之一
resultMap:它是映射集的引用,与<resultMap元素一起使用>,返回时可以使用reusltType或resultMap之一
flushCache:用于设置在调用sql语句后时否要求MyBatis清空之前查询的本地缓存和二级缓存,默认是false
useCache:启动二级缓存开关,默认是true
timeout:设置超时时间,单位是秒,如果超时则会抛出异常
fetchSize:获取记录的总条数设定
statementType:告诉MyBatis使用哪个JDBC的Statement工作,可取值:STATEMENT(Statement)、PREPARED(PreparedStatement)、CALLABLE(CallbleStatement)
resutlSetType:针对JDBC的ResultSet接口而言,它的值可以设置为FORWARD_ONLY(只可以向前访问)、SCROLL_SENSITIVE(双向滚动,但不及时更新)、SCROLL_INSENSITIVE(双向滚动,及时更新)
关于多个参数传递的问题
方式一:使用Map做为参数传递
在实际的应用开发过程中,查询sql语句通常需要多个查询参数(多个条件),这个时候可以在parameterType属性中指定为map
在Mapper中做如下查询定义
<!-- 测试多参数传递 -->
< select id= "selectStudentByNameAndAge" resultType= "com.xiaoxie.pojo.Student" parameterType= "map" >
        select id,name,age from student
        where 1=1
        and name=#{name}
        and age=#{age}
</ select >
这里可以看到parameterType指定的为map
在对应的Dao接口中对以上标识定义接口方法与之对应
//测试多参数查询,条件:姓名、年龄
List<Student> selectStudentByNameAndAge(Map<String,Object> param);
在测试类中新增如下方法进行测试
System. out.println( "测试多条件参数:");
//Map条件
Map<String,Object> param = new HashMap<>();
param.put( "name", "张飞");
param.put( "age",26);
StudentDao dao = (StudentDao) context.getBean( "studentDao");
List<Student> stu = dao.selectStudentByNameAndAge( param);
for (Student student : stu) {
     System. out.println( student);
}
从上面我们可以看到我们定义了一个map,map的key对应的就是查询语句中的参数名称
方式二:使用Java Bean来传递参数
对于参数复杂的情况下我们使用Map的方式传递参数是比较复杂的需要对参数进行初始化
使用JavaBean作为参数则是专门为参数建立一个JavaBean的类
在com.xiaoxie.dao.param包下建立一个基础的参数pojo类
package com.xiaoxie.dao.param;
public class StudnetNameAndAgeParam {
       private String name;
       private Integer age;
      
       public String getName() {
             return name;
      }
       public void setName(String name) {
             this. name = name;
      }
       public Integer getAge() {
             return age;
      }
       public void setAge(Integer age) {
             this. age = age;
      }
      
}
在Mapper中做如下定义
<!-- 测试多参数的传递,这里使用JavaBean的方式传入多个参数 -->
< select id= "selectStudentByNameAndAgeUseJavaBean" resultType= "com.xiaoxie.pojo.Student" parameterType= "com.xiaoxie.dao.param.StudnetNameAndAgeParam" >
     select id,name,age from student
      where 1=1
      and name=#{name}
      and age=#{age}
 </ select >
在dao接口中定时对应的接口方法
//测试多参数查询,条件:姓名、年龄,作用JavaBean
List<Student> selectStudentByNameAndAgeUseJavaBean(StudnetNameAndAgeParam param);
在测试类的main方法中做如下测试可以把建立的JavaBean对象作为参数传递进去
System. out.println( "使用JavaBean作为参数传递");
StudnetNameAndAgeParam beanParam = new StudnetNameAndAgeParam();
beanParam.setName( "刘备");
beanParam.setAge(30);
stu = dao.selectStudentByNameAndAgeUseJavaBean( beanParam);
for (Student student : stu) {
    System. out.println( student);
}
对于多参数的传递方式是使用Map还是使用JavaBean,这个可以根据实际的情况灵活确定,如果觉得参数过多则可以选择JavaBean这种方式
 
insert元素
<insert>元素用于映射插入语句,在MyBatis插入完成后会返回一个整数表示它执行影响的行数。它的属性与select元素的不只属性大部分都是一样的,有如下几个特有的属性
keyProperty:这个属性是把插入或更新操作时返回值赋给po类的某个属性上,通常来说会设置为主键对应的属性,如果是联合主键,可以用逗号把多个值隔开
keyColumn:这个属性是用来设置第几例为主键,当主键不是第一列的时候是需要设置的,如果是联合主键则可以使用多个值用逗号隔开
useGeneratedKeys:这个属性是MyBatis使用JDBC的getGeneratedKeys()方法获取数据库内部产生的主键,默认值是false
对于mysql、sqlServer数据库一般会采用自动递增值作为主键,在insert数据完成后,有时是需要刚和新增数据的主键值的,这个时候则可以在mapper中对于insert元素添加keyProperty和useGeneratedKeys属性
 
自动回填主键
在mapper中定义insert元素如下
<!-- 添加一条记录 -->
< insert id= "addStudent" parameterType= "com.xiaoxie.pojo.Student" keyProperty= "id" useGeneratedKeys= "true" >
    insert into student(name,age) values(#{name},#{age})
</ insert >
这里表示主键值是id属性
通过如下方式新增记录
Student stu1 = new Student( "刘备",30);
int rows = studentDao.addStudent( stu1);
System. out.println( "===============添加"+ rows + "条记录==============");
System. out.println( "新增记录的主键为:" + stu1.getId());
那么新增记录的主键会回写到stu1的id属性上
 
自主设定主键
有些数据库是不支持自增主键的这个时候则需要自主去设置主键,这个时候可以使用<selectKey>元素来实现
在Mapper中需要做如下定义
< insert id= "addStudent" parameterType= "com.xiaoxie.pojo.Student" >
     < selectKey keyProperty= "id" resultType= "Integer" order= "BEFORE" >
        select if(max(id) is null,1,max(id)+1) as mid from student
     </ selectKey >
        insert into student(id,name,age) values(#{id},#{name},#{age})
</ insert >
注:一般对于mySql这样的数据库是不可以这样操作的,因为原表的数据可能会被删除记录,这个时候max出来的主键是不正确的,非要使用则需要使用额外表来做记录主键当前的递增值
<selectKey>元素中的keyProperty属性表表示查询到的返回给到Po类的哪个属性,order表示在什么时机执行(可选值:BEFORE、AFTER)这里的之前和之后是相对于执行insert语句来说的。
 
update元素和delete元素
它们分别对应的是sql语句中的update和delete,其属性与insert、select属性差不多,它在执行后也会返回一个整数,表示影响到了数据库多少行记录
mapper中的定义可以为如下
<!-- 修改一条记录 -->
< update id= "updateStudentById" parameterType= "com.xiaoxie.pojo.Student" >
     update student set name=#{name},age=#{age} where 1=1 and id=#{id}
</ update >
<!-- 删除一条记录 -->
< delete id= "deleteStudentById" parameterType= "Integer" >
     delete from student where id=#{id}
</ delete >
 
sql元素
这个元素主要是用来自定义sql代码片段,这些sql片段可以在后续的配置中进行引用
如下示例:可以把需要使用到的列名用sql元素进行定义,在后续需要使用的地方进行引用即可
<!-- 使用 sql 标签自定义部分 sql 语句供其他配置中引用 -->
< sql id= "studentColumns" > id,name,age </ sql >
< select id= "selectStudentByColumns" resultType= "com.xiaoxie.pojo.Student" >
    select < include refid= "studentColumns" /> from student
</ select >
 
resultMap元素
它是MyBatis中最为重要的元素,主要用来定义映射规则、级联的更新以及定义类型转化器……
<resultMap>元素的结构说明:
<resultMap type="" id="">
    <constructor>    <!-- 类在实例化的时候用来注入结果到构造方法 -->
        <idArg/>    <!-- ID参数,结果为ID -->
        <arg/>    <!-- 注入到构造方法的一个普通结果 -->
    </constructor>
    <id/>    <!-- 用来表示哪个列是主键 -->
    <result/>    <!-- 注入到字段或JavaBean属性的普通结果 -->
    <association property=""/>    <!-- 用于一对一关联 -->
    <collection property=""/>    <!-- 用于一对多、多对多关联 -->
    <discriminator javaType="">    <!-- 使用结果值来决定使用哪个结果映射 -->
        <case value=""/>    <!-- 基于某些值的结果映射 -->
    </discriminator>
</resultMap>
简单说明:
resultMap的type属性表示需要的pojo,id属性则表示resultMap的唯一值
子元素<constructor>用来配置构造方法(在POJO中没有定义无参构造时使用)
子元素<id>表示哪个列为主键
子元素<result>表示POJO和数据表普通列的映射关系
子元素<association>、<collection>、<discriminator>用在级联的情况
 
使用Map来存储结果集
指的是在配置select元素时,指定resultType="map"
在Mapper中可以做如下定义
<!-- 使用Map来存储结果集 -->
< select id= "selectStudentUseMap" resultType= "map" >
     select * from student
</ select >
在Dao接口中新增对应的接口方法
//使用Map来存储查询的结果集
List<Map<String,Object>> selectStudentUseMap();
在测试类中新增如下代码进行测试
System. out.println( "使用Map来存储查询返回的结果集");
List<Map<String, Object>> studentMap  = dao.selectStudentUseMap();
Set<Map.Entry<String, Object>> entrySet = null;
for (Map<String, Object> map : studentMap) {
//遍历map
entrySet = map.entrySet();
for (Map.Entry<String, Object> entry : entrySet) {
    System. out.println( entry.getKey() + ":" + entry.getValue());
}
 System. out.println( "------------");
}
这里我们通过测试的结果可以看到,当使用map做结果集的存储时,map中的key为字段名,value则是查询结果返回的对应字段的值,使用这种方式对于少量的记录(比如一条记录)很方便,但是可读性并不高。
 
使用POJO存储结果集
使用POJO进行结果集的存储有两个方面是比较好的
第一,可以使用resultType属性
第二,当有复杂的映射或级联,这个时候可以使用select元素的resultMap属性配置映射集合
在mapper中配置resultMap元素
<!-- resultMap元素进行映射 -->
       < resultMap type= "com.xiaoxie.pojo.Student" id= "studentResult" >
             < id property= "id" column= "id" /> <!-- 指定主键 -->
             < result property= "name" column= "name" />
             < result property= "age" column= "age" />
       </ resultMap >
      
       < select id= "selectStudentUseResultMap" resultMap= "studentResult" >
            select * from student
       </ select >
在Dao接口中新增对应的接口方法
//使用resultMap进行结果集的映射
      List<Student> selectStudentUseResultMap();
在测试类中新增如下代码进行测试
System. out.println( "使用resultMap进行结果集的映射");
     List<Student> resultMap = dao.selectStudentUseResultMap();
      for (Student student : resultMap) {
         System. out.println( student);
     }
 
级联查询
级联查询,它有三种:一对一级联,一对多级联,多对多级联
优点:可以方便地获取关联数据
缺点:过多的级联会增加数据库系统的复杂性,同时影响系统的性能
实际开发过程中需要根据实际的情况做取舍,一般不建议做数据库级别的级联,关联的关系放在程序逻辑中即可
何为级联查询?
当有一个表A,它其中有一个字段做外键引用了表B的主键,这个时候通过表A的外键把表B对应的记录查询出来,这个就是级联查询
 
一对一级联查询
MyBatis中对于一对一级联查询的处理方式是,通过<resultMap>元素的子元素<association>元素处理,在这个子元素中通常使用以下属性
property:指定映射到实体类的对象属性
column:指定表中对应的字段
javaType:指定映射到实体对象属性的类型
select:指定引入嵌套查询的子sql语句
 
在数据库中建立如下两张表
-- 身份证表
create table idcard(
    id BIGINT(19) NOT NULL auto_increment COMMENT '主键ID',
    code varchar(18) NOT NULL DEFAULT '' COMMENT '身份证号码',
    PRIMARY key(id)
);
 
-- 身份信息表
CREATE TABLE `person` (
  `id` bigint(19) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `name` varchar(20) DEFAULT '' COMMENT '姓名',
  `age` int(11) NOT NULL DEFAULT '0' COMMENT '年龄',
  `address` varchar(512) DEFAULT '' COMMENT '常住地址',
  `idcard_id` bigint(19) DEFAULT NULL COMMENT 'idcard表的id',
  PRIMARY KEY (`id`),
  KEY `idcard` (`idcard_id`),
  CONSTRAINT `idcard` FOREIGN KEY (`idcard_id`) REFERENCES `idcard` (`id`)
);
 
新增POJO实体类:IdCard,Person
IdCard:
package com.xiaoxie.pojo;
public class IdCard {
       private Integer id;
       private String code;
      
       /*Setter与Getter*/
       public Integer getId() {
             return id;
      }
       public void setId(Integer id) {
             this. id = id;
      }
       public String getCode() {
             return code;
      }
       public void setCode(String code) {
             this. code = code;
      }
      
       @Override
       public String toString() {
             return "idCard[id=+"+ id+ ",code="+ code+ "]";
      }
}
Person:
package com.xiaoxie.pojo;
public class Person {
       private Integer id;
       private String name;
       private Integer age;
       private String address;
       private IdCard idcard;   //身份证信息
      
      
       public Integer getId() {
             return id;
      }
       public void setId(Integer id) {
             this. id = id;
      }
       public String getName() {
             return name;
      }
       public void setName(String name) {
             this. name = name;
      }
       public Integer getAge() {
             return age;
      }
       public void setAge(Integer age) {
             this. age = age;
      }
       public String getAddress() {
             return address;
      }
       public void setAddress(String address) {
             this. address = address;
      }
       public IdCard getIdcard() {
             return idcard;
      }
       public void setIdcard(IdCard idcard) {
             this. idcard = idcard;
      }
      
       @Override
       public String toString() {
             return "Person[id=+"+ id+ ",name="+ name+ ",age="+ age+ ",address="+ address+ ",idcard="+ idcard+ "]";
      }
}
 
新增Mapper映射文件
IdCardMapper:
<? xml version= "1.0" encoding= "UTF-8" ?>
<! DOCTYPE mapper
  PUBLIC "-// mybatis.org//DTD Mapper 3.0//EN"
  < mapper namespace= "com.xiaoxie.dao.IdCardDao" >
       < select id= "selectIdCardById" parameterType= "Integer" resultType= "com.xiaoxie.pojo.IdCard" >
            select * from idcard where id = #{id}
       </ select >
  </ mapper >
 
PersonMapper:
<? xml version= "1.0" encoding= "UTF-8" ?>
<! DOCTYPE mapper
  PUBLIC "-// mybatis.org//DTD Mapper 3.0//EN"
  < mapper namespace= "com.xiaoxie.dao.PersonDao" >
       <!-- 一对一级联,执行两个 sql 进行查询 -->
       < resultMap type= "com.xiaoxie.pojo.Person" id= "idCardAdnPerson_1" >
             < id property= "id" column= "id" />      <!-- 指定ID主键列 -->
             <!-- 普通列的映射关系 -->
             < result property= "name" column= "name" />
             < result property= "age" column= "age" />
             < result property= "address" column= "address" />
             <!-- 一对一的级联查询 -->
             < association property= "idcard" column= "idcard_id" javaType= "com.xiaoxie.pojo.IdCard" select= "com.xiaoxie.dao.IdCardDao.selectIdCardById" />
       </ resultMap >
       < select id= "selectPersonById_1" parameterType= "Integer" resultMap= "idCardAdnPerson_1" >
            select * from person where id=#{id}
       </ select >
      
       <!-- 一对一级联,执行一个 sql 语句 -->
       < resultMap type= "com.xiaoxie.pojo.Person" id= "idCardAdnPerson_2" >
             < id property= "id" column= "id" />      <!-- 指定主键列 -->
             <!-- 普通列的映射关系 -->
             < result property= "name" column= "name" />
             < result property= "age" column= "age" />
             < result property= "address" column= "address" />
             <!-- 一对一的级联查询 -->
             < association property= "idcard" javaType= "com.xiaoxie.pojo.IdCard" >
                   < id property= "id" column= "idcard_id" />
                   < result property= "code" column= "code" />
             </ association >
       </ resultMap >
       < select id= "selectPersonById_2" parameterType= "Integer" resultMap= "idCardAdnPerson_2" >
            select p.*,c.code from person p left join idcard c on p.idcard_id = c.id
            where p.id=#{id}
       </ select >
      
       <!-- 一对一级联,根据id查询个人信息,连接查询(使用 pojo 存储查询结结果) -->
       < select id= "selectPersonById_3" parameterType= "Integer" resultType= "com.xiaoxie.dao.result.IdCardAdnPerson" >
            select p.*,c.code from person p left join idcard c on p.idcard_id = c.id
            where p.id=#{id}
       </ select >
  </ mapper >
 
对应新增Dao接口
idCardDao:
package com.xiaoxie.dao;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import com.xiaoxie.pojo.IdCard;
@Repository( "idCardDao")
@Mapper
public interface IdCardDao {
      IdCard selectIdCardById(Integer id);
}
 
PersonDao:
package com.xiaoxie.dao;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import com.xiaoxie.dao.result.IdCardAdnPerson;
import com.xiaoxie.pojo.Person;
@Repository( "personDao")
@Mapper
public interface PersonDao {
      Person selectPersonById_1(Integer id);
      Person selectPersonById_2(Integer id);
      IdCardAdnPerson selectPersonById_3(Integer id);
}
 
新增实体类来保存MyBatis查询返回的结果
IdCardAdnPerson:
package com.xiaoxie.dao.result;
public class IdCardAdnPerson {
       private Integer id;
       private String name;
       private Integer age;
       private String address;
       private String code;
       public Integer getId() {
             return id;
      }
       public void setId(Integer id) {
             this. id = id;
      }
       public String getName() {
             return name;
      }
       public void setName(String name) {
             this. name = name;
      }
       public Integer getAge() {
             return age;
      }
       public void setAge(Integer age) {
             this. age = age;
      }
       public String getAddress() {
             return address;
      }
       public void setAddress(String address) {
             this. address = address;
      }
       public String getCode() {
             return code;
      }
       public void setCode(String code) {
             this. code = code;
      }
      
       @Override
       public String toString() {
             return "IdCardAdnPerson[id=+"+ id+ ",name="+ name+ ",age="+ age+ ",address="+ address+ ",code="+ code+ "]";
      }
}
 
在MyBatis的核心配置文件中把Mapper的映射添加进去
<? 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 >
       <!-- 在MyBatis进行嵌套查询时,使用延迟加载可以提高一定的性能所以在这里可把把这个配置打开 -->
       < settings >
             <!-- 延迟加载 -->  
             < setting name= "lazyLoadingEnabled" value= "true" />
             <!-- 按需加载 -->
             < setting name= "aggressiveLazyLoading" value= "false" />
       </ settings >
      
       <!-- 查找映射文件 -->
       < mappers >
             < mapper resource= "com/xiaoxie/dao/mybatis/StudentMapper.xml" />
             < mapper resource= "com/xiaoxie/dao/mybatis/IdCardMapper.xml" />
             < mapper resource= "com/xiaoxie/dao/mybatis/PersonMapper.xml" />
       </ mappers >
      
</ configuration >
 
新增Controller类
package com.xiaoxie.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import com.xiaoxie.dao.PersonDao;
import com.xiaoxie.dao.result.IdCardAdnPerson;
import com.xiaoxie.pojo.Person;
@Transactional
@Controller( "personController1")
public class PersonController1 {
       @Autowired
       private PersonDao personDao;
      
       public void test() {
            Person P1 = personDao.selectPersonById_1(1);
            System. out.println( P1);
            System. out.println( "----------------------");
            Person p2 = personDao.selectPersonById_2(1);
            System. out.println( p2);
            System. out.println( "-----------------------");
            IdCardAdnPerson p3 = personDao.selectPersonById_3(1);
            System. out.println( p3);
      }
}
 
在测试类中调用
ApplicationContext context = new ClassPathXmlApplicationContext( "spring-config.xml");
PersonController1 personController1 = (PersonController1) context.getBean( "personController1");
personController1.test();
注意:上述的例子中使用了数据库的外键使用数据库的两个表有了级联关系,实际上在数据库中没有这种强制的级联关系,只要逻辑上是这样的也是可以使用上面的这种方式做级联查询的(实际应用中应该这种方式是更常见的,实际上这样设计会更合理些)
 
一对多级联查询
一对多级联是指的一个实体表A的记录对应关联实体表B中的多条记录,比如一个用户购物时会产生多个订单,那么用户与订单是一对多的关系。
 
新增两个数据库表
-- user表
CREATE TABLE `user` (
  `id` bigint(19) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `user_code` varchar(50) NOT NULL DEFAULT '' COMMENT '用户编码',
  `user_name` varchar(50) NOT NULL DEFAULT '' COMMENT '用户名称',
  PRIMARY KEY (`id`)
)
-- order表
CREATE TABLE `order` (
  `id` bigint(19) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `order_no` varchar(25) NOT NULL DEFAULT '' COMMENT '订单编号',
  `user_code` varchar(50) NOT NULL DEFAULT '' COMMENT '用户编码',
  PRIMARY KEY (`id`)
)
 
新增POJO实体类
Order:
package com.xiaoxie.pojo;
public class Order {
       private Integer id;
       private String order_no;
       private String user_code;
      
      
       public Integer getId() {
             return id;
      }
       public void setId(Integer id) {
             this. id = id;
      }
       public String getOrder_no() {
             return order_no;
      }
       public void setOrder_no(String order_no) {
             this. order_no = order_no;
      }
       public String getUser_code() {
             return user_code;
      }
       public void setUser_code(String user_code) {
             this. user_code = user_code;
      }
      
       @Override
       public String toString() {
             return "Order[id=+"+ id+ ",order_no="+ order_no+ ",user_code="+ user_code+ "]";
      }
}
 
User:
package com.xiaoxie.pojo;
import java.util.List;
public class User {
       private Integer id;
       private String user_code;
       private String user_name;
       private List<Order> orders;
      
       public Integer getId() {
             return id;
      }
       public void setId(Integer id) {
             this. id = id;
      }
       public String getUser_code() {
             return user_code;
      }
       public void setUser_code(String user_code) {
             this. user_code = user_code;
      }
       public String getUser_name() {
             return user_name;
      }
       public void setUser_name(String user_name) {
             this. user_name = user_name;
      }
       public List<Order> getOrders() {
             return orders;
      }
       public void setOrders(List<Order> orders) {
             this. orders = orders;
      }
       @Override
       public String toString() {
             return "User[id=+"+ id+ ",user_code="+ user_code+ ",user_name="+ user_name+ ",orders:"+ orders+ "]";
      }
      
}
 
新增Mapper映射文件
OrderMapper.xml:
<? xml version= "1.0" encoding= "UTF-8" ?>
<! DOCTYPE mapper
  PUBLIC "-// mybatis.org//DTD Mapper 3.0//EN"
  < mapper namespace= "com.xiaoxie.dao.OrderDao" >
       < select id= "selectOrderByUserCode" parameterType= "String" resultType= "com.xiaoxie.pojo.Order" >
            select * from `order` where user_code = #{user_code}
       </ select >
  </ mapper >
 
UserMapper:
<? xml version= "1.0" encoding= "UTF-8" ?>
<! DOCTYPE mapper
  PUBLIC "-// mybatis.org//DTD Mapper 3.0//EN"
  < mapper namespace= "com.xiaoxie.dao.UserDao" >
       < resultMap type= "com.xiaoxie.pojo.User" id= "userAndOrders_1" >
             < id property= "id" column= "id" />
             < result property= "user_code" column= "user_code" />
             < result property= "user_name" column= "user_name" />
             <!-- 一对多的级联,这里面ofType表示集合的元素类型,把user_code作为参数传入(嵌套查询) -->
             < collection property= "orders" ofType= "com.xiaoxie.pojo.Order" column= "user_code" select= "com.xiaoxie.dao.OrderDao.selectOrderByUserCode" />
       </ resultMap >
       < select id= "selectUserOrdersById_1" parameterType= "Integer" resultMap= "userAndOrders_1" >
            select * from user where id=#{id}
       </ select >
      
       <!-- 一对多的级联,一个查询嵌套结果 -->
       < resultMap type= "com.xiaoxie.pojo.User" id= "userAndOrders_2" >
             < id property= "id" column= "id" />
             < result property= "user_code" column= "user_code" />
             < result property= "user_name" column= "user_code" />
             < collection property= "orders" ofType= "com.xiaoxie.pojo.Order" >
                   < id property= "id" column= "id" />
                   < result property= "order_no" column= "order_no" />
             </ collection >
       </ resultMap >
       < select id= "selectUserOrdersById_2" parameterType= "Integer" resultMap= "userAndOrders_2" >
            select u.*,o.id,o.order_no,o.user_code from user u left join `order` o on u.user_code = o.user_code
            where u.id = #{id}
       </ select >
      
       <!-- 一对多级联,使用 pojo 类存储结果 -->
       < select id= "selectUserOrdersById_3" parameterType= "Integer" resultType= "com.xiaoxie.dao.result.UserAndOrders" >
            select u.*,o.order_no from user u left join `order` o on u.user_code = o.user_code
            where u.id = #{id}
       </ select >
  </ mapper >
 
新增对应的Dao接口
OrderDao:
package com.xiaoxie.dao;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import com.xiaoxie.pojo.Order;
@Repository( "orderDao")
@Mapper
public interface OrderDao {
      List<Order> selectOrderByUserCode(String user_code);
}
 
UserDao:
package com.xiaoxie.dao;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import com.xiaoxie.dao.result.UserAndOrders;
import com.xiaoxie.pojo.User;
@Mapper
@Repository( "userDao")
public interface UserDao {
      User selectUserOrdersById_1(Integer id);
      
      User selectUserOrdersById_2(Integer id);
      
      List<UserAndOrders> selectUserOrdersById_3(Integer id);
}
 
新增实体类来保存MyBatis返回的结果
UserAndOrders:
package com.xiaoxie.dao.result;
public class UserAndOrders {
       private Integer id;
       private String user_code;
       private String user_name;
       private String order_no;
       public Integer getId() {
             return id;
      }
       public void setId(Integer id) {
             this. id = id;
      }
       public String getUser_code() {
             return user_code;
      }
       public void setUser_code(String user_code) {
             this. user_code = user_code;
      }
       public String getUser_name() {
             return user_name;
      }
       public void setUser_name(String user_name) {
             this. user_name = user_name;
      }
       public String getOrder_no() {
             return order_no;
      }
       public void setOrder_no(String order_no) {
             this. order_no = order_no;
      }
      
       @Override
       public String toString() {
             return "UserOrders[id=+"+ id+ ",user_code="+ user_code+ ",user_name="+ user_name+ ",order_no:"+ order_no+ "]";
      }
}
 
在MyBatis的核心配置文件中添加对这两个Mapper映射文件的扫描
<? 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 >
       <!-- 在MyBatis进行嵌套查询时,使用延迟加载可以提高一定的性能所以在这里可把把这个配置打开 -->
       < settings >
             <!-- 延迟加载 -->  
             < setting name= "lazyLoadingEnabled" value= "true" />
             <!-- 按需加载 -->
             < setting name= "aggressiveLazyLoading" value= "false" />
       </ settings >
      
       <!-- 查找映射文件 -->
       < mappers >
             < mapper resource= "com/xiaoxie/dao/mybatis/StudentMapper.xml" />
             < mapper resource= "com/xiaoxie/dao/mybatis/IdCardMapper.xml" />
             < mapper resource= "com/xiaoxie/dao/mybatis/PersonMapper.xml" />
             < mapper resource= "com/xiaoxie/dao/mybatis/OrderMapper.xml" />
             < mapper resource= "com/xiaoxie/dao/mybatis/UserMapper.xml" />
       </ mappers >
      
</ configuration >
 
新增Controller类
UserOrderController:
package com.xiaoxie.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import com.xiaoxie.dao.UserDao;
import com.xiaoxie.dao.result.UserAndOrders;
import com.xiaoxie.pojo.User;
@Controller( "userOrderController")
@Transactional
public class UserOrderController {
       @ Autowired
       private UserDao userDao;
      
       public void test() {
            User userOrders1 = userDao.selectUserOrdersById_1(1);
            System. out.println( userOrders1);
            System. out.println( "-------------------------------");
            User userOrder2 = userDao.selectUserOrdersById_2(1);
            System. out.println( "-------------------------------");
            List<UserAndOrders> userOrder3 = userDao.selectUserOrdersById_3(1);
            System. out.println( userOrder3);
      }
}
 
在测试类中进行测试:
ApplicationContext context = new ClassPathXmlApplicationContext( "spring-config.xml");
UserOrderController userOrderController = (UserOrderController) context.getBean( "userOrderController");
userOrderController.test();
 
多对多级联查询
MyBatis是没有对多对多的级联实现的,因为多对多级联是可以通过两个一对多的级联来实现的。
如我们的订单表与订单商品表一般就是多对多的关系,一个订单A、订单B可以有商品A、商品B
我们再向数据库新增两个表
-- order_detail表
CREATE TABLE `order_detail` (
  `id` bigint(19) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `order_no` varchar(25) NOT NULL DEFAULT '' COMMENT '订单编号',
  `goods_no` varchar(50) NOT NULL DEFAULT '' COMMENT '商品编码',
  PRIMARY KEY (`id`)
);
-- goods表
CREATE TABLE `goods` (
  `id` bigint(19) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `goods_no` varchar(50) NOT NULL DEFAULT '' COMMENT '商品编码',
  PRIMARY KEY (`id`)
);
 
新增POJO实体类
Goods
package com.xiaoxie.pojo;
import java.util.List;
public class Goods {
       private Integer id;
       private String goods_no;
      
       //商品对应订单是一个对多的关系
       private List<Order> orders;
      
      
       public Integer getId() {
             return id;
      }
       public void setId(Integer id) {
             this. id = id;
      }
       public String getGoods_no() {
             return goods_no;
      }
       public void setGoods_no(String goods_no) {
             this. goods_no = goods_no;
      }
      
      
       public List<Order> getOrders() {
             return orders;
      }
       public void setOrders(List<Order> orders) {
             this. orders = orders;
      }
       @Override
       public String toString() {
             return "Goods[id="+ id+ ",goods_no="+ goods_no+ ",orders="+ orders+ "]";
      }
}
 
修改Order实体类把对goods的一对多关系加入进去
package com.xiaoxie.pojo;
import java.util.List;
public class Order {
       private Integer id;
       private String order_no;
       private String user_code;
      
       private List<Goods> goods;
      
       public Integer getId() {
             return id;
      }
       public void setId(Integer id) {
             this. id = id;
      }
       public String getOrder_no() {
             return order_no;
      }
       public void setOrder_no(String order_no) {
             this. order_no = order_no;
      }
       public String getUser_code() {
             return user_code;
      }
       public void setUser_code(String user_code) {
             this. user_code = user_code;
      }
      
      
      
       public List<Goods> getGoods() {
             return goods;
      }
       public void setGoods(List<Goods> goods) {
             this. goods = goods;
      }
       @Override
       public String toString() {
             return "Order[id=+"+ id+ ",order_no="+ order_no+ ",user_code="+ user_code+ ",goods="+ goods+ "]";
      }
}
 
在OrderMapper的映射文件中新增<resultMap>来处理多对多的查询
<? xml version= "1.0" encoding= "UTF-8" ?>
<! DOCTYPE mapper
  PUBLIC "-// mybatis.org//DTD Mapper 3.0//EN"
  < mapper namespace= "com.xiaoxie.dao.OrderDao" >
       < select id= "selectOrderByUserCode" parameterType= "String" resultType= "com.xiaoxie.pojo.Order" >
            select * from `order` where user_code = #{user_code}
       </ select >
       <!-- 多对多的级联 -->
       < resultMap type= "com.xiaoxie.pojo.Order" id= "OrdersAndGoods" >
             < id property= "id" column= "id" />
             < result property= "order_no" column= "order_no" />
             < result property= "user_code" column= "user_code" />
             <!-- 多对多 -->
             < collection property= "goods" ofType= "com.xiaoxie.pojo.Goods" >
                   < id property= "id" column= "id" />
                   < result property= "goods_no" column= "goods_no" />
             </ collection >
       </ resultMap >
       < select id= "selectAllOrderAndGoods" resultMap= "OrdersAndGoods" >
            select o.*,g.* from `order` o
            left join order_detail d on o.order_no = d.order_no
            left join goods g on d.goods_no = g.goods_no
       </ select >
  </ mapper >
 
新增对应的Dao接口方法
package com.xiaoxie.dao;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import com.xiaoxie.pojo.Order;
@Repository( "orderDao")
@Mapper
public interface OrderDao {
      List<Order> selectOrderByUserCode(String user_code);
      List<Order> selectAllOrderAndGoods();    //新增的多对多接口方法
}
 
新增Controller类
OrdersAndGoodsController:
package com.xiaoxie.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import com.xiaoxie.dao.OrderDao;
import com.xiaoxie.pojo.Order;
@Controller( "ordersAndGoodsController")
@Transactional
public class OrdersAndGoodsController {
       @Autowired
       private OrderDao orderDao;
       public void test() {
            List<Order> orders = orderDao.selectAllOrderAndGoods();
            System. out.println( orders);
      }
}
 
在测试类中进行测试
ApplicationContext context = new ClassPathXmlApplicationContext( "spring-config.xml");
OrdersAndGoodsController ogc = (OrdersAndGoodsController) context .getBean( "ordersAndGoodsController" );
ogc.test();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值