Mybatis的使用--查询
1.定义需要的映射
1.1首先再UserMapper接口中定义查询接口,
接口的方法映射到对应的xml文件中的语句,xml文件中id对应方法名;
1.2mapper.xml中的注意事项:
构建返回的结果集合:
1.3 注意
1.3.1 只传递一个参数
我们发现当查询只传递一个参数时,无论接口中的名称和xml中的名称是否对应,只要类型对应都能够按照传递的参数进行查询
在xml文件中:
在测试中:
即使名称不对应依旧能够返回结果:
1.3.2 传递多个参数
此时名称不对应,就会报错,因为找不到相应的参数;
Parameter 'uid' not found.Available parameters are [password, param1, username, param2]
当前端和后端的属性名称不能够对应时;我们可以使用@Param注解,使用如下:
public User getUserByNameAndPassword(@Param("name") String username, String password);
这样我们可以在查询时使用name来找到username参数;
将xml中的查询参数改为name
此时进行测试:
这表示name可以指代username参数进行查询;
2.动态传输的问题
动态传输的标识:
->#{}表示从接口声明的方法参数中获取参数,并设置到当前sql语句当中;
-> KaTeX parse error: Expected 'EOF', got '#' at position 4: {}与#̲的不同指出在于#{}可以将其中…时不会加上引号;
因此当替换sql的信息为非系统关键字的使用一定要使用#{},可以防止sql注入;
当替换的sql为系统的mysql的关键字一定要使用${};如果使用#{}就会给替换的值加上单引号,导致查询的sql错误;
2.1 例子;
当我们使用模糊查询时;在mapper.xml文件中:
<select id="getListByName" resultType="com.example.demo.model.User">
select * from userinfo where username like '%#{username}%'
</select>
此时就会报错
因为我们此时定义的sql语句是错的
上述sql语句相当于:
select * from userinfo where username like '%'username'%'
出现了两次单引号;
改成$就可以避免这个问题;
<select id="getListByName" resultType="com.example.demo.model.User">
select * from userinfo where username like '%${username}%'
</select>
2.2 关于sql注入
定义:使用一个特殊的sql语句查询了一个不应该查询到的内容
2.2.1 解决sql注入问题:
1.Mapper类-只有开发人员自己能够调用;
手动排查sql注入的关键字–‘or/and’;
2.针对like查询–使用系统提共的参数进行参数拼接;
使用concat关键字进行拼接;
示例:
select * from userinfo where username like concat('%',#{username},'%');
3. 联表查询
3.1 一对一:
文章表和用户表;
当使用联表查询的时候,如果表中数据是1对1的关系,我们需要改动一下查询的返回集合构成,:
如下:在这里以一个文章表和用户表相互对应为例:
<resultMap id="BaseResultMap" type="com.example.demo.model.ArticleInfo">
<id property="id" column="id"></id>
<result property="title" column="title"></result>
<result property="content" column="content"></result>
<result property="createtime" column="createtime"></result>
<result property="updatetime" column="updatetime"></result>
<result property="uid" column="uid"></result>
<result property="rcount" column="rcount"></result>
<result property="state" column="state"></result>
<association property="user" columnPrefix="u_"
resultMap="com.example.demo.mapper.UserMapper.BaseResultMap">
</association>
</resultMap>
注意
这里需要注意:查询的前缀一定不能省略,如果两张表中有相同的字段名,就会出现数据覆盖的问题,
3.1.2 实现过程
1.创建实体对象: articleinfo->包含了属性user;
2.在mapper接口中定义查询方法
3.mapper.xml具体实现; 在resultmap中定义一对一的关系;–> sql语句
<mapper namespace="com.example.demo.mapper.ArticleInfoMapper">
<resultMap id="BaseResultMap" type="com.example.demo.model.ArticleInfo">
<id property="id" column="id"></id>
<result property="title" column="title"></result>
<result property="content" column="content"></result>
<result property="createtime" column="createtime"></result>
<result property="updatetime" column="updatetime"></result>
<result property="uid" column="uid"></result>
<result property="rcount" column="rcount"></result>
<result property="state" column="state"></result>
<association property="user" columnPrefix="u_"
resultMap="com.example.demo.mapper.UserMapper.BaseResultMap">
#用于联表查询,定义查询到的user属性映射关系;
</association>
</resultMap>
<select id="getAll" resultMap="BaseResultMap">
select a.*,u.username u_username,u.id u_id,u.password u_password from articleinfo
a left join userinfo u on a.uid=u.id
</select>
</mapper>
在联表查询时,两个标的字段都需要与我们设置的对象属性一对一的对应起来
3.2 一对多查询
一对多指的是,当前查询到的数据还能够通过某个相关联的数据查询到另一张表的多个数据,因此,我们查询的返回值会出现一个对象还附带着多个其他对象的情况,这种情况下我们需要定义一个collection来保存这些其他对象:
示例:每个用户拥有多篇文章
<resultMap id="BaseResultMap" type="com.example.demo.model.User">
<id column="id" property="id"></id>
<result column="username" property="username" />
<result column="password" property="password" />
<result column="photo" property="photo" />
<collection property="alist" columnPrefix="a_"
resultMap="com.example.demo.mapper.ArticleInfoMapper.BaseResultMap">
</collection>
</resultMap>
可以发现一对一的时候,使用的association除了关键字不同其他的都相同,collection代表的是集合,就是说查询到当前所有符合条件的数据都显示
4. 设置动态sql语句
4.1 if的使用,
如果存在就拼接到sql语句中,如果不存在就不拼接:
首先定义接口
再定义sql.xml方法:
<select id="getArticleInfo" resultMap="BaseResultMap">
select * from articleinfo where title = #{title}
<if test="content!=null">
and content = #{content}
</if>
<if test="state!=0">
and state=#{state}
</if>
</select>
测试
总结:使用if可以进行选择性的参数拼接;
当三个参数都不是必要传递的时候,我们需要写三个if判断,这样太麻烦了
接下来使用trim关键字实现多个参数的判断拼接:
4.2 trim的使用
定义接口
定义xml
<insert id="addArticle">
insert into articleinfo(
title,content,uid
<trim prefix="," suffixOverrides=",">
<if test="rcount !=null">
rcount,
</if>
<if test="state!=null">
state,
</if>
</trim>
)values(#{title},#{content},#{uid} <trim prefix="," suffixOverrides=",">
<if test="rcount !=null">
#{rcount},
</if>
<if test="state!=null">
#{state},
</if>
</trim>)
trim中的几个参数,prefix添加前缀,suffix添加后缀,加上override表示重写;
测试
4.3 where的使用
当关键字不为null时,都为查询条件:
定义接口:
public List<ArticleInfo> getArticleInfo3(String title, String content,int state);
定义xml
<select id="getArticleInfo3" resultType="com.example.demo.model.ArticleInfo">
select * from articleinfo
<where>
<if test="title!=null">
title=#{title}
</if>
<if test="content!=null">
content=#{content}
</if>
<if test="state!=0">
state=#{state}
</if>
</where>
</select>
测试
@Test
void getArticleInfo3() {
List<ArticleInfo> list=articleInfoMapper.getArticleInfo3("Java",null,0);
}
4.4 update中set的使用
首先查看数据库中的原有数据
定义接口
定义xml方法
<update id="upArticle">
update articleinfo
<set>
<if test="title !=null">
title=#{title}
</if>
<if test="content!=null">
content=#{content}
</if>
</set>
where id=#{id}
</update>
测试
void upArticle() {
int result= articleInfoMapper.upArticle(2,"今天晴天",null);
System.out.println(result);
}
4.5 foreach的使用
定义接口
定义xml
<delete id="delArticleByIds">
delete from articleinfo
where id in
<foreach collection="ids" item="item" open="(" close=")" separator=",">
#{item}
</foreach>
</delete>
测试
再看看查询操作:
<select id="getArticleInfo4" resultType="com.example.demo.model.ArticleInfo">
select * from articleinfo where id in
<foreach collection="ids" open="(" close=")" separator="," item="item">
#{item}
</foreach>
</select>
需要注意的是:这里的separator指的是sql语句中的分割: