[Java]Mybatis学习笔记(动力节点老杜)(七)

简介: [Java]Mybatis学习笔记(动力节点老杜)(七)

返回 List(多条记录)

/**
 * 查询所有的汽车信息
 * 
 * @return 所有的汽车信息
 */
List<Car> selectAll();
<select id="selectAll" resultType="car">
  select id,
         car_num      as carNum,
         brand,
         guide_price  as guidePrice,
         produce_time as produceTime,
         car_type     as carType
  from t_car;
</select>
@org.junit.Test
public void testSelectAll() {
    SqlSession sqlSession = SqlSessionUtil.openSession();
    CarMapper mapper = sqlSession.getMapper(CarMapper.class);
    List<Car> cars = mapper.selectAll();
    cars.forEach(System.out::println);
    SqlSessionUtil.close();
}

  • 如果返回的结果集只有一条记录,可以使用集合进行接收
  • 如果返回的结果集有多条记录,只能使用集合进行接收,如果返回的结果集只有一条记录,可以使用集合进行接收也可以使用一个pojo进行接收

返回 Map

  • 当返回的数据,没有合适的实体类对应的话,可以采用Map集合接收,字段名做key,字段值做value,如果SQL语句中使用了别名,则使用指定的别名做key
  • 查询如果可以保证只有一条数据,则返回一个Map集合即可。如果返回的数据存在多条,则使用一个Map集合接收会报错,得使用Map组成的List集合进行接收
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bZqbNusc-1685870936829)(https://www.yuque.com/api/filetransfer/images?url=https%3A%2F%2Fucc.alicdn.com%2Fimages%2Fuser-upload-01%2F63cfeac812cf4a99a1381937b72343bf.png&sign=2b687760bd7f818d690380fb59baf7e89531b0ad5e79ba1e9630c4d78948a06f#from=url&height=225&id=N4UXP&originHeight=313&originWidth=316&originalType=binary&ratio=1.25&rotation=0&showTitle=false&status=done&style=none&title=&width=227)]
/**
 * 根据id查询汽车信息
 *
 * @param id 汽车信息的id
 * @return 汽车信息封装成的Map
 */
Map<String, Object> selectByIdReturnMap(Long id);
<!-- MyBatis 中 map 为 java.util.Map 的别名 -->
<select id="selectByIdReturnMap" resultType="map">
  select id,
         car_num      as carNum,
         brand,
         guide_price  as guidePrice,
         produce_time as produceTime,
         car_type     as carType
  from t_car
  where id = #{id};
</select>
@org.junit.Test
public void testSelectByIdReturnMap() {
    SqlSession sqlSession = SqlSessionUtil.openSession();
    CarMapper mapper = sqlSession.getMapper(CarMapper.class);
    Map<String, Object> map = mapper.selectByIdReturnMap(5L);
    System.out.println(map);
    SqlSessionUtil.close();
}

返回 List<Map>

  • 查询结果条数大于等于1条数据,没有合适的实体类对应的话,则可以返回一个存储Map集合的List集合。
  • List<Map>相当于List<Car>
  • 查询出来的数据有多条或者只有一条都可以使用存储Map集合的List集合进行接收
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ET4Etots-1685870936830)(https://www.yuque.com/api/filetransfer/images?url=https%3A%2F%2Fucc.alicdn.com%2Fimages%2Fuser-upload-01%2F41b7c6ebf4454d82b5a8e61d75f06698.png&sign=164d10c96d9a58c55ad0984c21efae7c611f5c3cdc9f43da16de37ccc6fb26bb#from=url&height=381&id=Gbi57&originHeight=733&originWidth=477&originalType=binary&ratio=1.25&rotation=0&showTitle=false&status=done&style=none&title=&width=248)]
/**
 * 查询所有的汽车信息
 *
 * @return 由汽车信息封装在Map中组成的List集合
 */
List<Map<String, Object>> selectAllReturnListMap();
<!-- MyBatis 中 map 为 java.util.Map 的别名 -->
<!-- 返回的还是 map,只有最后数据多个map封装在list中 -->
<select id="selectAllReturnListMap" resultType="map">
  select id,
         car_num      as carNum,
         brand,
         guide_price  as guidePrice,
         produce_time as produceTime,
         car_type     as carType
  from t_car;
</select>
@org.junit.Test
public void testSelectAllReturnListMap() {
    SqlSession sqlSession = SqlSessionUtil.openSession();
    CarMapper mapper = sqlSession.getMapper(CarMapper.class);
    List<Map<String, Object>> maps = mapper.selectAllReturnListMap();
    maps.forEach(System.out::println);
    SqlSessionUtil.close();
}

返回 Map<String, Map>

  • 当查询结果集中存在多条数据记录,使用List<Map>进行接收,不利于我们对结果集中的数据进行查询,需要顺序遍历查询
  • 为了可以更快的查询我们所需的数据,我们可以拿数据记录的id(主键)做key,由整条数据记录封装而成的Map作为value,则以后取出对应的所需数据的Map集合时更方便。
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XHoQiYeX-1685870936832)(https://www.yuque.com/api/filetransfer/images?url=https%3A%2F%2Fucc.alicdn.com%2Fimages%2Fuser-upload-01%2F78116385c1a742ac9862719ae9d2635d.png&sign=f48795a8beb121c5ffb9d5e63f0f160f78d5104ed3b2f7c3b863e2ea13231504#from=url&height=311&id=zwM3Y&originHeight=736&originWidth=787&originalType=binary&ratio=1.25&rotation=0&showTitle=false&status=done&style=none&title=&width=332.4000244140625)]
/**
 * 查询所有的汽车信息
 *
 * @return 由汽车信息封装在Map中组成的Map集合
 */
@MapKey("id") // @MapKey 注解的属性 value 指定使用数据哪个字段作为Map 的 key
// 作为大Map key 的数据类型要与@MapKey 注解指定的字段的数据类型一致
Map<Long, Map<String, Object>> selectAllReturnMapMap();
<!-- MyBatis 中 map 为 java.util.Map 的别名 -->
<!-- 返回的还是 map,只有最后数据多个map封装在Map中 -->
<select id="selectAllReturnMapMap" resultType="map">
  select id,
         car_num      as carNum,
         brand,
         guide_price  as guidePrice,
         produce_time as produceTime,
         car_type     as carType
  from t_car;
</select>
@org.junit.Test
public void testSelectAllReturnMapMap() {
    SqlSession sqlSession = SqlSessionUtil.openSession();
    CarMapper mapper = sqlSession.getMapper(CarMapper.class);
    Map<Long, Map<String, Object>> map = mapper.selectAllReturnMapMap();
    System.out.println(map.get(5L));
    System.out.println(map.get(7L));
    SqlSessionUtil.close();
}

结果映射

  • 当查询结果的列名和 java 对象的属性名对应不上时的解决方式:
  • 第一种方式:as 给列起别名
  • 第二种方式:使用resultMap进行结果映射
  • 第三种方式:是否开启驼峰命名自动映射(配置settings)

使用 resultMap 进行结果映射

  • resultMap 可以实现查询结果集中字段名和Java对象的属性名之间的映射
/**
 * 查询所有的汽车信息
 * 使用 ResultMap 标签进行结果映射
 * 
 * @return 汽车信息组成的集合
 */
List<Car> selectAllByResultMap();
<!-- 
  定义一个结果映射
  在这个结果映射中指定数据库表字段和Java类的属性名之间的对应关系 
  type="":用于指定Java类的类名
  id="":指定 resultMap 的唯一标识,这个id要在select标签中进行使用
-->
<!-- 在Mybatis核心配置文件中指定了别名,所以可以直接使用car -->
<resultMap id="carResultMap" type="car">
  <!-- 如果数据库表中有主键,建议配一个id标签,提高Mybatis的执行效率 -->
  <!-- 当然 id 也可以使用 result 标签,就是效率较低 -->
  <id property="id" column="id"/>
  <!-- 
    property="":填写Java类的属性名
    column="":填写数据库表的字段名
    javaType:指定Java类属性的类型,不用Mybatis自动类型推断,提高效率(可以使用别名)
    jdbcType:指定数据库表字段的类型,不用Mybatis自动类型推断,提高效率
  -->
  <result property="carNum" 
      column="car_num"
      javaType="java.lang.String"
      jdbcType="VARCHAR"
  />
  <!-- 如果column和property的属性值一样可以省略 -->
  <!-- <result property="brand" column="brand"/> -->
  <result property="guidePrice" column="guide_price"/>
  <result property="produceTime" column="produce_time"/>
  <result property="carType" 
      column="carType"
          javaType="string"
          jdbcType="VARCHAR"
  />
</resultMap>
<!-- 
  使用结果映射,在select标签中不使用resultType
  而是使用 resultMap,其属性值为 resultMap 的 id
  使用 resultMap 指定结果映射
-->
<select id="selectAllByResultMap" resultMap="carResultMap">
  select * from t_car;
</select>
@org.junit.Test
public void testSelectAllByResultMap() {
    SqlSession sqlSession = SqlSessionUtil.openSession();
    CarMapper mapper = sqlSession.getMapper(CarMapper.class);
    List<Car> cars = mapper.selectAllByResultMap();
    cars.forEach(System.out::println);
    SqlSessionUtil.close();
}

开启驼峰命名自动映射

  • 驼峰命名自动映射这种方式的前提是:Java类的属性名遵循Java的命名规范,数据库表的列名遵循SQL的命名规范。
  • Java命名规范:首字母小写,后面每个单词首字母大写,遵循驼峰命名方式。
  • SQL命名规范:全部小写,单词之间采用下划线分割。
  • Java类的属性名与数据库表的列名的对应关系:
    | 实体类中的属性名 | 数据库表的列名 |
    | — | — |
    | carNum | car_num |
    | carType | car_type |
    | produceTime | produce_time |
  • 开启驼峰命名自动映射,在MyBatis的核心配置文件中的settings标签中进行配置
<settings>
  <!-- 开启驼峰命名自动映射 -->
  <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
/**
 * 查询所有汽车信息
 * 使用驼峰命名自动映射
 * 
 * @return 汽车信息组成的集合
 */
List<Car> selectAllByMapUnderscoreToCamelCase();
<select id="selectAllByMapUnderscoreToCamelCase" resultType="car">
  select * from t_car;
</select>
@org.junit.Test
public void testSelectAllByMapUnderscoreToCamelCase() {
    SqlSession sqlSession = SqlSessionUtil.openSession();
    CarMapper mapper = sqlSession.getMapper(CarMapper.class);
    List<Car> cars = mapper.selectAllByMapUnderscoreToCamelCase();
    cars.forEach(System.out::println);
    SqlSessionUtil.close();
}

返回总记录条数

/**
 * 查询汽车信息的总记录条数
 * 
 * @return 汽车信息的总记录条数
 */
Long selectTotal();
<!-- long 是 java.util.Long 的别名 -->
<select id="selectTotal" resultType="long">
  select count(*) from t_car;
</select>
@org.junit.Test
public void testSelectTotal() {
    SqlSession sqlSession = SqlSessionUtil.openSession();
    CarMapper mapper = sqlSession.getMapper(CarMapper.class);
    Long total = mapper.selectTotal();
    System.out.println(total);
    SqlSessionUtil.close();
}

动态 SQL

业务场景(为什么需要动态SQL)

  • 我们需要进行数据的批量删除
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2HD5LXTw-1685870936837)(https://www.yuque.com/api/filetransfer/images?url=https%3A%2F%2Fucc.alicdn.com%2Fimages%2Fuser-upload-01%2F7dcef7f1f04e44bf8f7431c7a5e87bdd.png&sign=9532cda95213becdabf7a702b5cadecf196a083af802d074aa92c11792567342#from=url&height=109&id=sPcVI&originHeight=168&originWidth=232&originalType=binary&ratio=1.25&rotation=0&showTitle=false&status=done&style=none&title=&width=150)]
  • delete from t_car where id in(1,2,3,4,5,6,...);,其中,SQL语句中的 in() 中的内容是动态的,根据用户选择的id不同,SQL语句 in() 中的内容是不同的
  • 我们需要进行多条件查询
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EzjhAMts-1685870936838)(https://www.yuque.com/api/filetransfer/images?url=https%3A%2F%2Fucc.alicdn.com%2Fimages%2Fuser-upload-01%2Fd56eb25cb21b43a39ad5fb938d6659d0.png&sign=4557fedb9e295ef872fcccf3a5b57265041fcbeeb0a4d48807994f5cf1be35fa#from=url&height=92&id=Pr2m3&originHeight=159&originWidth=706&originalType=binary&ratio=1.25&rotation=0&showTitle=false&status=done&style=none&title=&width=410.4000244140625)]
  • select * from t_car where brand like '丰田%' and guide_price > 30 and .....;,其中,SQL语句中where后面条件的个数是不确定的,是动态的,用户选择不同的条件,SQL语句中条件的个数不同

if 标签

  • 可能的条件包括:品牌(brand)、指导价格(guide_price)、汽车类型(car_type)
/**
 * 多条件查询
 * 可能的条件包括:品牌(brand)、指导价格(guide_price)、汽车类型(car_type)
 *
 * @param brand 品牌
 * @param guidePrice 指导价格
 * @param carType 汽车类型
 * @return 汽车信息组成的集合
 */
List<Car> selectByMultiCondition(
        @Param("brand") String brand, 
        @Param("guidePrice") Double guidePrice, 
        @Param("carType") String carType
);
<select id="selectByMultiCondition" resultType="Car">
    <!-- where 1 = 1 保证条件都为空时sql语法可以通过 -->
    <!-- 
      如果条件都为空,并且没有1 = 1,则SQL语句会变为select * from t_car where,
      会报语法错误
    -->
    select * from t_car where 1 = 1
    <!--
        1. if标签中test属性是必须的。
        2. if标签中test属性的值是false或者true。
              if标签的test属性中可以写表达式,值为false或者true
        3. 如果test是true,则if标签中的sql语句就会拼接。反之,则不会拼接。
        4. 在test属性中使用接口方法中参数的方式:(与#{}中使用接口方法中参数一样)
            1)当使用了@Param注解,那么test中要出现的是@Param注解指定的参数名。
                @Param("brand"),那么这里只能使用brand
            2)当没有使用@Param注解,那么test中要出现的是:
                param1 param2 param3 arg0 arg1 arg2....
            3)当使用了POJO,那么test中出现的是POJO类的属性名。
        5. 在mybatis的动态SQL当中,不能使用&&,只能使用and。
    -->
    <!-- 第一个条件添加and防止“where 1 = 1 brand like "%"#{brand}"%"”语法错误 -->
    <if test="brand != null and brand != ''">
        and brand like "%"#{brand}"%"
    </if>
    <if test="guidePrice != null and guidePrice != ''">
        and guide_price > #{guidePrice}
    </if>
    <if test="carType != null and carType != ''">
        and car_type = #{carType}
    </if>
