MyBatis的使用(注解方式)
1.MyBatis的日志开启方式
默认情况下执行接口的方法是不显示任何内容的,但是可以基于MyBatis开启日志输出
在配置文件中配置如下信息:
properties
# 开启MyBatis的日志输出
mybatis.configuration.log-impl=org.apache.itbatis.logging.stdout.StudOutImpl
开启之后,可以在执行SQL语句的时候看到实际执行的语句内容以及参数的内容(实际影响数据库的行数)
2.MyBatis的SQL注入
预编译SQL就是SQL语句中不确定的地方提前用?进行占位的SQL语句
好处:减少数据库对SQL语句语法检查/优化/编译的次数,预编译SQL就相当于一个模板
而直接写好的SQL语句每次都会经过语法检查/优化/编译
在MyBatis中,SQL中获取参数的方式有两种
-
${}:底层使用不是预编译SQL而是将参数拼接在SQL语句中
java//使用${}进行取值 @Delete("DELETE FROM emp WHERE username = '${username}'") //DELETE FROM emp WHERE id = '10' public void deleteEmp2(@Param("username") String username);
java@Test public void testDeleteEmp2() { //SQL注入:传递数据导致SQL本身的语义发生改变攻击方式 empMapper.deleteEmp2("' OR '1' = '1"); }
由于底层是拼接最终的SQL语句变成了DELETE FROM WHERE username=' OR '1' = '1',条件永远成立,所有的数据都被删除了,就存在SQL注入的问题
-
#{}:底层使用的是预编译SQL可以保证SQL语句的安全性
java//使用#{}进行取值 @Delete("DELETE FROM emp WHERE username = #{username}") //DELETE FROM emp WHERE username = ? public void deleteEmp3(@Param("username") String username);
由于预编译SQL已经先发送给MySQL进行编译,之后传递给的所有值都会被MySQL当作参数对待
总结:${}和#{}在MyBatis中取值的优缺点对比
1.底层的方式
- #{}使用的是预编译语句,先将不确定的地方使用?占位,提前发送给MySQL进行编译
- ${}底层直接进行内容的拼接,每次都会将拼接好的内容发给MySQL进行执行
2.效率的对比
- 预编译SQL语句的性能更高,因为当模板被MySQL编译好之后就不需要再进行编译了,直接传递参数
- ${}由于每次的内容都不一样,都需要进行编译的过程
3.灵活性的对比
- ${}更加灵活,因为不仅仅可以拼接参数,SQL语句中的任何一个部分都可以拼接(表名/数据库名/字段)
- #{}没有${}灵活,它只能够作为参数的占位符
开发中使用#{}!
3.MyBatis的添加操作
添加操作:要添加一条数据到数据库,基于已经完成ORM映射(表/类)直接声明该类作为方法的参数
可以基于#{}获取对象中成员变量内容组成的SQL语句
java
@Insert("INSERT INTO emp VALUES (NULL,#{emp.username},#{emp.password},#{emp.name},#{emp.gender}," +
"#{emp.image},#{emp.job},#{emp.entrydate},#{emp.deptId},#{emp.createTime},#{emp.updateTime})")
public void saveEmp(@Param("emp") Emp emp);
复杂对象:一个对象包含多个值(自定义类的对象),使用#{对象名.属性名}
@Param("emp") Emp emp,可以限制SQL语句中必须基于指定的名称进行获取
MyBatis添加操作(返回主键值)
如果需要在添加数据完成之后获取本次数据的主键,可以在添加的注解上使用@Options注解进行获取
java
//开启主键返回(添加完成之后将生成的主键赋值给参数对象的id属性)
@Options(keyProperty = "id",useGeneratedKeys = true)
4.MyBatis更新操作
一般情况下可以将更新后的数据保存到一个与表进行映射的Java类中。参数对象里面必须带有id(id是定位要更新数据的唯一方式),创建时间不需要更新。
java
@Update("UPDATE emp SET username = #{emp.username},password = #{emp.password},name = #{emp.name}" +
",gender = #{emp.gender},image = #{emp.image},job = #{emp.job},entrydate = #{emp.entrydate}" +
",dept_id = #{emp.deptId},update_time = #{emp.updateTime} WHERE id = #{emp.id}")
public void updateEmp(@Param("emp") Emp emp);
5.MyBatis查询单条数据
当执行增删改语句的时候返回值类型可以写void,但是查询的时候一定会产生一个伪表结果,声明返回值类型的目的就是告诉MyBatis如何处理伪表的结果
java
@Select("SELECT * FROM emp WHERE id = #{id}")
public Emp selectEmpById(@Param("id") Integer id);
当MyBatis读取到返回值类型之后,会默认创建一个对象,按照表与类的映射关系完成对象成员变量的赋值
6.MyBatis解决表名/列名不一致问题
1.基于修改查询出伪表列的别名与类的成员变量名一致让MyBatis完成封装(起别名)
java
@Select("SELECT id, username, password, name, gender, image, job, entrydate, dept_id AS deptId, create_time AS createTime, update_time AS updateTime FROM emp WHERE id = #{id}")
public Emp selectEmpById2(@Param("id") Integer id);
2.基于手动指定伪表列与类的成员变量的映射关系完成封装
java
@Select("SELECT * FROM emp WHERE id = #{id}")
@Results({@Result(column = "dept_id", property = "deptId"), //伪表的dept_id列映射给deptId成员变量
@Result(column = "create_time", property = "createTime"), //伪表的create_time列映射给createTime成员变量
@Result(column = "update_time", property = "updateTime")}) //伪表的update_time列映射给updateTime成员变量
public Emp selectEmpById3(@Param("id") Integer id);
3.开启MyBatis的驼峰映射(这种情况的使用前提是双方都遵守各自的开发规范)
properties
mybatis.configuration.map-underscore-to-camel=true
7.MyBatis查询多条数据操作
-
查询多条数据的基础方式:没有条件
由于要查询多条数据,要将返回值声明为List,泛型为封装为什么对象
java@Select("SELECT * FROM emp") public List<Emp> selectEmpList();
-
查询多条数据的进阶方式:有条件
有条件指的是要基于多个参数进行的查询,将多个参数封装为一个Java类(条件对象)
java@Data @Builder public class EmpQuery { private String name; //员工姓名 private Integer gender; //员工性别 private LocalDate begin; //开始入职时间 private LocalDate end; //结束入职时间 }
java@Select("SELECT * FROM emp WHERE name LIKE CONCAT('%',#{empQuery.name},'%') AND gender = #{empQuery.gender} AND entrydate >= #{empQuery.begin} AND entrydate <= #{empQuery.end}") public List<Emp> selectEmpListByCondition(@Param("empQuery") EmpQuery empQuery);