目录
Mybatis的两种获取参数的形式
mybatis有两种获取参数值的方式: ${ } 和 #{ }
方式 | ${ } | #{ } |
底层原理 | 字符串拼接 | 占位符赋值 |
字符串和日期类型字段的单引号 | 手动添加单引号 | 自动添加单引号 |
对比
字符串拼接:
select * from user where name = ' " + username +" '
占位符赋值
select * from user where name = ?
其中,字符串拼接非常容易受到sql注入*的攻击,而且还需要手动添加单引号,非常麻烦
*sql注入:
就比如这字符串拼接中的例子,由于username是一个变量,并且拼接在了sql语句中
假设现在有人将username赋值为 ' or ' 1 ' = '1 那么最终呈现出来的效果就会是这样的
SELECT * FROM user WHERE name = '' OR '1'='1';
这个查询将会返回表中的所有记录,因为
OR '1'='1'
条件始终为真。攻击者利用了SQL注入漏洞,绕过了正常的验证机制,并成功获取了系统中的所有用户数据。
因此我们一般使用#{ },特殊情况下才会使用到${ }
单表操作
我们使用<select>标签可以进行查询,其中除了resultType还有其他的重要的参数
id
:查询语句的唯一标识符,必须在命名空间中是唯一的。parameterType
:指定输入参数的类型。可以是Java类的完全限定名、别名或者是map
(用于接收多个参数)。resultType
:指定返回结果的类型。可以是Java类的完全限定名、别名或者是map
(用于返回多个结果)。resultMap
:指定一个结果映射的标识符,用于复杂的结果映射配置。flushCache
:设置是否刷新缓存,默认值为false
。当设置为true
时,每次查询都会刷新缓存。timeout
:设置查询的超时时间,单位为毫秒。超过指定时间仍未返回结果,则会抛出异常。fetchSize
:设置一次数据库查询返回的行数。可以提高查询性能,默认使用驱动程序的默认值。fetchType
:设置结果集的获取方式,可以是LAZY
(延迟加载)或EAGER
(立即加载),默认为LAZY
。statementType
:设置SQL语句的执行方式,可以是STATEMENT
(直接操作SQL语句)、PREPARED
(使用预编译语句)、CALLABLE
(使用存储过程)。useCache
:设置是否启用二级缓存,默认值为true
。设置为false
时,每次查询结果都会从数据库中获取
我们在接下来的例子中会慢慢使用到
1、根据id查询属性
mapper层
映射文件
我们在会多次使用到返回类型的user,但是每次使用都要写上很长的包和类名,使得代码看起来很繁琐
我们之前在配置核心文件的时候提到过有一个标签可以起别名
<typeAliases>
:用于配置 Java 类型的别名,简化映射器中的类型引用。
我们比之前写的入门案例多使用了一个parameterType,因为我们引入了参数,这个属性会指定参数的类型,并使用了动态sql#{}
在MyBatis中,#{ }是一种用于处理动态SQL的占位符语法。它主要用于防止SQL注入攻击,并且可以将参数转换为预编译语句中的占位符。
测试
这段创建sqlSession的代码复用性很高,于是我将他封装成了一个工具类,这个可做可不做
@Test
public void selectById() throws IOException {
//将sqlSession封装成了util
SqlSession sqlSession = SqlSessionUtil.getSqlSession("mybatis.xml");
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.selectById(1);
System.out.println(user);
}
我们之前使用了sqlSession原生的selectList方法,凡是缺点是很容易出bug,我们引入新的方式
直接得到mapper接口的实现对象,并调用其中的方法
这种方式更直观
2、增加
映射器
映射文件
测试
@Test
public void addUser() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession("mybatis.xml");
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = new User("派大星",3,"海星",666);
mapper.addUser(user);
//提交事务
sqlSession.commit();
sqlSession.close();
System.out.println("添加成功");
}
这里要提交一下事务,否则不会添加到数据库中
3、修改
映射器
映射文件
测试
@Test
public void updateUser(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession("mybatis.xml");
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.updateUser(new User(9,"海绵宝宝",8,"海绵",888));
sqlSession.commit();
sqlSession.close();
System.out.println("修改成功");
}
4、删除
映射器
映射文件
测试
@Test void deleteById(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession("mybatis.xml");
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.deleteById(9);
sqlSession.commit();
sqlSession.close();
System.out.println("删除成功");
}
Mybatis获取参数时的多种情况
我们刚才的增删改查操作均是单个参数的简单情况,现在我们有多个情况
1、参数为多个
事实上,我们也可以像之前添加用户一样传入一个对象调用其属性,我们可以利用登录信息构建一个LoginInfo对象然后实现调用其中的多个参数的效果,而且适用于需要传递更多验证信息的情况,例如验证码、记住我等。
不过我们这里只是想体现多个参数的使用
我们来模拟用户登录的操作,为数据库新增两个字段
alter table springtest.user
add username varchar(20) null;
alter table springtest.user
add password varchar(20) null;
mybatis的底层会检测我们方法的参数,当为多个参数时,会自动将参数放在一个map集合中
以arg为键,以参数为值 或 以param为键,以参数为值,
唯一的区别就是arg的下标从0开始,param的下标从1开始,
你甚至可以同时使用arg和param,但是注意别把下标搞混了
我们来举例演示
映射器
映射文件
注:如果你要使用${ },记得手动加一个' '单引号 -> ' ${ param } '
测试
成功查询
2、参数为存储多个参数的map
我们刚才提到了多个参数会被存储在map集合中,那理所当然的我们可以直接传入这个map作为参数
mapper
mapper.xml
测试
由于我们需要手动创建map,手动将信息存入map,还是比较麻烦的,不太推荐
3、参数为实体类
事实上,我们从网页前端传来的数据一般都是一个实体类。
我们之前在上面案例中的增加用户时就是用了实体类user作为参数,那么它是怎么根据user来获取到对应的数据的?
注意了,他并不是直接去寻找user的属性然后对应起来的,它是根据get和set方法得到的。
所以要想使用实体类作为参数,首先需要有字段对应的getter和setter
例子就在上方的增加案例演示,我们这里不再演示
4、参数为命名参数@Param
@Param注解是MyBatis框架中的一个注解,用于给参数取别名。当方法参数中存在多个参数时,可以使用@Param注解明确指定每个参数的名称,以便在映射文件中引用。
其底层也是以map集合存储键值对的形式实现的,@Param的值为键,参数的值为值
这样使用方式集合了情况2和3的优点,非常推荐使用这种方式
mapper
mapper.xml
这里依旧可以同时使用param和你自己定义的键,就想方式2一样
测试
问:
当参数为一个时,还可以使用@Param注解吗
当然可以,事实上,我们可以规定全部使用@Param注解,这样的话就不存在参数是多个还是单个的情况了
特殊SQL的执行
1、模糊查询
我们先写sql语句,写一个模糊查询
SELECT * FROM employees WHERE name LIKE '%wal%';
查询表中所有包含wal的数据,但是我们现在要使用mybatis,按照我们的直觉来使用就是
select * from employees where name like '%#{ name }%'
但这样是不对的,系统会将 ? 视为字符串的一部分,最终呈现出 '%?%' 的效果
此时我们有两种解决方法
<1>、 ${ }
此时我们使用${ }就可以实现最终效果了
select * from user where name like '%${name}%'
<2>、 手动字符串拼接
select * from employees where name like concat('%',#{username},'%')
<3>、 推荐方法
select * from employees where name like "%"#{username}"%"
2、批量删除
我们先看sql语句
delete from user where id in ('1,2,3');
在标签中正确得写法应该是
<delete id="deleteMore">
delete from user where id in (${ids})
</delete>
3、动态设置表命
我们想要动态的去设置查询的表
select * from #{ tablename }
这样也是不行的,最总呈现的效果是select * from ? 识别不了这个占位符
所以我们应该通过字符串拼接${ }
select * from ${ tablename }