</select>
@Test
    public void testSelectByMultiCondition(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        // 假设三个条件都不是空
        //List<Car> cars = mapper.selectByMultiCondition("比亚迪", 2.0, "新能源");
        // 假设三个条件都是空
        //List<Car> cars = mapper.selectByMultiCondition("", null, "");
        // 假设后两个条件不为空,第一个条件为空
        //List<Car> cars = mapper.selectByMultiCondition("", 2.0, "新能源");
        // 假设第一个条件不是空,后两个条件是空
        List<Car> cars = mapper.selectByMultiCondition("比亚迪", null, "");
        cars.forEach(car -> System.out.println(car));
        sqlSession.close();
    }

where 标签

  • where标签的作用:让where子句更加动态智能。当所有条件都为空时,where标签保证不会生成where子句,可以自动去除某些条件前面多余的and或or,但是不能自动去除某些条件后面多余的and或or
/**
 * 使用where标签,让where子句更加的智能。
 * @param brand
 * @param guidePrice
 * @param carType
 * @return
 */
List<Car> selectByMultiConditionWithWhere(@Param("brand") String brand, @Param("guidePrice") Double guidePrice, @Param("carType") String carType);
<select id="selectByMultiConditionWithWhere" resultType="Car">
    select * from t_car
    <!--
      where标签是专门负责where子句动态生成的。
      如果where标签中的条件都不成立,则SQL语句中不会有where子句
    -->
    <where>
        <!-- 可以自动去除条件前面多余的and或or -->
        <if test="brand != null and brand != ''">
            and brand like "%"#{brand}"%"
        </if>
        <if test="guidePrice != null and guidePrice != ''">
            and guide_price > #{guidePrice}
        </if>
        <if test="carType != null and carType != ''">
            and car_type = #{carType}
        </if>
    </where>
