MyBatis 基础与使用

1 创建
- 勾选依赖 : MyBaits Framework , MySql Driver;
- resource/application.properties ; 添加数据库信息


1.1 代码提示
- 选中 ‘select * from user’ 右键->显示上下文操作->语言注入设置->选择 Mysql即可, 写代码有提示; 库名和表名一样时表名要全, user.user 只写一个user不行
- 在 idea 中连接数据库后, 表名和字段名也会有提示;
1.2 连接池
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.24</version>
</dependency>
spring.application.name=SpringBootMyBatis
#驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接的url
spring.datasource.url=jdbc:mysql://localhost:3306/user
#连接数据库的用户名
spring.datasource.username=root
#连接数据库的密码
spring.datasource.password=1234
spring.datasource.type = com.alibaba.druid.pool.DruidDataSource
2 lombok
- 框架: 编译时自动生成 getter setter toString…

3 预编译

3.1 sql注入

@Delete("delete from emp where id = #{id}") // 这个是站位, 不会sql注入问题
int delete(Integer id);//返回操作影响的数据
@Delete("delete from emp where id = ${id}") // 这个是拼接, 有sql注入问题
int delete(Integer id);//返回操作影响的数据
4 基础操作
4.1 命名

数据库中 可以使用下划线, 实体类中使用驼峰命名法;
4.2 删除

- Mapper 标记
- 接口
@Autowired
private EmpMapper empMapper;
@Test
public void testDelete(){
System.out.println(empMapper.delete(16));
}
4.3 插入
- 接口类前面要Mapper注解
@Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) "+
"values (#{username},#{name},#{gender},#{image},#{job},#{entrydate},#{deptId},#{createTime},#{updateTime})")
void insert(Emp emp);
public void testInsert(){
Emp emp = new Emp();
emp.setUsername("Tom1");
emp.setName("Tom");
emp.setGender((short)1);
emp.setImage("1.img");
emp.setJob((short)2);
emp.setEntrydate(LocalDate.of(2006,3,4));
emp.setDeptId(1);
emp.setCreateTime(LocalDateTime.now());
emp.setUpdateTime(LocalDateTime.now());
empMapper.insert(emp);
}
4.3.1 插入返回主键

dishMapper.insert(dish);
// xml文件中设置属性回显, useGeneratedKeys="true" keyProperty="id" 返回的值赋值为传入insert的参数dish的id, 再获取属性
Long dishId = dish.getId();
4.4 修改
@Update("update emp set username = #{username},name = #{name},gender = #{gender},image = #{image}, job = #{job}, entrydate = #{entrydate},dept_id = #{deptId}, update_time = #{updateTime} where id = #{id};")
void update(Emp emp);
@Test
public void testUpdate(){
Emp emp = new Emp();
emp.setId(18);
emp.setUsername("update_test");
emp.setName("Tom");
emp.setGender((short)1);
emp.setImage("1.img");
emp.setJob((short)2);
emp.setEntrydate(LocalDate.of(2006,3,4));
emp.setDeptId(1);
emp.setUpdateTime(LocalDateTime.now());
empMapper.update(emp);
}
4.5 查询
- 查询时 名称一致才能自动封装

@Test
public void testSelect(){
Emp emp = empMapper.selectById(1);
System.out.println(emp);
}
@Select("select * from emp where id= #{id}")
Emp selectById(Integer id);
4.5.1 解决名称不一致
4.5.1.1 sql起别名
- 在sql语句中给返回字段起别名
@Select("select id, username, password, name, gender, image, job, entrydate, dept_id deptId, create_time createTime, update_time updateTime from emp where id= #{id}")
Emp selectById(Integer id);
4.5.1.2 Result
@Results({
@Result(column = "dept_id", property = "deptId"),
@Result(column = "create_time", property = "createTime"),
@Result(column = "update_time", property = "updateTime")
})
@Select("select * from emp where id= #{id}")
Emp selectById(Integer id);
4.5.1.3 MyBatis 自动映射
- a_column –> aColumn 自动;映射
mybatis.configuration.map-underscore-to-camel-case=true
4.5.2 拼接查询 concat
@Select("select * from emp where name like '%${name}%' and gender = #{gender} and entrydate " +
"between #{begin} and #{end} order by update_time desc;")
List<Emp> selectBy(String name, Short gender, LocalDate begin, LocalDate end);
# { }不能出现在''内, 改成$

存在 sql 注入问题, 且性能低.
- concat 函数
@Select("select * from emp where name like concat('%',#{name},'%') and gender = #{gender} and entrydate " +
"between #{begin} and #{end} order by update_time desc;")
List<Emp> selectBy(String name, Short gender, LocalDate begin, LocalDate end);

5 Xml
- xml 文件中
<>要转义字符> <

- resultType 是单条数据的实体类型, 函数返回的是list 但是单条数据是Emp 类型, 因次是 org.hzl.pojo.Emp
<mapper namespace="org.hzl.mapper.EmpMapper">
<select id="selectBy" resultType="org.hzl.pojo.Emp">
select * from emp where name like '%${name}%' and gender = #{gender} and entrydate between #{begin} and #{end} order by update_time desc; </select>
</mapper>
// mapper 中不用写注解
List<Emp> selectBy(String name, Short gender, LocalDate begin, LocalDate end);
- MyBatisX 插件
6 动态sql

