Mybatis记单词

发布时间:2024年01月14日

(一)Mybatis

1.1 全局配置文件mybatis-config.xml

1、在resources文件夹下新建mybatis-config.xml和db.properties,mybatis-config.xml引入db.properties中关于数据库的配置:

<properties resource="db.properties"/>

然后用<environments标签里面将对应的driver、url、username、password注入。
2、设置驼峰(例如:sql查询属性名:last_name -> 实体类的属性名:lastName)

<settings>
   <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

3、为实体类起别名(自动转换大小写)

	<typeAliases>
        <!--第一种方式:-->
        <!--<typeAlias type="com.atguigu.bean.Employee" alias="emp"/>
        <typeAlias type="com.atguigu.bean.Department" alias="Department"/>-->

        <!--第二种方式:省略alias属性,别名默认就是类名-->
        <!--<typeAlias type="com.atguigu.bean.Employee"/>
        <typeAlias type="com.atguigu.bean.Department"/>-->

        <!--第三种方式 ★:指定包下的所有实体类,都会起别名为类名-->
        <package name="com.atguigu.bean"/>
    </typeAliases>

4、插件(以分页插件为例,先在pom.xml中导入相关依赖,然后就到mybatis-config.xml中进行配置)

<plugins>
    <!--添加分页插件:自动将分页的sql语句,添加到sql语句中 interceptor:分页插件核心类的全类名 -->
    <plugin interceptor="com.github.pagehelper.PageInterceptor">
          <!-- 设置数据库类型  Oracle,Mysql,MariaDB,SQLite,Hsqldb,PostgreSQL 六种数据库-->
           <property name="helperDialect" value="Mysql"/>
    </plugin>
</plugins>

那么在测试类中:

//pageNum:从第几页开始   pageSize:一页多少条数据
Page page = PageHelper.startPage(2, 3);//直接存放到Page对象中,从第2页开始,每页3条数据
//测试page对象
//(1)当前是第几页
int pageNum = page.getPageNum();
//(2)一页有多少条数据
int pageSize = page.getPageSize();
//(3)总页数:一共有多少页
int pages = page.getPages();
//(4)总条数:符合查询条件的总条数
long total = page.getTotal();
//(5)当前页开始的行
int startRow = page.getStartRow();
//(6)当前页结束的行
int endRow = page.getEndRow();

//测试PageInfo对象
//创建PageInfo对象:将查询结果employees对象传入进行创建
PageInfo<Employee> pageInfo = new PageInfo(employees, 3);//navigatePages为3,意思是前端一次只展示3个导航页面:1,2,3或者2,3,4以此类推
//(1)直接显示查询列表
List<Employee> list = pageInfo.getList();//查询结果
System.out.println(list);//需要重写Employee类的toString方法
list.stream().forEach(System.out::println);//在页面端直接遍历拿结果
//(2)前一页的页码
int prePage = pageInfo.getPrePage();
//(3)下一页的页码
int nextPage = pageInfo.getNextPage();
//(4)是否有上一页
boolean hasPreviousPage = pageInfo.isHasPreviousPage();
//(5)是否有下一页
boolean hasNextPage = pageInfo.isHasNextPage();
//(6)是否是第一页
boolean isFirstPage = pageInfo.isIsFirstPage();
//(7)是否是最后一页
boolean isLastPage = pageInfo.isIsLastPage();
//(8)当前状态下导航页的页码
int[] navigatepageNums = pageInfo.getNavigatepageNums();
System.out.println("navigatepageNums = " + Arrays.toString(navigatepageNums));//Arrays.toString()将数组转换成字符串

5、加载映射文件

	<mappers>
        <!--方式一:单个文件进行加载-->
<!--        <mapper resource="EmployeeDao.xml"/>-->
        <!--方式二:将指定包下的接口和映射文件进行加载
            条件:持久层接口和映射文件->同包同名
        -->
        <package name="com.atguigu.dao"/>
    </mappers>

