MyBatis的各种查询功能

  1. 如果查询出的数据只有一条,可以通过
    1. 实体类对象接收
    2. List集合接收
    3. Map集合接收,结果{password=123456, sex=男, id=1, age=23, username=admin}
  2. 如果查询出的数据有多条,一定不能用实体类对象接收,会抛异常TooManyResultsException,可以通过
    1. 实体类类型的LIst集合接收
    2. Map类型的LIst集合接收
    3. 在mapper接口的方法上添加@MapKey注解

      查询一个实体类对象

      1. User getUserById(Integer id);
      1. <select id="getUserById" resultType="com.liwq.entity.User" parameterType="int">
      2. select *
      3. from user
      4. where id = #{id}
      5. </select>

      查询一个List集合

      1. List<User> listUsers();
      1. <select id="listUsers" resultType="com.liwq.entity.User">
      2. select *
      3. from user
      4. </select>

      查询单个数据

      1. int getCount();
      1. <select id="getCount" resultType="integer">
      2. select count(id) from t_user
      3. </select>

      查询一条数据为map集合

      1. Map<String, Object> getUserToMap(@Param("id") int id);
      1. <!--Map<String, Object> getUserToMap(@Param("id") int id);-->
      2. <select id="getUserToMap" resultType="map">
      3. select * from user where id = #{id}
      4. </select>

      查询多条数据为map集合

      方法一

      1. List<Map<String, Object>> getAllUserToMap();
      1. <!--Map<String, Object> getAllUserToMap();-->
      2. <select id="getAllUserToMap" resultType="map">
      3. select * from user
      4. </select>

      方法二

      ```java /**
    • 查询所有用户信息为map集合
    • @return
    • 将表中的数据以map集合的方式查询,一条数据对应一个map;若有多条数据,就会产生多个map集合,并且最终要以一个map的方式返回数据,此时需要通过@MapKey注解设置map集合的键,值是每条数据所对应的map集合 */ @MapKey(“id”) Map getAllUserToMap();
      1. ```xml
      2. <select id="getAllUserToMap" resultType="map">
      3. select * from user
      4. </select>
      查询结果:
      result:{1={user_name=张三, pass_word=123, id=1}, 10={user_name=张三, pass_word=123, id=10}, 11={user_name=张三, pass_word=123, id=11}, 12={user_name=张三, pass_word=123, id=12}, 13={user_name=tom3153e703-582b-40b1-96b1-142889d476d0, pass_word=pass398f68fd-b4cc-47d9-83e3-947750bddae6, id=13}}

      特殊SQL的执行

      模糊查询

      1. List<User> getUserByLike(@Param("username") String username);
      1. <select id="getUserByLike" resultType="User">
      2. select * from t_user where username like "%"#{mohu}"%"
      3. </select>
  • 其中select * from t_user where username like "%"#{mohu}"%"是最常用的

    批量删除

  • 只能使用${},如果使用#{},则解析后的sql语句为delete from t_user where id in ('1,2,3'),这样是将1,2,3看做是一个整体,只有id为1,2,3的数据会被删除。正确的语句应该是delete from t_user where id in (1,2,3),或者delete from t_user where id in ('1','2','3')

    1. /**
    2. * 根据id批量删除
    3. * @param ids
    4. * @return int
    5. * @date 2022/2/26 22:06
    6. */
    7. int deleteMore(@Param("ids") String ids);
    1. <delete id="deleteMore">
    2. delete from t_user where id in (${ids})
    3. </delete>
    1. //测试类
    2. @Test
    3. public void deleteMore() {
    4. SqlSession sqlSession = SqlSessionUtils.getSqlSession();
    5. SQLMapper mapper = sqlSession.getMapper(SQLMapper.class);
    6. int result = mapper.deleteMore("1,2,3,8");
    7. System.out.println(result);
    8. }

    动态设置表名

  • 只能使用${},因为表名不能加单引号

    1. /**
    2. * 查询指定表中的数据
    3. * @param tableName
    4. * @return java.util.List<com.atguigu.mybatis.pojo.User>
    5. * @date 2022/2/27 14:41
    6. */
    7. List<User> getUserByTable(@Param("tableName") String tableName);
    1. <!--List<User> getUserByTable(@Param("tableName") String tableName);-->
    2. <select id="getUserByTable" resultType="User">
    3. select * from ${tableName}
    4. </select>

    添加功能获取自增的主键

  • 在mapper.xml中设置两个属性

    • useGeneratedKeys:设置使用自增的主键
    • keyProperty:因为增删改有统一的返回值是受影响的行数,因此只能将获取的自增的主键放在传输的参数user对象的某个属性中

      1. /**
      2. * 添加用户信息
      3. * @param user
      4. * @date 2022/2/27 15:04
      5. */
      6. void insertUser(User user);
      1. <insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
      2. insert into user values (null,#{username},#{password})
      3. </insert>
      1. public void test() throws IOException {
      2. InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
      3. SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
      4. SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
      5. SqlSession sqlSession = sqlSessionFactory.openSession(true);
      6. UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
      7. //添加功能获取自增的主键
      8. User user1 = new User();
      9. user1.setUserName("测试");
      10. user1.setPassWord("测试");
      11. userMapper.insertUser(user1);
      12. int idKey = user1.getId();
      13. System.out.println("主键:" + idKey);
      14. }

      自定义映射resultMap

      resultMap处理字段和属性的映射关系

  • resultMap:设置自定义映射

    • 属性:
      • id:表示自定义映射的唯一标识,不能重复
      • type:查询的数据要映射的实体类的类型
    • 子标签:
      • id:设置主键的映射关系
      • result:设置普通字段的映射关系
      • 子标签属性:
        • property:设置映射关系中实体类中的属性名
        • column:设置映射关系中表中的字段名
  • 若字段名和实体类中的属性名不一致,则可以通过resultMap设置自定义映射,即使字段名和属性名一致的属性也要映射,也就是全部属性都要列出来

    1. <resultMap id="userMap" type="User">
    2. <id property="id" column="id"></id>
    3. <result property="userName" column="user_name"></result>
    4. <result property="passWord" column="pass_word"></result>
    5. </resultMap>
    6. <!--List<Emp> getAllEmp();-->
    7. <select id="getAllUsers" resultMap="userMap">
    8. select * from user
    9. </select>
  • 若字段名和实体类中的属性名不一致,但是字段名符合数据库的规则(使用_),实体类中的属性名符合Java的规则(使用驼峰)。此时也可通过以下两种方式处理字段名和实体类中的属性的映射关系

    1. 可以通过为字段起别名的方式,保证和实体类中的属性名保持一致

      1. <select id="getAllUsers" resultType="User">
      2. select userName,passWord from user
      3. </select>
    2. 可以在MyBatis的核心配置文件中的setting标签中,设置一个全局配置信息mapUnderscoreToCamelCase,可以在查询表中数据时,自动将_类型的字段名转换为驼峰,例如:字段名user_name,设置了mapUnderscoreToCamelCase,此时字段名就会转换为userName。

      多对一映射处理

      查询员工信息以及员工所对应的部门信息

  1. public class Emp {
  2. private Integer eid;
  3. private String empName;
  4. private Integer age;
  5. private String sex;
  6. private String email;
  7. private Dept dept;
  8. //...构造器、get、set方法等
  9. }

级联方式处理映射关系

  1. <resultMap id="empAndDeptResultMapOne" type="Emp">
  2. <id property="eid" column="eid"></id>
  3. <result property="empName" column="emp_name"></result>
  4. <result property="age" column="age"></result>
  5. <result property="sex" column="sex"></result>
  6. <result property="email" column="email"></result>
  7. <result property="dept.did" column="did"></result>
  8. <result property="dept.deptName" column="dept_name"></result>
  9. </resultMap>
  10. <!--Emp getEmpAndDept(@Param("eid")Integer eid);-->
  11. <select id="getEmpAndDept" resultMap="empAndDeptResultMapOne">
  12. select * from t_emp left join t_dept on t_emp.eid = t_dept.did where t_emp.eid = #{eid}
  13. </select>

使用association处理映射关系

  • association:处理多对一的映射关系
  • property:需要处理多对的映射关系的属性名
  • javaType:该属性的类型

    1. <resultMap id="empAndDeptResultMapTwo" type="Emp">
    2. <id property="eid" column="eid"></id>
    3. <result property="empName" column="emp_name"></result>
    4. <result property="age" column="age"></result>
    5. <result property="sex" column="sex"></result>
    6. <result property="email" column="email"></result>
    7. <association property="dept" javaType="Dept">
    8. <id property="did" column="did"></id>
    9. <result property="deptName" column="dept_name"></result>
    10. </association>
    11. </resultMap>
    12. <!--Emp getEmpAndDept(@Param("eid")Integer eid);-->
    13. <select id="getEmpAndDept" resultMap="empAndDeptResultMapTwo">
    14. select * from t_emp left join t_dept on t_emp.eid = t_dept.did where t_emp.eid = #{eid}
    15. </select>

    分步查询

    1. 查询员工信息

  • select:设置分布查询的sql的唯一标识(namespace.SQLId或mapper接口的全类名.方法名)

  • column:设置分步查询的条件

    1. //EmpMapper里的方法
    2. /**
    3. * 通过分步查询,员工及所对应的部门信息
    4. * 分步查询第一步:查询员工信息
    5. * @param
    6. * @return com.atguigu.mybatis.pojo.Emp
    7. * @date 2022/2/27 20:17
    8. */
    9. Emp getEmpAndDeptByStepOne(@Param("eid") Integer eid);
    1. <resultMap id="empAndDeptByStepResultMap" type="Emp">
    2. <id property="eid" column="eid"></id>
    3. <result property="empName" column="emp_name"></result>
    4. <result property="age" column="age"></result>
    5. <result property="sex" column="sex"></result>
    6. <result property="email" column="email"></result>
    7. <association property="dept"
    8. select="com.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
    9. column="did"></association>
    10. </resultMap>
    11. <!--Emp getEmpAndDeptByStepOne(@Param("eid") Integer eid);-->
    12. <select id="getEmpAndDeptByStepOne" resultMap="empAndDeptByStepResultMap">
    13. select * from t_emp where eid = #{eid}
    14. </select>

    2. 查询部门信息

    1. //DeptMapper里的方法
    2. /**
    3. * 通过分步查询,员工及所对应的部门信息
    4. * 分步查询第二步:通过did查询员工对应的部门信息
    5. * @param
    6. * @return com.atguigu.mybatis.pojo.Emp
    7. * @date 2022/2/27 20:23
    8. */
    9. Dept getEmpAndDeptByStepTwo(@Param("did") Integer did);
    1. <!--此处的resultMap仅是处理字段和属性的映射关系-->
    2. <resultMap id="EmpAndDeptByStepTwoResultMap" type="Dept">
    3. <id property="did" column="did"></id>
    4. <result property="deptName" column="dept_name"></result>
    5. </resultMap>
    6. <!--Dept getEmpAndDeptByStepTwo(@Param("did") Integer did);-->
    7. <select id="getEmpAndDeptByStepTwo" resultMap="EmpAndDeptByStepTwoResultMap">
    8. select * from t_dept where did = #{did}
    9. </select>

    一对多映射处理

    1. public class Dept {
    2. private Integer did;
    3. private String deptName;
    4. private List<Emp> emps;
    5. //...构造器、get、set方法等
    6. }

    collection

  • collection:用来处理一对多的映射关系

  • ofType:表示该属性对饮的集合中存储的数据的类型

    1. <resultMap id="DeptAndEmpResultMap" type="Dept">
    2. <id property="did" column="did"></id>
    3. <result property="deptName" column="dept_name"></result>
    4. <collection property="emps" ofType="Emp">
    5. <id property="eid" column="eid"></id>
    6. <result property="empName" column="emp_name"></result>
    7. <result property="age" column="age"></result>
    8. <result property="sex" column="sex"></result>
    9. <result property="email" column="email"></result>
    10. </collection>
    11. </resultMap>
    12. <!--Dept getDeptAndEmp(@Param("did") Integer did);-->
    13. <select id="getDeptAndEmp" resultMap="DeptAndEmpResultMap">
    14. select * from t_dept left join t_emp on t_dept.did = t_emp.did where t_dept.did = #{did}
    15. </select>

    分步查询

    1. 查询部门信息

    1. /**
    2. * 通过分步查询,查询部门及对应的所有员工信息
    3. * 分步查询第一步:查询部门信息
    4. * @param did
    5. * @return com.atguigu.mybatis.pojo.Dept
    6. * @date 2022/2/27 22:04
    7. */
    8. Dept getDeptAndEmpByStepOne(@Param("did") Integer did);
    1. <resultMap id="DeptAndEmpByStepOneResultMap" type="Dept">
    2. <id property="did" column="did"></id>
    3. <result property="deptName" column="dept_name"></result>
    4. <collection property="emps"
    5. select="com.atguigu.mybatis.mapper.EmpMapper.getDeptAndEmpByStepTwo"
    6. column="did"></collection>
    7. </resultMap>
    8. <!--Dept getDeptAndEmpByStepOne(@Param("did") Integer did);-->
    9. <select id="getDeptAndEmpByStepOne" resultMap="DeptAndEmpByStepOneResultMap">
    10. select * from t_dept where did = #{did}
    11. </select>

    2. 根据部门id查询部门中的所有员工

    1. /**
    2. * 通过分步查询,查询部门及对应的所有员工信息
    3. * 分步查询第二步:根据部门id查询部门中的所有员工
    4. * @param did
    5. * @return java.util.List<com.atguigu.mybatis.pojo.Emp>
    6. * @date 2022/2/27 22:10
    7. */
    8. List<Emp> getDeptAndEmpByStepTwo(@Param("did") Integer did);
    1. <!--List<Emp> getDeptAndEmpByStepTwo(@Param("did") Integer did);-->
    2. <select id="getDeptAndEmpByStepTwo" resultType="Emp">
    3. select * from t_emp where did = #{did}
    4. </select>

    延迟加载

  • 分步查询的优点:可以实现延迟加载,但是必须在核心配置文件中设置全局配置信息:

    • lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载
    • aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。 否则,每个属性会按需加载
  • 此时就可以实现按需加载,获取的数据是什么,就只会执行相应的sql。此时可通过association和collection中的fetchType属性设置当前的分步查询是否使用延迟加载,fetchType=”lazy(延迟加载)|eager(立即加载)”

    1. <settings>
    2. <!--开启延迟加载-->
    3. <setting name="lazyLoadingEnabled" value="true"/>
    4. </settings>
    1. @Test
    2. public void getEmpAndDeptByStepOne() {
    3. SqlSession sqlSession = SqlSessionUtils.getSqlSession();
    4. EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
    5. Emp emp = mapper.getEmpAndDeptByStepOne(1);
    6. System.out.println(emp.getEmpName());
    7. }
  • 关闭延迟加载,两条SQL语句都运行了延迟加载测试1.png

  • 开启延迟加载,只运行获取emp的SQL语句
    延迟加载测试2.png

    1. @Test
    2. public void getEmpAndDeptByStepOne() {
    3. SqlSession sqlSession = SqlSessionUtils.getSqlSession();
    4. EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
    5. Emp emp = mapper.getEmpAndDeptByStepOne(1);
    6. System.out.println(emp.getEmpName());
    7. System.out.println("----------------");
    8. System.out.println(emp.getDept());
    9. }
  • 开启后,需要用到查询dept的时候才会调用相应的SQL语句延迟加载测试3.png

  • fetchType:当开启了全局的延迟加载之后,可以通过该属性手动控制延迟加载的效果,fetchType=”lazy(延迟加载)|eager(立即加载)”

    1. <resultMap id="empAndDeptByStepResultMap" type="Emp">
    2. <id property="eid" column="eid"></id>
    3. <result property="empName" column="emp_name"></result>
    4. <result property="age" column="age"></result>
    5. <result property="sex" column="sex"></result>
    6. <result property="email" column="email"></result>
    7. <association property="dept"
    8. select="com.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
    9. column="did"
    10. fetchType="lazy"></association>
    11. </resultMap>

    QBC

    查询

  • selectByExample:按条件查询,需要传入一个example对象或者null;如果传入一个null,则表示没有条件,也就是查询所有数据

  • example.createCriteria().xxx:创建条件对象,通过andXXX方法为SQL添加查询添加,每个条件之间是and关系

    1. @Test public void testMBG() throws IOException {
    2. InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
    3. SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
    4. SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
    5. SqlSession sqlSession = sqlSessionFactory.openSession(true);
    6. EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
    7. EmpExample example = new EmpExample();
    8. //名字为张三,且年龄大于等于20
    9. example.createCriteria().andEmpNameEqualTo("张三").andAgeGreaterThanOrEqualTo(20);
    10. //或者did不为空
    11. example.or().andDidIsNotNull();
    12. List<Emp> emps = mapper.selectByExample(example);
    13. emps.forEach(System.out::println);
    14. }

    增改

  • updateByPrimaryKey:通过主键进行数据修改,如果某一个值为null,也会将对应的字段改为null

    • mapper.updateByPrimaryKey(new Emp(1,"admin",22,null,"456@qq.com",3));
  • updateByPrimaryKeySelective():通过主键进行选择性数据修改,如果某个值为null,则不修改这个字段
    • mapper.updateByPrimaryKeySelective(new Emp(2,"admin2",22,null,"456@qq.com",3));