Mybatis
Mybatis项目创建
1. 创建一个新的springboot工程,选择引入对应的起步依赖(mybatis、mysql驱动、lombok)
2. application.properties中引入数据库连接信息(复制过来即可)
3. 准备数据库表 emp,及对应的实体类 Emp (实体类属性采用驼峰命名模式)
4. 准备Mapper接口 EmpMapper
application.properties文件配置
#下面这些内容是为了让MyBatis映射 #指定Mybatis的Mapper文件 mybatis.mapper-locations=classpath:mappers/*xml ##指定Mybatis的实体目录 #自己修改 mybatis.type-aliases-package=com.itheima.Pojo.Emp 实体类地址 #开启驼峰命名自动映射,即从经典数据库列名 a_column 映射到经典 Java 属性名 aColumn。 mybatis.configuration.map-underscore-to-camel-case=true #指定mybatis输出日志的位置, 输出控制台 mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl #驱动 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver #连接路径 spring.datasource.url=jdbc:mysql://localhost:3306/tlias #账号 spring.datasource.username=root #密码 spring.datasource.password=1234
java语言编译为SQL语言的过程
语法检查>缓存> 编译SQL> 缓存>执行
预编译SQL
1.3.3.1 介绍
预编译的SQL,有两个优势:
-
性能更高
-
防止SQL注入
A. 性能更高: 预编译SQL,编译一次之后会将编译后的SQL语句缓存起来,后面再次执行这条insert语句时,SQL语句一样,不会再次编译。 只是输入的参数不同。
B. 防止SQL注入:将敏感字进行转义,安全。
参数占位符
在Mybatis中提供的参数占位符有两种:${...}, #{...}。
1). #{...}
执行SQL时,会将#{…}替换为?,生成预编译SQL,会自动设置参数值。
使用时机:参数传递,都使用#{…}
2). ${...}
拼接SQL。直接将参数拼接在SQL语句中,存在SQL注入问题。
使用时机:如果对表名、列表进行动态设置时使用。
基础操作
增 insert into
删 delete
改 update
查 select
数据封装
我们看到查询返回的结果中大部分字段是有值的,但是deptId,createTime,updateTime这几个字段是没有值的,而数据库中是有对应的字段值的,这是为什么呢?(表和实体类名字对应不上)
原因如下:
-
实体类属性名 和 数据库表查询返回的字段名一致,mybatis会自动封装为实体类。
-
如果实体类属性名 和 数据库表查询返回的字段名不一致,不能自动封装。
三种方法解决
起别名
@Select("select id, username, password, name, gender, image, job, entrydate, dept_id deptId, create_time createTime, update_time updateTime from emp where id = #{id}") public Emp getById(Integer id);
手动结果映射
@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}") public Emp getById(Integer id);
开启驼峰命名(推荐)
#开启驼峰命名自动映射,即从经典数据库列名 a_column 映射到经典 Java 属性名 aColumn。 mybatis.configuration.map-underscore-to-camel-case=true
参数名说明(@Param注解)
接口中的方法怎么设定参数名,好让SQL语句中能够识别
在springBoot的2.x版本之后,springBoot的父工程对compiler编译插件进行了默认的参数 parameters 配置,使得在编译时,会在字节码文件中保留原方法形参的名称,所以#{…}里面可以直接通过形参名获取对应的值。
在springBoot的1.x版本中,所有接口方法形参编译后的为var1、var2 …,此时如果有多个参数,就需要通过@Param注解来指定SQL语句中的参数名
@Select("select * from emp " + "where name like concat('%',#{name},'%') and gender=#{gender} and entrydate between #{begin} and #{end};") List<Emp> list3(@Param("name") String name, @Param("gender") Short gender, @Param("begin") LocalDate begin, @Param("end") LocalDate end);
主键返回(@Options(keyProperty = "id", useGeneratedKeys = true))
@Options(keyProperty = "id", useGeneratedKeys = true) @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})") public void insert(Emp emp);
动态SQL
XML映射文件
-
XML映射文件的名称与Mapper接口名称一致,并且将XML映射文件和Mapper接口放置在相同包下。(同包同名)
-
XML映射文件的namespace属性为Mapper接口全限定名一致。
-
XML映射文件中sql语句的id与Mapper 接口中的方法名一致,并保持参数类型和返回值类型一致。
<?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=" 接口全限定名 "> 接口地址 <select id="接口方法名" resultType=" 返回值类型 "> 绑定方法名 返回值地址到POJO的类中 <!-- sql语句 --> </select> </mapper>
if
用于判断条件是否成立,使用test属性进行条件判断,如果条件为true,则拼接SQL
<select id="list" resultType="com.itheima.pojo.Emp"> select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time from emp where <if test="name != null"> name like concat('%',#{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>
where 标签
<where> (去and 或 or)如果不去除会出现SQL语句语法错误
where 元素只会在子元素有内容的情况下才插入where子句。而且会自动去除子句的开头的AND 或OR。
Set标签
<set>(去逗号) 如果不去除会出现SQL语句语法错误
动态地在行首插入 SET 关键字,并会删掉额外的逗号。(用在update语句中)
<update id="update"> 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>
foreach标签
<foreach>(批量处理数据 例如删除)
foreach属性介绍:
collection:集合名称
item:集合遍历出来的元素/项
separator:每一次遍历使用的分隔符
open:遍历开始前拼接的片段
close:遍历结束后拼接的片段
SQL语句 delete from emp where id in (1,2,3); //批量删除 public void deleteByIds(List<Integer> ids); XML映射文件 <delete id="deleteByIds"> delete from emp where id in <foreach collection="ids" item="id" separator="," open="(" close=")"> #{id} </foreach> </delete>
SQL标签
<sql>用于减少重复代码块 生成一个可重用的代码块片段
include标签
<include> 通过属性refid,指定包含的sql片段。
<sql id="commonSelect"> select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time from emp </sql> <select id="list" resultType="com.itheima.pojo.Emp"> <include refid="commonSelect"/> <where> <if test="name != null"> name like concat('%',#{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>