</select>
@Test
public void testSelectByMultiConditionWithWhere(){
    SqlSession sqlSession = SqlSessionUtil.openSession();
    CarMapper mapper = sqlSession.getMapper(CarMapper.class);
    // 三个条件都不是空
    //List<Car> cars = mapper.selectByMultiConditionWithWhere("比亚迪", 2.0, "新能源");
    // 三个条件都是空
    //List<Car> cars = mapper.selectByMultiConditionWithWhere("", null, "");
    // 如果第一个条件是空
    //List<Car> cars = mapper.selectByMultiConditionWithWhere("", 2.0, "新能源");
    // 后面两个条件是空
    List<Car> cars = mapper.selectByMultiConditionWithWhere("比亚迪", null, "");
    cars.forEach(car -> System.out.println(car));
    sqlSession.close();
}

trim 标签

<select id="selectByMultiConditionWithTrim" resultType="Car">
    select * from t_car
    <!--
        prefix:加前缀
        suffix:加后缀
        prefixOverrides:删除前缀
        suffixOverrides:删除后缀
    -->
    <!--
      prefix="where" 是在trim标签内容的前面添加 where,
      这个添加是动态的
      如果有条件,会动态添加where,没有则不添加
    -->
    <!--
      suffixOverrides="and|or" 
      把trim标签中动态判断完后的内容多余的后缀and或or去掉
    -->
    <trim prefix="where" suffixOverrides="and|or">
        <if test="brand != null and brand != ''">
            brand like "%"#{brand}"%" or
        </if>
        <if test="guidePrice != null and guidePrice != ''">
            guide_price > #{guidePrice} and
        </if>
        <if test="carType != null and carType != ''">
            car_type = #{carType}
        </if>
    </trim>
