一、Mapper接口来实现CRUD

1.1 接口映射

接口映射:mybatis提供了一种可以通过调用接口中的方法实现调用对应的SQL语句,xxxx.fun(user);
接口: 接口对应指定的mapper文件
映射:使用接口与对应的mapper文件形成映射关系,操作接口就是在操作mapper文件

要求
1.接口的名字最好与mapper的名字相同
2.接口与mapper最好在同一个包下
3.mapper文件的namespace必须是对应接口的类型全名
4.mapper中SQL的id必须与接口中对应的方法名相同
5.在mybatis的主配置文件中需要扫描mapper、接口所在的包

1.2 代码实现

在昨天的测试类中,我们进行测试的方法为

  1. session.insert("abc.add", user);

不符合面对接口编程的思想,于是我们创建UserMapper接口来实现CRUD

1.2.1 UserMapper.java接口

  1. package com.woniuxy.mapper;
  2. import java.util.List;
  3. import java.util.Map;
  4. import com.woniuxy.entity.User;
  5. public interface UserMapper {
  6. // 全查询,返回List
  7. public List<User> findAll();
  8. // 添加
  9. public int add(User user);
  10. // 删除
  11. public int delById(int id);
  12. // 修改
  13. public int changePwd(Map<String, Object> map);
  14. }

注意:其中,方法名对应UserMapper.xml中CRUD的id
image.png

1.2.2 UserMapper.xml

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <!-- namespace:命名空间,作用与包名一样,区分相同id的SQL -->
  6. <mapper namespace="com.woniuxy.mapper.UserMapper">
  7. <!-- 二级缓存:
  8. 指定当前mapper中所有SQL语句查询到的数据都可以“可以”放到二级缓存中,建议为只读
  9. 触发:需要session.commit()提交后或session.close()关闭后才会存入二级缓存
  10. -->
  11. <cache readOnly="true"></cache>
  12. <!-- id为SQL的唯一标识,同一命名空间下不能有id相同的SQL
  13. resultType:将查询出来的数据封装成什么类型的对象
  14. -->
  15. <select id="findAll" resultType="com.woniuxy.entity.User">
  16. select * from mall_user
  17. </select>
  18. <!-- 增 -->
  19. <insert id="add">
  20. insert into mall_user
  21. values (default,#{account},#{password},#{email},
  22. #{avatar},#{score},#{regtime},#{status})
  23. </insert>
  24. <!-- 删
  25. 如果参数是基本数据类型、包装类、string类型,获取参数时名字可以随意取
  26. 但是建议与要操作的字段名字保持一致
  27. -->
  28. <delete id="delById">
  29. delete from mall_user where id = #{id};
  30. </delete>
  31. <!-- 改 -->
  32. <update id="changePwd">
  33. update mall_user set password = #{password} where account = #{account}
  34. </update>
  35. </mapper>

注意:标签中的namespace需要对应着接口的全名,并且需要在mabatis-config.xml中扫描mapper所在的包
image.png
image.png
**

1.2.3 UserMapperTest.java 测试类

package com.woniuxy.test;

import java.io.IOException;
import java.io.InputStream;

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 com.woniuxy.mapper.GoodsMapper;

public class UserMapperTest {

    public static void main(String[] args) throws IOException {

        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");

        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);

        SqlSession session = factory.openSession();

        // 获取mapper对象,利用动态代理自动生成了实现该接口的实现类,自动创建该类型的对象
//        UserMapper userMapper = session.getMapper(UserMapper.class);
//        System.out.println(userMapper.findAll());

        // 获取mapper对象,利用动态代理自动生成了实现该接口的实现类,自动创建该类型的对象

        GoodsMapper goodsMapper = session.getMapper(GoodsMapper.class);
        // 全查询商品
//        System.out.println(goodsMapper.findAll());

        // 根据ID查询商品
//        System.out.println(goodsMapper.findById(150));

        // 根据名字模糊查询商品
        System.out.println(goodsMapper.findByNameLike("%IT%"));

        session.close();
    }

}

可见,上述方法实现了 接口.方法名来实现CRUD,从而实现了面向接口编程

二、mybatis的自动映射

自动映射:mybatis根据查询出来的“结果集”,自动将数据封装成指定类型的对象
第一层含义:对象中的数据只能包含结果集中的数据
第二层含义:mybatis在进行自动映射时是根据结果集的字段名找到对应的setter给对应的属性赋值

在使用mybatis时,创建entity对象时,它的属性应该与表中的字段名保持一致

保持一致的方式:

2.1 起别名(不常用)

user
uid uname uage
select uid id,
User
id name age

2.2 手动映射(常用)