常用方式二,但是要求接口和映射文件同包同名,例如,在com.atguigu.dao文件夹下新建EmployeeDao接口,我们写的EmployeeDao.xml就要放到相同包中,在resources文件夹下新建目录com/atguigu/dao,将EmployeeDao.xml放到这个dao文件夹下。

1.2 映射文件XXDao.xml

自动映射
1、增
如果想要获取/自动返回自增主键,在对应的xml文件中的sql语句前缀加上useGeneratedKeys=“true” keyProperty="id"两个属性(这里是将id作为自增主键)。

<!--int insert(Employee employee);-->
<!--useGeneratedKeys:是否自动返回自增主键
    keyProperty:将自增的主键,设置到参数的哪个属性上(并不是以返回值的形式返回的),这里绑定的是id属性-->
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
    insert into employees values(null,'${lastName}','${email}',${gender},${salary},${deptId})
</insert>

在控制类中的代码就这样写:

Employee employee=new Employee(null,"胖东来","pangdonglai@163.com",1,8888.0,2);
employeeDao.insert(employee);
System.out.println(employee.getId());//新增完后输出employee对象,可以直接用getId,getEmail等,因为xml中绑定了keyProperty="id"

2、删

<!--int delete(Integer id);-->
<delete id="delete">
    delete from employees where id=#{id}
</delete>

3、改

<!--int update(Employee employee);-->
<update id="update">
    update employees set
    last_name=#{lastName},email=#{email},gender=#{gender},salary=#{salary},dept_id=#{deptId}
    where id=#{id}
</update>

4、查
(1)传入一个参数时