</select>

set 标签

  • 主要使用在update语句当中,用来动态生成set关键字,同时去掉最后多余的“,”
  • 需求:只更新提交的不为空的字段,如果提交的数据是空或者"“,那么这个字段我们将不更新,即字段不为空或者”"就动态拼接其对应的SQL子句,否则不动态拼接其对应的SQL子句
/**
* 更新信息,使用set标签
* @param car
* @return
*/
int updateWithSet(Car car);
<update id="updateBySet">
    update t_car
    <set>
        <if test="carNum != null and carNum != ''">car_num = #{carNum},</if>
        <if test="brand != null and brand != ''">brand = #{brand},</if>
        <if test="guidePrice != null and guidePrice != ''">guide_price = #{guidePrice},</if>
        <if test="produceTime != null and produceTime != ''">produce_time = #{produceTime},</if>
        <if test="carType != null and carType != ''">car_type = #{carType},</if>
    </set>
    where
        id = #{id}
</update>

choose when otherwise

这三个标签是必须在一起使用的:

<choose>
  <when></when>
  <when></when>
  <when></when>
  <otherwise></otherwise>
</choose>

等同于:

if(){
}else if(){
}else if(){
}else if(){
}else{
}

只有一个分支会被选择!!!!

需求:先根据品牌查询,如果没有提供品牌,再根据指导价格查询,如果没有提供指导价格,就根据汽车类型查询。