手动映射:程序员自己指定映射规则,哪些字段的值映射到哪些属性上

三、@Param

使用@Param注解可以自动帮我们把数据封装成Map的形式

3.1 使用之前

GoodsMapper接口中的方法

public int findByPage(Map<String, Object> map);

GoodsTest测试类中的实现

        //分页查询
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("index", (page-1)*size);
        params.put("size", size);
        System.out.println(goodsMapper.findByPage(params));

3.2 使用@Param注解

GoodsMapper接口中的方法

    // @Param 自动将参数封装到map中,其中的("index")为key,参数的值为value
    // 此处参数名不重要,重要的是("index")是否正确
    public List<Goods> findByPage(@Param("index")int index,@Param("size")int size);

GoodsTestMapper测试类中的实现

System.out.println(goodsMapper.findByPage(5, 10));

四、mybatis缓存

mybatis自带缓存,缓存是用临时存储数据,主要是为了提高查询效率
mybatis提供两种缓存:一级缓存,二级缓存

4.1 一级缓存

session缓存,session级别的缓存,只缓存当前session查询到的数据,每个session都有自己的缓存,在查询时session首先会先到自己的缓存中去查看是否有满足需求的数据,如果有则直接从缓存中获取到数据,否则执行SQL查询数据,然后将查询到的数据放到一级缓存中

4.2 二级缓存

factory缓存,factory级别的缓存,只要是通过该工厂创建出来的session查询到的数据都可以放到factory缓存中,所有的session就可以共享
注意:不是什么数据都往里面放,是那些使用非常频繁的数据才往里面扔,所有mybatis在运行时默认不会将session查询到的数据放到二级缓存中,而是需要程序员告诉mybatis哪些数据需要放到二级缓存,mybatis才会将这些数据放到二级缓存中
告诉mybatis的方法是在mapper文件中通过cache标签指定当前mapper查询到的数据可以存放到二级缓存中
在xml中添加标签:

<!--     二级缓存:
          指定当前mapper中所有SQL语句查询到的数据都可以“可以”放到二级缓存中,建议为只读
          触发:需要session.commit()提交后或session.close()关闭后才会存入二级缓存
-->
<cache readOnly="true"></cache>

其位置在内,SQL语句之前**
image.png

五、手动映射

程序员自己指定映射规则,哪些字段的值映射到哪些属性上

5.1 User2实体类

我们手动制造出表中列名与实体类中的属性名无法自动映射的情况
image.png

package com.woniuxy.entity;

import java.util.Date;

import lombok.Data;

@Data
public class User2 {
    private int uid;                //id
    private String uaccount;        //账号
    private String upassword;        //密码
    private String uemail;            //邮箱
    private String uavatar;            //头像
    private int uscore;                //积分
    private Date uregtime;            //注册时间
    private String ustatus;            //状态
}

5.2 UserMapper.java接口

package com.woniuxy.mapper;

import java.util.List;
import java.util.Map;

import com.woniuxy.entity.User;
import com.woniuxy.entity.User2;

public interface UserMapper2 {
    //all
    public List<User2> findAll();
}

5.3 UserMapper.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.woniuxy.mapper.UserMapper2">
    <select id="findAll" resultMap="abc">
        select * from mall_user
    </select>

    <!-- 自定义映射规则 
        type:将数据封装成指定类型的对象
    -->
    <resultMap type="User2" id="abc">
        <!-- 指定主键的映射关系:必须指定 -->
        <id column="id" property="uid"/>
        <!-- 非主键列的映射规则 -->
        <result column="account" property="uaccount"/>
        <result column="password" property="upassword"/>
        <result column="email" property="uemail"/>
        <result column="avatar" property="uavatar"/>
        <result column="score" property="uscore"/>
        <result column="regtime" property="uregtime"/>
        <result column="status" property="ustatus"/>
    </resultMap>
</mapper>

5.4 UserMapper2Test测试类

package com.woniuxy.test;

import java.io.InputStream;

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 com.woniuxy.mapper.UserMapper2;

public class UserMapper2Test {
    public static void main(String[] args)throws Exception {
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = factory.openSession();
        UserMapper2 userMapper2 = session.getMapper(UserMapper2.class);

        System.out.println(userMapper2.findAll());

        session.close();
    }
}

六、映射关系

类与类之间的映射关系
一对一:一个husband一个wife、一个person对应一张card
一对多:一个班级多个学生、一个公司多个职员、一个家庭多个成员
多对一:多个学生一个班级
多对多:多个老板对应多个公司、多个班级多个老师

七、一对一映射

image.png
新建Husband表与Wife表,其中一一对应

7.1 实体类

7.1.1 Husband

