删除操作
首先在我们进行最基础删除的操作的时候,我们要清楚我们执行操作的基础的表结构,表的内容,还需要有数据库表的实现类
准备工作
1.数据库的表结构以及内容
2.我们数据库表中对应的实体类
实体类创建好之后,类中需要一个标准的javabean,这里就不再放出来
3.准备操作该数据库的 mapper接口
加上mapper注解代表 该类为mybatis中的mapper接口,程序运行的时候会自动创建接口的实现类对象,并且交给spring的ioc容器管理,具体ioc可以看我上一篇文章
工程结构如下
删除操作
我们要在mybatis中实现 根据主键的删除操作
例如 删除id=2的数据
sql语句的写法为 delete from people where id=2
我们在mapper接口中的写法只需要加上对应的注解和 一个对应的方法
值得注意的是 一个mapper接口可以写入多个语句
@Delete("delete from people where id=2") public void delete();
然后在我们的测试包中的测试类中 定义如下方法
执行之后,就能删除id为2的数据了,但是这种有一个弊端,就是你只能指定一行的删除情况,想删除其他的id 内容,就需要再编写删除方法,或者修改 delete注解中的sql语句内容,那么有没有方法能解决这种冗余的情况 ,我们可以使用占位符 #{}
改造后的sql语句如下 而在test方法中语句只需要加上想删除的对应id即可
#{}大括号中的命名是自己自由定义的,但是要与自己方法中的形参名称保持一致 ,但这是delete语句中 只有一个条件所执行的删除操作,如果delete语句中有两个条件成立才能执行删除的话怎么写呢
这是两个条件进行删除的时候的语句,但是当我运行 test方法进行测试的时候,报错了报了如下错误
就是我们在运行的时候,程序找不到sql语句idname与之对应的方法形参名字,那么 我们这时候就需要注解来进行绑定与之对应的形参值
注意 当我们使用param注解之后,注解中的字符串 需要与sql语句中的对应,而 方法形参名 跟不跟sql语句中的 名字对应都可以
日志输入
再mybatis的运行当中,我们可以看到sql语句的执行,执行操作和执行结果,配置如下
打开之后,我们执行一下我们上面的delete测试方法 看一下控制台.
可以看到我们的执行记录,我们发现 #{}内容 被?代替,然后由 方法传过来的形参值 进行与sql语句?的匹配,然后 在匹配好之后,执行sql语句,updates代表表中更改了几条数据,因为我的数据是随便输入的,所以更改了0
这种sql 进行?占位 并且与之匹配值的sql语句 我们称为预编译sql
预编译sql与sql注入
预编译sql有两个优势
1 .性能更高
当我们根据三个不同的id值正常执行三次sql删除语句的话 ,就是 执行一次,删除一次
但是 我们执行删除时,发现 只有删除的id值不同,其他语句都相同,性能较低
预编译sql会将编译依次的sql语句缓存起来,后面再次执行这条语句的时候,不会再次编译。
2.更安全 可以防止sql注入
sql注入:通过操作输入的数据修改事先定义好的sql语句,达到执行代码对服务器进行攻击的方式
由于没有对用户输入进行充分检查,而SQL又是拼接而成,在用户输入参数时,在参数中添加一些 SQL关键字,达到改变SQL运行结果的目的,也可以完成恶意攻击
比如一个登录系统
我们数据库中的账号对应的密码并不是这个密码,但是当我们 输入这串字符串当密码的时候,仍会登陆成功,那是因为 在底层中 sql语句的形式为
可以看到 拼接的为 password=‘ ‘or ’1‘=’1 ’ 这样拼接 就会变成一句完好的sql语句,从而达到登录效果 这种是不安全的
所以我们都用#{}占位符 来进行sql占位,生成预编译sql,我们输入的内容在sql语句中都是用?来进行占位的,这样防止sql注入安全
在Mybatis中提供的参数占位符有两种
:${...} 、#{...}
#{...} 执行SQL时,会将#{…}替换为?,生成预编译SQL,会自动设置参数值 使用时机:参数传递,都使用#{…}
${...} 拼接SQL。直接将参数拼接在SQL语句中,存在SQL注入问题 使用时机:如果对表名、列表进行动态设置时使用
增加操作
我们在插入的时候是根据一整行的信息进行插入的,这时候我们可以用我们之前建立的实体类 封装 好要插入的数据内容,然后调用mapper接口的方法 给sql语句返回一个封装好的实体类,mybatis会自动识别类中的名称与内容,进行插入操作
插入的代码
@Insert("insert into people(name,age,gender,phone)values (#{name},#{age},#{gender},#{phone})") public void insert(UserPeople userPeople);
测试类中的代码
@Test public void in(){ UserPeople up=new UserPeople(); up.setAge(10); up.setGender(1); up.setName("王五"); up.setPhone("111510506");}
在一般情况下,在我们插入完数据是不会返回主键的id值的,我们可以用一个options注解来得到返回的主键值 并在注解中指定属性useGeneratedKeys=true和 keyProperty="实体类属性名"
修改操作
修改操作与增加操作类似,也是可以指定一个修改的实体类的内容来进行修改
查询操作
查询操作正常的是select * 查询所有,但是当我们查询单个的时候,有时候会出现查询空值的情况比如下面这段查询代码
@Mapper
public interface EmpMapper {
@Select("select id, username,job, entrydate, dept_id, create_time, update_time from emp where id=#{id}")
public Emp getById(Integer id);}
而我们与之对应的实体类中 的内容为
可以看到 红色部分字段对应的名称不同,原因是因为
实体类属性名和数据库表查询返回的字段名一致,mybatis会自动封装。
如果实体类属性名和数据库表查询返回的字段名不一致,不能自动封装。
无法自动封装解决方法
1. 起别名 2. 结果映射 3. 开启驼峰命名
1.@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}")
2.
column 为数据库表中字段名 peoperty为 实体类的属性名
@Results({@Result(column = "dept_id", property = "deptId"),
@Result(column = "create_time", property = "createTime"),
@Result(column = "update_time", property = "updateTime")})
@Select("select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time from emp where id=#{id}")
3.如果字段名与属性名符合驼峰命名规则,mybatis会自动通过驼峰命名规则映射.
驼峰命名规则: abc_xyz => abcXyz
表中字段名:abc_xyz
类中属性名:abcXyz
sql注入的其他问题
当我们在进行模糊查询的时候,模糊查询进行的是字符串的拼接,这样会出现sql注入的问题,而且效率不高
如下一段
@Select("select * from emp " + "where name like '%${name}%' " + "and gender = #{gender} " + "and entrydate between #{begin} and #{end} " + "order by update_time desc")
解决这种方法 可以用字符串拼接函数解决
concat('%',#{name},'%')
mybatisxml文件与动态sql
使用Mybatis的注解方式,主要是来完成一些简单的增删改查功能。如果需要实现复杂的SQL功能,建 议使用XML来配置映射语句,也就是将SQL语句写在XML配置文件中。
在Mybatis中使用XML映射文件方式开发,需要符合一定的规范:
1. XML映射文件的名称与Mapper接口名称一致,并且将XML映射文件和Mapper接口放置在相同包下 (同包同名)
2. XML映射文件的namespace属性为Mapper接口全限定名一致
3. XML映射文件中sql语句的id与Mapper接口中的方法名一致,并保持返回类型一致。
resultType属性,指的是查询返回的单条记录所封装的类型。
编写xml映射文件
xml映射文件中的dtd约束,直接从mybatis官网复制即
<?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"><mappe namespace=" "></mapper>
不同的sql语句操作写在与之对应的标签中去 查询语句就写在 select标签中去
动态sql
if,where
在这段查询语句中 ,如果我们只想用这句sql查询名字返回记录,但是其他查询字段为null,会发现这个查询结果是不正确的
但是我们会想 谁有病吗,我设置好查询之后偏偏传入空值,但是当我们面对这样的表单的时候就会出现以上情况
该查询就可以选择性传入参数,遇见这种我们不可能排列组合般的写很多句sql查询,所以这时候我们就要用到动态sql
SQL语句会随着用户的输入或外部条件的变化而变化,我们称为:动态SQL。
我们根据上面查询表单的情况写的动态sql语句应该是
这样写sql 只有在查询到姓名之后,后面两项即使不输入内容也可以查询出条件,但是当我们查询姓名的时候为空,后面两项继续查询,就会出现拼接问题
我们举个例子,我们不查询姓名,只查询gender 动态sql语句拼接为
select * from emp where and gender=#{} order by update_time desc
多了一个and,语句就会报错
那么怎么解决呢?就用where标签 包裹该判断的语句,where标签会自动判断是否去除 多余的and或者其他值
set
在使用动态sql的时候,需要把在mapper接口中的定义的方法的与之对应的 查询注解删除,只保留方法即可,其他在xml文件中书写
在进行update操作的时候,用if判断完之后,会出现 多余的逗号 比如后面就出现了多余的逗号,此种情况用set标签包裹即可
foreach
有下面的sql 语句
delete from emp where id in (1,2,3);
用foreach遍历in中的内容批量删除