/**
* 使用choose when otherwise标签查询
* @param brand
* @param guidePrice
* @param produceTime
* @return
*/
List<Car> selectWithChoose(@Param("brand") String brand, @Param("guidePrice") Double guidePrice, @Param("carType") String carType);
<select id="selectByChoose" resultType="Car">
        select * from t_car
        <where>
            <!--
              先根据品牌查询,没有传品牌,在根据价格查询,
              都没有最后根据汽车类型查询
            -->
            <choose>
                <!--只有一个分支会执行,所以不需要and or关键字-->
                <when test="brand != null and brand != ''">
                    brand like "%"#{brand}"%"
                </when>
                <when test="guidePrice != null and guidePrice != ''">
                    guide_price > #{guidePrice}
                </when>
                <!--都为null,还是执行这个分支,car_type = null,只是查不到数据-->
                <otherwise>
                    car_type = #{carType}
                </otherwise>
            </choose>
        </where>
    </select>

foreach 标签

  • 循环数组或集合,动态生成sql,比如这样的SQL:
delete from t_car where id in(1,2,3);
delete from t_car where id = 1 or id = 2 or id = 3;
insert into t_car values
  (null,'1001','凯美瑞',35.0,'2010-10-11','燃油车'),
  (null,'1002','比亚迪唐',31.0,'2020-11-11','新能源'),
  (null,'1003','比亚迪宋',32.0,'2020-10-11','新能源')

