回顾:
1. mybatis的介绍.
mybatis的好处:
是一个半自动化的ORM框架.
动态sql.
映射返回结果的一对多,多对一.
性能优化,一级缓存,二级缓存,懒加载.
简单易学,轻量级.
mybatis和hibernate的区别: spring-data-jpa
2. mybatis的入门.
1. 创建项目. -> jar
2. 导入依赖.
mybatis,mysql-connector-java,lombok,junit
3. 准备数据库和实体类. (dao层框架)
... POJOs脚本文件-> 二阶段你没听课.
4. 编写配置文件.
mybatis-config.xml.
1. 写xml文件的头.
2. 导入mybatis的DTD约束.
3. 跟标签. <configuration>
4. 环境. <environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC|MANAGED" />
<dataSource type="POOLED|UNPOOLED|JNDI">
<property name="driver" value=".." />
<property name="url" value=".." />
<property name="username" value=".." />
<property name="password" value=".." />
</dataSource>
</environment>
</environments>
5. 引入映射文件. <mappers>
<mapper resource="相对java|resources的路径" />
</mappers>
映射文件.xml
1. 写xml文件的头.
2. 导入mybatis的DTD约束.
3. 跟标签. <mapper namespace="映射文件的唯一标识">
4. 编写CRUD.
<select id="sql的唯一标识" resultType="返回结果">
sql语句.
</select>
5. 测试.
1. InputSteam is = Resources.getResourcesAsStream("resource");
2. SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
3. SqlSession sqlSession = factory.openSession();
4. sqlSession.selectOne(映射文件唯一标识.SQL语句唯一标识);
Too Many Results Exception
3. 日志框架的选择.
日志框架的要求:
1. 将日志输出到当前系统的本地文件中.
2. 区别输出日志信息类别.
3. 定制输出的格式.
4. 通过外部的配置文件随意的修改日志的信息.
5. 一日一日志.
6. 优异的性能.
挑选日志框架:
日志的门面 日志的实现
commons-logging JUL
SLF4J log4j
jboss-logging log4j2
logback
导入SLF4J和logback的依赖.
...
赋值logback.xml的日志配置文件.
...
编写日志信息.
@Slf4j
log.error|info|debug
4. 基于Mapper接口实现mybatis.
1. 接口名和映射文件名保持一致.
2. 映射文件的namespace属性写接口的全路径.
3. 接口的抽象方法要和映射的sql/标签一一对应.
4. 放在同一目录下.(不是硬性要求)
5. 核心配置文件的详解.
1. properties
引入外部的properties文件,内部通过${key}
2. settings.
配置mybatis运行时的环境 -> 驼峰映射....
3. typeAliases
别名.
4. plugins.
.. 分页助手.
5. environments
环境.
6. mappers
<mappers>
<mapper resource|url|class="" />
扫描映射文件
<package name="包名" />
</mappers>
6. 核心API详解.
SqlSessionFactoryBuilder
SqlSessionFactory
SqlSession
Executor
一. mybatis的CRUD.
1. select.
1. 根据年龄做等值判断.
select * from user where age = #{age}
select * from user where age = ${value}
-> parameterType映射抽象方法的参数类型.
-> #{} 和 ${}的区别. (面试题)
1. 当传入一个参数时, #{随便写},${value}(3.5.2以下的版本必须写value)
2. #{}可以防止sql注入, ${}sql的字符串拼接.
2. 根据名称做模糊查询.
select * from user where name like "%"#{name}"%"
select * from user where name like concat('%',#{name},'%')
-> 因为#{}防止sql注入,会将传入的值用单引号包起来,导致直接拼接%会失效.
"%"#{值}"%"
concat('%',#{值},'%')
3. 根据名称做模糊查询并且根据年龄做等值判断.
List<User> findByNameLikeAndAge(String name,Integer age);
由于传入了多个且类型不一致的参数,导致parameterType无法声明.
三种解决方案:
1. 采用注解传参.
List<User> findByNameLikeAndAge(@Param("name") String name,@Param("a") Integer age);
<select id="findByNameLikeAndAge" resultType="User" >
select * from user where name like "%"#{name}"%" and age = #{a}
</select>
2. 采用POJO类传参.
List<User> findByNameLikeAndAgeForUser(User user);
<select id="findByNameLikeAndAgeForUser" resultType="User" parameterType="User">
select * from user where name like "%"#{name}"%" and age = #{age}
</select>
3. 采用Map传参.
根据名称做模糊查询并且根据年龄做等值判断同时做分页.
// 根据名称做模糊查询和用户年龄查询分页.
List<User> findByNameLikeAndAgeLimitForMap(Map<String,Object> map);
<select id="findByNameLikeAndAgeLimitForMap" resultType="User" >
select * from user where name like "%"#{user.name}"%" and age = #{user.age} limit #{offset},#{size}
</select>
2. insert
添加一条用户信息.
抽象方法: Integer save(User user);
映射文件: <insert id="save" parameterType="User">
insert into user (name,age,hobby) values (#{name},#{age},#{hobby})
如果主键是自增,获得自增后的主键值.
方式1:
<insert useGeneratedKeys="true" keyProperty="oid(Object id)" >
方式2
<selectKey keyProperty="oid" resultType="Integer">
select LAST_INSERT_ID()
</selectKey>
在添加之后,通过传入的user对象,接收自增后的id.
3. update&delete
update:
抽象方法: Integer updateById(User user);
映射文件: <update id="updateById" parameterType="User">
update user set name = #{name},.... where id = #{id}
</update>
delete:
抽象发放: Integer deleteById(@Param("id") Integer id);
映射文件: <delete id="deleteById" >
delete from user where id = #{id}
</delete>
二. ResultMap的使用.
当实体类的属性名和关系表的字段名无法自动映射时,采用resultMap手动映射.
<select resultMap="唯一标识">
<resultMap id="唯一标识" type="抽象方法的返回值类型." >
<id property="属性名" column="字段名" />
<result property="属性名" column="字段名" />
</resultMap>
mybatis默认开启了自动映射,resultMap只编写无法自动映射的属性和字段即可.
(当返回值类型设计到了一对多/多对一映射时,默认映射级别PARTIAL无法自动映射)
三. 一对多和多对一.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y5Ao0MUH-1573006317909)(img/1569487180009.png)]
1. 多对一.
R:
关系表维护关系靠的是外键
O:
一的一方的类对象.
M:
ResultMap -> 映射sql语句的返回结果.
<resultMap id="shoeAndBrandResultMap" type="Shoe">
<!--映射oid和普通字段-->
<id property="id" column="id" />
<result property="title" column="title" />
<result property="size" column="size" />
<result property="color" column="color" />
<result property="price" column="price" />
<result property="stock" column="stock" />
<!--维护多对一的关系-->
<association property="brand" javaType="Brand" columnPrefix="b_" >
<!--映射oid和普通字段-->
<id property="id" column="id" />
<result property="name" column="name" />
<result property="description" column="description" />
<result property="created" column="created" />
</association>
</resultMap>
<!-- // 根据id查询鞋子和其品牌信息.-->
<!-- Shoe findShoeAndBrandById(@Param("id") Integer id);-->
<select id="findShoeAndBrandById" resultMap="shoeAndBrandResultMap" >
select
s.*,
b.id as b_id,
b.name as b_name,
b.description as b_description,
b.created as b_created
from
shoe s ,
brand b
where
s.brand_id = b.id
and s.id = #{id}
</select>
2. 一对多.
R:
......
O:
// 维护 一 对 多 的关系
private Set<Shoe> shoeSet;
M:
<!-- 封装一对多关系的resultMap-->
<resultMap id="brandAndShoesResultMap" type="Brand">
<id property="id" column="id" />
<result property="name" column="name" />
<result property="description" column="description" />
<result property="created" column="created" />
<!-- 维护一对多关系-->
<collection property="shoeSet" ofType="Shoe" columnPrefix="s_">
<id property="id" column="id" />
<result property="title" column="title" />
<result property="size" column="size" />
<result property="color" column="color" />
<result property="price" column="price" />
<result property="stock" column="stock" />
<result property="state" column="state" />
</collection>
</resultMap>
<!-- // 根据id查询品牌和其对应的全部鞋子.-->
<!-- Brand findBrandAndShoesById(@Param("id") Integer id);-->
<select id="findBrandAndShoesById" resultMap="brandAndShoesResultMap">
select
b.*,
s.id s_id,
s.title s_title,
s.size s_size,
s.color s_color,
s.price s_price,
s.stock s_stock,
s.state s_state
from
brand b inner join shoe s on b.id = s.brand_id
where
b.id = #{id}
</select>
四. 动态sql.
1. if + where
当条件很多,并且可有可无,之前需要手动封装很多个sql,才能完成指定业务.
if -> 可以通过
<if test="条件判断"></if>
如果条件判断返回true -> 添加if标签体内的查询条件.
如果条件判断返回false -> 忽略if标签体内的查询条件.
where -> 将全部查询条件包裹在<where>标签体内.
1. <where>标签体内有查询条件,添加where关键字,
<where>标签体内没有查询条件,不添加where关键字.
2. <where>会去除前缀多余的一个and|or
例子:
<select id="findByCondition" resultType="Shoe" parameterType="Shoe">
select
*
from
shoe
<where>
<if test="title != null and title != ''">
title like "%"#{title}"%"
</if>
<if test="size != null and size != ''">
and size = #{size}
</if>
<if test="color != null and color != ''">
and color = #{color}
</if>
<if test="price != null">
and price = #{price}
</if>
<if test="stock != null and stock >= 0">
and stock = #{stock}
</if>
<if test="state != null and state != ''">
and state = #{state}
</if>
</where>
</select>
2. if + set
当修改的字段变化时,可以使用if+set解决问题.
if(同上)
set
1. 当set标签体内有内容时,添加set关键字.
当set标签体内没有内容时,不添加set关键字.
2. 去除修改内容中后缀多余的一个.
<update id="updateById" parameterType="Shoe" >
update
shoe
<set>
id = #{id},
<if test="title != null and title != ''">
title = #{title},
</if>
<if test="size != null and size != ''">
size = #{size},
</if>
<if test="color != null and color != ''">
color = #{color},
</if>
<if test="price != null">
price = #{price},
</if>
<if test="stock != null and stock >= 0">
stock = #{stock},
</if>
<if test="state != null and state != ''">
state = #{state}
</if>
</set>
where
id = #{id}
</update>
3. if + trim
trim可以代替set或where.
自定义指定代替什么关键字,自定义去除多余的什么前缀和什么后缀.
trim的4个属性.
prefix -> 指定前缀
prefixOverrides -> 去除多余的前缀.
suffix -> 指定后缀
suffixOverrides -> 去除多余的后缀.
4. foreach.
循环遍历.
select * from table where id in (?,?,?,?)
<foreach
collection="array|list|map-key"
open="开始" separator="间隔" close="结束"
item="遍历的值的别名">
#{别名}
</foreach>
select * from table where id in (?,?,?,?)
<select id="findByIdListIn" resultType="shoe">
select * from shoe where id in
<foreach collection="array|list|map-key" open="(" separator="," close=")" item="id">
#{id}
</foreach>
</select>
批量添加.
insert into table (name,age) values (?,?),(?,?),(?,?).....
batchSave(Shoe[] shoeArray);
batchSave(List<Shoe> shoeList);
batchSave(Map<String,Object(传入set集合)> map);
insert into table (name,age) values
<foreach collection="array" separator="," item="shoe">
(#{shoe.name},#{shoe.age})
</foreach>
5. choose + when + otherwise
switch + case + default.
当需要涉及到多个查询条件使用其中一个时,多选一的情况,又动态sql没有提供elseif的功能,为了避免多次判断,采用
choose + when + otherwise的方式.
<select id="findByState" resultType="Shoe">
select * from shoe where
<choose>
<when test="flag == 0">state = 'UP'</when>
<otherwise>state = 'DOWN'</otherwise>
</choose>
</select>
五. mybatis的性能优化.
me},#{shoe.age})
### 5. choose + when + otherwise
```xml
switch + case + default.
当需要涉及到多个查询条件使用其中一个时,多选一的情况,又动态sql没有提供elseif的功能,为了避免多次判断,采用
choose + when + otherwise的方式.
<select id="findByState" resultType="Shoe">
select * from shoe where
<choose>
<when test="flag == 0">state = 'UP'</when>
<otherwise>state = 'DOWN'</otherwise>
</choose>
</select>