package com.woniuxy.entity;

import lombok.Data;

@Data
public class Husband {

    private int hid;
    private String hname;
    private Wife wife;

}

7.1.2 Wife

package com.woniuxy.entity;

import lombok.Data;

@Data
public class Wife {

    private int wid;
    private String wname;

}

7.2 接口

HusbandMapper.java 接口

package com.woniuxy.mapper;

import com.woniuxy.entity.Husband;

public interface HusbandMapper {

    // 根据丈夫的id查询到他自己的信息及其配偶的信息
    public Husband findByHid(int id);

}

7.3 XML文件

HusbandMapper.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">

<!-- namespace:命名空间,作用与包名一样,区分相同id的SQL -->
<mapper namespace="com.woniuxy.mapper.HusbandMapper">

    <!-- 通过外键判断进行连表查询 -->
    <select id="findByHid" resultMap="husbandMap">
        select * from husband h,wife w where h.hid = w.hid and h.hid=#{hid}
    </select>

    <resultMap type="Husband" id="husbandMap">
        <!-- 指定主键的映射关系:必须指定,就算能自动映射也要写
             如果查询语句是连表查询,所有字段、属性的映射关系都必须指定
         -->
        <id column="hid" property="hid"/>
        <result column="hname" property="hname"/>
        <!-- 指定一对一的关系
            property:属性名    javaType:该属性的类型
        -->
        <association property="wife" javaType="Wife">
            <id column="wid" property="wid"/>
            <result column="wname" property="wname"/>
        </association>
    </resultMap>
</mapper>

image.png
image.png

7.4 测试类

OneToOneTest 测试类

package com.woniuxy.test;

import java.io.IOException;
import java.io.InputStream;

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 com.woniuxy.mapper.HusbandMapper;

public class OneToOneTest {

    public static void main(String[] args) throws IOException {

        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");

        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);

        SqlSession session = factory.openSession();

        HusbandMapper husbandMapper = session.getMapper(HusbandMapper.class);

        通过外键判断进行连表查询
        System.out.println(husbandMapper.findByHid(1001));

    }

}

7.5 n+1查询

上述方法为连表查询的方法,还有一种n+1的查询方法

7.5.1 Husband.java接口

package com.woniuxy.mapper;

import com.woniuxy.entity.Husband;

public interface HusbandMapper {

    // 根据丈夫的id查询到他自己的信息及其配偶的信息
    public Husband findByHid(int id);

    // 使用n+1的方法查询
    public Husband findByHid2(int id);

}

7.5.2 Husband.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">

<!-- namespace:命名空间,作用与包名一样,区分相同id的SQL -->
<mapper namespace="com.woniuxy.mapper.HusbandMapper">

    <!-- 通过外键判断进行连表查询 -->
    <select id="findByHid" resultMap="husbandMap">
        select * from husband h,wife w where h.hid = w.hid and h.hid=#{hid}
    </select>

    <resultMap type="Husband" id="husbandMap">
        <!-- 指定主键的映射关系:必须指定,就算能自动映射也要写
             如果查询语句是连表查询,所有字段、属性的映射关系都必须指定
         -->
        <id column="hid" property="hid"/>
        <result column="hname" property="hname"/>
        <!-- 指定一对一的关系
            property:属性名    javaType:该属性的类型
        -->
        <association property="wife" javaType="Wife">
            <id column="wid" property="wid"/>
            <result column="wname" property="wname"/>
        </association>
    </resultMap>

    <!-- n+1多表查询 -->

    <select id="findByHid2" resultMap="nMap">
        select * from husband where hid = #{hid}
    </select>

    <resultMap type="Husband" id="nMap">
        <id column="hid" property="hid"/>
        <!-- column:表示哪一个字段的值作为查询条件,去调用第二条SQL语句 
            select:需要调用的SQL语句id
        -->
        <association property="wife" column="hid" select="findWifeByHid"></association>
    </resultMap>

    <select id="findWifeByHid" resultType="Wife">
        select * from wife where hid = #{hid}
    </select>

</mapper>

image.png

7.5.3 OneToOneTest 测试类

package com.woniuxy.test;

import java.io.IOException;
import java.io.InputStream;

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 com.woniuxy.mapper.HusbandMapper;

public class OneToOneTest {

    public static void main(String[] args) throws IOException {

        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");

        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);

        SqlSession session = factory.openSession();

        HusbandMapper husbandMapper = session.getMapper(HusbandMapper.class);

        // 通过外键判断进行连表查询
//        System.out.println(husbandMapper.findByHid(1001));
        // n + 1查询
        System.out.println(husbandMapper.findByHid2(1001));
    }

}