批量删除

in()
/**
 * 批量删除。foreach标签
 * @param ids
 * @return
 */
int deleteByIds(@Param("ids") Long[] ids);
<!--
    foreach标签的属性:
        collection:指定数组或者集合
        item:代表数组或集合中的元素
        separator:循环之间的分隔符,自动添加分隔符,会自动在分隔符的两边添加空格
        open: foreach循环拼接的所有sql语句的最前面以什么开始。
        close: foreach循环拼接的所有sql语句的最后面以什么结束。
-->
<delete id="deleteByIds">
    <!--
      delete from t_car where id in(
      <foreach collection="ids" item="aaaaaaa" separator=",">
          #{aaaaaaa}
      </foreach>
      )
      没有使用@Param注解,上面的SQL报错了,错误信息是:[array, arg0]
      因为没有使用@Param注解时,参数在map集合中存储,默认使用array, arg0作为key
          map.put("array", 数组);
          map.put("arg0", 数组);
    -->
    delete from t_car where id in
    <foreach collection="ids" item="id" separator="," open="(" close=")">
        #{id}
    </foreach>
</delete>
or
/**
 * 根据id批量删除 使用or关键字。
 * @param ids
 * @return
 */
int deleteByIds2(@Param("ids") Long[] ids);
<delete id="deleteByIds2">
        delete from t_car where
        <!-- 会自动在分隔符的两边添加空格 -->
        <foreach collection="ids" item="id" separator="or">
            id=#{id}
        </foreach>
    </delete>

批量插入

/**
 * 批量插入,一次插入多条Car信息
 * @param cars
 * @return
 */