<!--List<Employee> getByLastName(String name);-->
<select id="getByLastName" resultType="Employee">
    select * from employees where last_name like concat('%',#{abc},'%')
</select>

(2)传入多个参数时
一般情况:

<!--List<Employee> getByNameAndSalary(String name,Double salary);
    多个普通参数:将多个参数存放在一个Map集合内的value值上,key值是什么?[arg0,arg1,param1,param2]
    param1~paramn
    arg0~argn
    第一个参数#{}里面可以写param1/arg0 第二个参数#{}里面可以写param2/arg1
    -->
<select id="getByNameAndSalary" resultType="Employee">
    select * from employees where last_name like concat('%',#{param1},'%') and salary>#{arg1}
</select>

有命名参数时,例如name属性需要赋给lastName:

<!-- List<Employee> getByNameAndSalary(@Param("lastName") String name, Double salary);
        命名参数:变成了[lastName,arg1,param1,param2]
        第一个参数#{}里面只能写param1/lastName 第二个参数#{}里面可以写param2/arg1
        想一想:如果第二个salary也被命名为Salary呢?-这时变成了[lastName,Salary,param1,param2]
               那么第一个参数#{}里面只能写param1/lastName 第二个参数#{}里面可以写param2/Salary
    -->
<select id="getByNameAndSalary" resultType="Employee">
    select * from employees where last_name like concat('%',#{lastName},'%') and salary>#{arg1}
</select>

(3)传入参数是javabean实体类
可以#{对象的属性名},它会直接调取实体类的get方法:

<!--List<Employee> getByEmployee(Employee employee);  -->
    <select id="getByEmployee" resultType="Employee">
        select * from employees where last_name = #{lastName} and salary=#{salary}
    </select>

(4)传入参数是Map

<!--List<Employee> getByMap(Map map);
        #{map的key值}
    -->
<select id="getByMap" resultType="Employee">
   select * from employees where last_name = #{name} and salary=#{salary}
</select>

因为我们在MyBatisTest中是这么定义的:(传入的key分别是name和salary)

	   Map map=new HashMap();
       map.put("name","胖东来666");
       map.put("salary","88888");
       List<Employee> emps = employeeDao.getByMap(map);
       emps.stream().forEach(System.out::println);

(5)返回类型是Map
查询单行数据返回Map集合:

<!--Map<String,Object> getByIdReturnMap(Integer id);
        数据库中字段名-key  数据库中字段值-value       map是别名,它在typeAlias中已经被定义了
    -->
<select id="getByIdReturnMap" resultType="map">
   select * from employees where id=#{id}
</select>

那么我们在MyBatisTest中进行测试:

Map<String, Object> map = employeeDao.getByIdReturnMap(2);
System.out.println(map);//可以直接输出map,但是是无序的

查询多行数据返回Map集合:
在EmployeeDao接口中定义:用注解的方式指定id列作为key,其数据类型是Integer

@MapKey("id")
Map<Integer,Employee> getAllReturnMap();

在sql语句的xml中:

<!--@MapKey("id")
    Map<Integer,Employee> getAllReturnMap();
    返回的类型还是Employee,因为返回的value是Employee对象-->
<select id="getAllReturnMap" resultType="Employee">
   select * from employees
</select>

我们在MyBatisTest中进行测试:

Map<Integer, Employee> allReturnMap = employeeDao.getAllReturnMap();
Set<Map.Entry<Integer, Employee>> entries = allReturnMap.entrySet();
for (Map.Entry<Integer, Employee> entry : entries) {
    System.out.println( entry); 
}

手动映射
1、需要手动映射的情况:
①查询结果的字段名和pojo的属性名不一致,且不满足自动驼峰
②如果出现多表查询,会有对象关联情况出现,使用手动映射比较方便
2、对于情况①
(1)创建resultMap标签(就是让开发者规定,sql语句的字段名对应pojo中的哪个属性)
id: 随意起名,唯一标识 type: 指定你要为哪个pojo做手动映射关系
在EmployeeDao.xml中:property表示映射在Employee实体类中属性名–column表示其在employees表中的列名

		<resultMap id="empYingShe" type="Employee">
          <!--主键-->
          <id property="id" column="id"></id>
          <!--非主键-->
          <result property="name" column="last_name"></result>
          <result property="email" column="email"></result>
          <result property="gender" column="gender"></result>
          <result property="salary" column="salary"></result>
          <result property="deptId" column="dept_id"></result>
      </resultMap>

(2)将select标签中的resultType属性换成resultMap属性,并且将resultMap标签的id属性值设置给resultMap属性
也就是说,其中的select语句的resultMap要改为empYingShe:

 <select id="getById" resultMap="empYingShe">
     select * from employees where id=#{id}
</select>

3、对于情况②
一对多:查询名叫“胖东来”的员工信息(包括职位信息),
sql语句应该为:

SELECT employees.*,departments.id did,departments.name 
FROM employees 
LEFT JOIN departments
ON employees.`dept_id`=departments.`id` 
WHERE last_name=“胖东来”

方式1–两表联查
(1) 创建resultMap标签,id=“empMap01”

<resultMap id="empMap01" type="Employee01">
          <!--对employees表的属性定义-->
          <id property="id" column="id"></id>
          <result property="name" column="last_name"></result>
          <result property="email" column="email"></result>
          <result property="gender" column="gender"></result>
          <result property="salary" column="salary"></result>

          <!--将sql语句中部门的数据,映射到employee01对象中的department对象内-->
          <!--对一的关系:association
              property:关联对象的属性名(我们在Employee01实体类中定义的Department类对象的名字)
              javaType:关联对象的类型(使用的是别名,不然的话要写全类名)
          -->
          <association property="department" javaType="Department">
              <!--(下面是对Department表中的两个属性进行定义)-->
              <id property="id" column="did"></id>
              <result property="name" column="name"></result>
          </association>
      </resultMap>

(2)再多表联查

<select id="getByName" resultMap="empMap01">
   SELECT employees.*,departments.id did,departments.name FROM employees LEFT JOIN departments
   ON employees.`dept_id`=departments.`id`
   WHERE last_name=#{name}
</select>

方式2–分布查询
要求查询id=2的部门内的所有员工信息。
sql语句:第一次查询:select * from departments where id=2;
第二次查询:select * from employees where dept_id=2;
(1)在Department01Dao.xml中:

<resultMap id="deptMap02" type="Department01">
     <!--departments表-->
     <id property="id" column="dept_id"></id>
     <result property="name" column="name"></result>
     <!--对多的处理 -employees表
         property:设置需要处理的集合属性名(在Department01实体类中定义的List<Employee> emps;名称为emps)
         ofType:指定集合内泛型的类型(在Department01实体类中定义的List<Employee> emps;列表泛型是Employee)
         select:调用方法,发送第二条sql语句(根据部门的id查找所有员工信息)
         column:第一条sql语句中哪一列的值,传递到第二条sql语句中作为查询条件
           -->
        <collection property="emps" ofType="Employee"
                select="com.atguigu.dao.EmployeeDao.getByDeptId"
                column="id">
        </collection>
</resultMap>

并写第一条sql语句:(用resultMap联系起来)

<select id="getById" resultMap="deptMap02">
    SELECT * FROM departments WHERE id=#{id}
</select>

(2)然后到EmployeeDao.xml中:

<select id="getByDeptId" resultType="Employee">
    SELECT * FROM employees WHERE dept_id=#{deptId}
</select>

拓展:在分布查询中,上面是将第一条sql语句中的第一列传到第二条sql语句作为查询条件,如果多列怎么办?
模拟:查询部门信息,将id这一列和name这一列的值传到第二条sql语句。
(1)在Department01Dao.xml中的collection标签修改:将id和name都传给getByDeptId方法。

<resultMap id="deptMap02" type="Department01">
     <!--departments表-->
     <id property="id" column="dept_id"></id>
     <result property="name" column="name"></result>
        <collection property="emps" ofType="Employee"
               select="com.atguigu.dao.EmployeeDao.getByDeptId"
               column="idkey=id,namekey=name">
        </collection>
</resultMap>

并写第一条sql语句:(用resultMap联系起来)

<select id="getById" resultMap="deptMap02">
    SELECT * FROM departments WHERE id=#{id}
</select>

(2)在EmployeeDao.xml中:

<select id="getByDeptId" resultType="Employee">
    SELECT * FROM employees WHERE dept_id=#{idkey} and last_name=#{namekey}
</select>

1.3 动态sql

1、where标签
if?标签
?????test属性:条件 ??原理:条件成立则拼接if内的sql语句,否则不拼接
where?标签
?????如果有if是成立的,会加where关键字,反之就不加
?????如果where后多一个and,会自动去除该语句最前面的and,如果and写在该语句的最后面,不会自动去除。

<!--List<Employee> getByMap(Map map);-->
    <select id="getByMap" resultType="Employee">
        select * from employees
        <where>
            <if test="name!=null and name!=''">
                and last_name like concat('%',#{name},'%')
            </if>
            <if test="salary!=null and salary!=''">
                and salary>#{salary}
            </if>
            <if test="deptId!=null and deptId!=''">
                and dept_id=#{deptId}
            </if>
        </where>
    </select>

在Employee01Test的testQuery01()方法中,将查询条件存入Map集合,然后调用getByMap()方法进行sql语句拼接:

Map<String, Object> map = new HashMap<>();
map.put("name","胖东来");//名字中含有"胖东来"的
map.put("salary",8888.0);//工资salary>8888.0的
map.put("deptId",2);//部门编号dept_id=2的
List<Employee> emps = employeeDao.getByMap(map);
emps.stream().forEach(System.out::println);

2、trim标签
????prefix 添加前缀 suffix 添加后缀
????prefixOverrides 去除前缀 suffixOverrides 去除后缀
??需求:如果有if成立,添加一个where的前缀(prefix=“where”),如果前面多一个and,去除前面的and(prefixOverrides=“and”)。

	<select id="getByMap1" resultType="Employee">
        select * from employees
        <trim prefix="where" prefixOverrides="and">
            <if test="name!=null and name!=''">
                and last_name like concat('%',#{name},'%')
            </if>
            <if test="salary!=null and salary!=''">
                and salary>#{salary}
            </if>
            <if test="deptId!=null and deptId!=''">
                and dept_id=#{deptId}
            </if>
        </trim>
    </select>

3、set标签
如果有if成立,则会添加set关键字(要保证set关键字必须添加)
会自动去除前后多出来的逗号

<!--int update(Employee employee);
    需求:如果参数中的last_name和email为null的话,就不修改这一列的信息-->
    <update id="update">
        update employees
        <set>
            <!--如果last_name和email都为空会报错(因为set这个词没有了),所以保留这个id=id(因为id为主键)相当于执行无用操作,是为了保证set关键字必须加上-->
            <if test="true">
                id=#{id},<!--当然也可以换成1=1,只要保证保留set关键字就行-->
            </if>
            <if test="lastName!=null">
                last_name=#{lastName},
            </if>
            <if test="email!=null">
                email=#{email},
            </if>
        </set>
        where id=#{id}
    </update>

测试:

Employee employee = new Employee(1,null,"huahua@qq.com",1,2000.0,2);
employeeDao.update(employee);

4、choose选择结构
????when 可以有多个
????otherwise 只有一个
????原理:从上往下判断是否有成立的条件,如果有一个when成立(被用户发起该条件)则拼接sql语句,后面不走了,只拼接一条;否则往下执行,如果还是没有拼到,就拼otherwise里面的语句。

	<select id="getByMap2" resultType="Employee">
        select * from employees
        <trim prefix="where" suffixOverrides="and">
            <choose>
                <when test="name!=null and name!=''">
                    last_name like concat('%',#{name},'%') and
                </when>
                <when test="salary!=null and salary!=''">
                    salary>#{salary} and
                </when>
                <when test="deptId!=null and deptId!=''">
                    dept_id=#{deptId}
                </when>
                <otherwise>
                    gender=1
                </otherwise>
            </choose>
        </trim>
    </select>

5、foreach:循环ids集合内的数据
??????collection:表明参数是什么(集合的话就是list,数组的话就是array)-这都是定义好了的别名
??????open:循环前置内容 close:循环后置内容
??????spearator:分割符??? item:变量名(自定义的)
??????index:自定义一个名字,通过这个名字可以获取到本次循环的索引
??应用位置:传入参数是集合或数组

<select id="getByIds" resultType="Employee">
     select * from employees where id in
     <foreach collection="list" open="(" close=")" separator="," item="id" index="i"><!--i=0,1,2,3;id=2,5,8,11-->
          #{id}
    </foreach>
</select>

测试–查找员工id为2,5,8,11的员工信息

List<Integer> ids = new ArrayList<>();
ids.add(2);
ids.add(5);
ids.add(8);
ids.add(11);
List<Employee> emps = employeeDao.getByIds(ids);
emps.stream().forEach(System.out::println);

6、sql标签:提取当前重复的sql片段,便于维护。
在EmployeeDao.xml中:将重复片段定义为“select01”。

<sql id="select01">
   SELECT * FROM employees
</sql>

那么在需要使用该片段时就用<include refid=“select01”></include>替代该片段的代码:

<select id="getByDeptId" resultType="Employee">
    <include refid="select01"></include>
    WHERE dept_id=#{deptId}
</select>

7、补充:条件语句中and可以用&amp;&amp;代替。''可以用&apos;&apos;代替。

<when test="name!=null and name!=''">  等价于 
<when test="name!=null &amp;&amp; name!=&apos;&apos;">

另外,Mybatis还有延迟加载、缓存机制和逆向工程(Mybatis03中介绍)。这里只做简单介绍:
(1)设置延迟加载只对day3中多表查询的分步查询有效:如果只使用员工信息employees表不使用部门信息department,那么只会发送第一条sql语句;
当用户需要使用departmrnt表的信息时,才会发送第二条sql语句。
(2)当再次发起相同的查询请求时,MyBatis不会再发送一次sql语句,会直接从缓存中调取上次的查询结果,即缓存。
(3)逆向工程可以快速根据数据库表生成对应的映射文件、接口类及bean类。支持基本的增删改查,以及QBC风格的条件查询。
在mybatis-config.xml中配置dao映射文件位置,运行即可生成对应main下的java文件夹下的com.atguigu.mbg文件夹及里面的bean类,dao类,以及resources文件夹下的com.atguigu.mbg.dao文件夹及里面的映射文件。

文章来源:https://blog.csdn.net/qq_44629163/article/details/135567129
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。