6.1 if
<mapper namespace="org.hzl.mapper.EmpMapper">
<select id="selectBy" resultType="org.hzl.pojo.Emp">
select * from emp where <if test="name!=null">
name like '%${name}%' </if>
<if test="gender!=null">
and gender = #{gender} </if>
<if test="begin!=null and end!=null">
and entrydate between #{begin} and #{end} </if>
order by update_time desc; </select>
</mapper>
List<Emp> list = empMapper.selectBy("张", null, null, null);
System.out.println(list);

6.1.1 and 拼接问题
<mapper namespace="org.hzl.mapper.EmpMapper">
<select id="selectBy" resultType="org.hzl.pojo.Emp">
select * from emp where <if test="name!=null">
name like '%${name}%' </if>
<if test="gender!=null">
and gender = #{gender} </if>
<if test="begin!=null and end!=null">
and entrydate between #{begin} and #{end} </if>
order by update_time desc; </select>
</mapper>
List<Emp> list = empMapper.selectBy(null, (short) 1, null, null);
System.out.println(list);

- name 字段为null, 但下面的 and gender 多了个 and.
- 当条件都不满足时, where 也多了.
使用 <where> </where> 标签包裹起来, 自动去除 and
<mapper namespace="org.hzl.mapper.EmpMapper">
<select id="selectBy" resultType="org.hzl.pojo.Emp">
select * from emp <where>
<if test="name!=null">
name like '%${name}%' </if>
<if test="gender!=null">
and gender = #{gender} </if>
<if test="begin!=null and end!=null">
and entrydate between #{begin} and #{end} </if>
</where>
order by update_time desc; </select>
</mapper>
<where>实现了 and or where 的去除
6.1.2 案例 不完全更新
- 需求: 有传递值就更新, 否则不更新该字段;
<update id="updateNotAll">
update emp set <if test="username!=null">username = #{username},</if>
<if test="name!=null">name = #{name},</if>
<if test="gender!=null">gender = #{gender},</if>
<if test="image!=null">image = #{image},</if>
<if test="job!=null">job = #{job},</if>
<if test="entrydate!=null">entrydate = #{entrydate},</if>
<if test="deptId!=null">dept_id = #{deptId},</if>
<if test="updateTime!=null">update_time = #{updateTime}</if>
where id = #{id}</update>
- 问题 会多个逗号 ; 使用
<set>标签解决;
<update id="updateNotAll">
update emp <set>
<if test="username!=null">username = #{username},</if>
<if test="name!=null">name = #{name},</if>
<if test="gender!=null">gender = #{gender},</if>
<if test="image!=null">image = #{image},</if>
<if test="job!=null">job = #{job},</if>
<if test="entrydate!=null">entrydate = #{entrydate},</if>
<if test="deptId!=null">dept_id = #{deptId},</if>
<if test="updateTime!=null">update_time = #{updateTime}</if>
</set>
where id = #{id}</update>
6.1.3 总结 逗号,where

6.2 foreach

<!-- item 遍历出来的;元素-->
<!-- separator 分隔符-->
<!-- open 遍历开始前面的拼接片段-->
<!-- close 遍历结束后拼接的片段-->
<delete id="deleteByIds">
delete from emp where id in <foreach collection="ids" item = "id" separator="," open = "(" close = ")">
#{id} </foreach>
</delete>
6.3 sql 和 include
6.3.1 问题

- 代码复用性差, 若修改需修改多处.
6.3.2 sql

<sql id = "commonSelect">
select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time from emp</sql>
<select id="selectBy" resultType="org.hzl.pojo.Emp">
<include refid="commonSelect"/>
<where>
<if test="name!=null">
name like '%${name}%' </if>
<if test="gender!=null">
and gender = #{gender} </if>
<if test="begin!=null and end!=null">
and entrydate between #{begin} and #{end} </if>
</where>
order by update_time desc;</select>
插入返回主键
keyProperty指定赋值给传入参数的哪个属性, 这里是赋值给dish.iddishMapper.insert(dish);
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
insert into dish(name, category_id, price, image, description, status, create_time, update_time, create_user, update_user) values (#{name},#{categoryId},#{price},#{image},#{description},#{status},#{createTime},#{updateTime},#{createUser},#{updateUser})</insert>
多表查询
<!-- select d.*,c.name categoryName from dish d left outer join category c on d.category_id = c.id;-->
<select id="pageQuery" resultType="com.sky.vo.DishVO">
select d.*,c.name categoryName from dish d left outer join category c on d.category_id = c.id <where>
<if test="name!=null and name!=''">d.name like concat('%',#{name},'%')</if>
<if test="categoryId!=null">and d.categoryId=#{categoryId}</if>
<if test="status!=null">and d.status = #{status}</if>
</where>
order by d.create_time desc </select>
6.4 总结

- 编写 xml 文件时 , 先在console中写好 sql 语句, 在替换标签.
- 编写xml 文件使 , String类型的 要判断是否为空

6.5 坑
- update 逗号问题, 检查sql 语句 每对后面逗号