int insertBatch(@Param("cars") List<Car> cars);
<insert id="insertBatch">
    insert into t_car values
    <!-- cars 汽车信息组成的list集合,car一个汽车类的对象,取属性,对象.属性 -->
    <foreach collection="cars" item="car" separator=",">
        (null,#{car.carNum},#{car.brand},#{car.guidePrice},#{car.produceTime},#{car.carType})
    </foreach>
</insert>

sql 标签与 include 标签

  • sql标签用来声明sql片段,可以使需要重复编写的重复的SQL语句片段可以得到复用
  • include标签用来将声明的sql片段包含到某个sql语句当中
  • 作用:代码复用,易维护。
<!-- 
  声明sql片段
  将重复的SQL片段提取出来
-->
<sql id="carCols">
  id,
  car_num carNum,
  brand,
  guide_price guidePrice,
  produce_time produceTime,
  car_type carType
</sql>
<select id="selectAllRetMap" resultType="map">
  <!-- 将声明的sql片段包含进来 -->
  select 
    <include refid="carCols"/> 
  from t_car
</select>
<select id="selectAllRetListMap" resultType="map">
  select 
    <include refid="carCols"/> 
  carType from t_car
</select>
<select id="selectByIdRetMap" resultType="map">
  select 
    <include refid="carCols"/> 
  from t_car 
  where id = #{id}
</select>

MyBatis的高级映射及延迟加载

  • 低级映射(基础映射):一个数据库表对应一个Java对象
  • 高级映射:数据存储在数据库中两张不同的表中,并两个表之间的数据之间具有关系,此时映射到Java对象上为高级映射

数据库表

use mybatis_study;
drop table t_clazz;
create table t_clazz(
    cid int primary key,
    cname varchar(255)
);
drop table t_student;
create table t_student(
    sid int primary key,
    sname varchar(255),
    cid int
);
insert into t_clazz
values (1000, '高三一班'),
       (1001, '高三二班');
insert into t_student
values (1, '张三', 1000),
       (2, '李四', 1000),
       (3, '王五', 1000),
       (4, '赵六', 1001),
       (5, '钱七', 1001);

依赖

<dependencies>
  <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.10</version>
  </dependency>
  <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.30</version>
  </dependency>
  <dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.4.5</version>
  </dependency>
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13.2</version>
    <scope>test</scope>
  </dependency>
</dependencies>

项目结构

实体类

package cw.study.mybatis.pojo;
/**
 * ClassName: Clazz
 * Package: cw.study.mybatis.pojo
 * Description:
 * 班级信息
 *
 * @Author tcw
 * @Create 2023-06-04 11:38
 * @Version 1.0
 */
public class Clazz {
    private Integer cid;
    private String cname;
    public Clazz() {
    }
    public Clazz(Integer cid, String cname) {
        this.cid = cid;
        this.cname = cname;
    }
    @Override
    public String toString() {
        return "Clazz{" + "cid=" + cid + ", cname='" + cname + '\'' + '}';
    }
    public Integer getCid() {
        return cid;
    }
    public void setCid(Integer cid) {
        this.cid = cid;
    }
    public String getCname() {
        return cname;
    }
    public void setCname(String cname) {
        this.cname = cname;
    }
}
package cw.study.mybatis.pojo;
/**
 * ClassName: Student
 * Package: cw.study.mybatis.pojo
 * Description:
 * 学生信息
 *
 * @Author tcw
 * @Create 2023-06-04 11:38
 * @Version 1.0
 */
public class Student {
    private Integer sid;
    private String sname;
    public Student() {
    }
    public Student(Integer sid, String sname) {
        this.sid = sid;
        this.sname = sname;
    }
    @Override
    public String toString() {
        return "Student{" + "sid=" + sid + ", sname='" + sname + '\'' + ", " + '}';
    }
    public Integer getSid() {
        return sid;
    }
    public void setSid(Integer sid) {
        this.sid = sid;
    }
    public String getSname() {
        return sname;
    }
    public void setSname(String sname) {
        this.sname = sname;
    }
}

多对一

  • 主表与副表:谁在前,谁就是主表
  • 多对一,多为主表
  • 一对多,一为主表
  • 主表对应Java中的主对象
  • 多对一,多个学生对应一个班级,学生表为主表,学生对象为主对象,班级对象为副对象,要建立两个对象之间的关系,通过学生对象可以找到班级对象,所以在学生类中添加对班级对象的引用属性
  • 多对一的映射实体类设计:
  • 修改学生类,添加对班级对象的引用属性,修改setter、getter、toString
/**
 * 学生信息
 */
public class Student { // Student是多的一方
    private Integer sid;
    private String sname;
    private Clazz clazz; // Clazz是一的一方。
    ......
}
/**
 * 班级信息
 */
public class Clazz {
    private Integer cid;
    private String cname;
  ......
}


相关文章
|
1月前
|
Java 数据库连接 Maven
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和MyBatis Generator,使用逆向工程来自动生成Java代码,包括实体类、Mapper文件和Example文件,以提高开发效率。
106 2
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
|
16天前
|
分布式计算 Java MaxCompute
ODPS MR节点跑graph连通分量计算代码报错java heap space如何解决
任务启动命令:jar -resources odps-graph-connect-family-2.0-SNAPSHOT.jar -classpath ./odps-graph-connect-family-2.0-SNAPSHOT.jar ConnectFamily 若是设置参数该如何设置
|
23天前
|
搜索推荐 Java 数据库连接
Java|在 IDEA 里自动生成 MyBatis 模板代码
基于 MyBatis 开发的项目,新增数据库表以后,总是需要编写对应的 Entity、Mapper 和 Service 等等 Class 的代码,这些都是重复的工作,我们可以想一些办法来自动生成这些代码。
30 6
|
1月前
|
分布式计算 资源调度 Hadoop
大数据-01-基础环境搭建 超详细 Hadoop Java 环境变量 3节点云服务器 2C4G XML 集群配置 HDFS Yarn MapRedece
大数据-01-基础环境搭建 超详细 Hadoop Java 环境变量 3节点云服务器 2C4G XML 集群配置 HDFS Yarn MapRedece
76 4
|
1月前
|
分布式计算 Java Hadoop
Hadoop-30 ZooKeeper集群 JavaAPI 客户端 POM Java操作ZK 监听节点 监听数据变化 创建节点 删除节点
Hadoop-30 ZooKeeper集群 JavaAPI 客户端 POM Java操作ZK 监听节点 监听数据变化 创建节点 删除节点
62 1
|
2月前
|
缓存 前端开发 Java
【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
Soring Boot的起步依赖、启动流程、自动装配、常用的注解、Spring MVC的执行流程、对MVC的理解、RestFull风格、为什么service层要写接口、MyBatis的缓存机制、$和#有什么区别、resultType和resultMap区别、cookie和session的区别是什么?session的工作原理
【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
|
2月前
|
存储 安全 Java
Java修仙之路,十万字吐血整理全网最完整Java学习笔记(基础篇)
从Java环境的搭建到实际代码的编写,从基本用法的讲解到底层原理的剖析,深度解析Java基础知识。本文是《Java学习路线》专栏的起始文章,旨在提供一套完整的Java学习路线,覆盖Java基础知识、数据库、SSM/SpringBoot等框架、Redis/MQ等中间件、设计模式、架构设计、性能调优、源码解读、核心面试题等全面的知识点,并在未来不断更新和完善,帮助Java从业者在更短的时间内成长为高级开发。
Java修仙之路,十万字吐血整理全网最完整Java学习笔记(基础篇)
|
2月前
|
存储 安全 Java
Java修仙之路,十万字吐血整理全网最完整Java学习笔记(进阶篇)
本文是Java基础的进阶篇,对异常、集合、泛型、Java8新特性、I/O流等知识进行深入浅出的介绍,并附有对应的代码示例,重要的地方带有对性能、底层原理、源码的剖析。适合Java初学者。
Java修仙之路,十万字吐血整理全网最完整Java学习笔记(进阶篇)
|
1月前
|
Java 数据安全/隐私保护
java学习笔记(基础习题)
java学习笔记(基础习题)
33 0
|
1月前
|
Java 程序员 开发工具
java学习笔记
java学习笔记
35 0