一.#{}和${}的区别
- 相同点:这两个都是占位符,用来指定传入sql的参数
- 不同点:
- #{}这个是预编译的,不会发生sql注入,如果需要使用拼接的话可以使用sql的内置函数contact()
- ${}这个是将其中的变量通过字符串拼接的方式插入到sql语句中的,容易发生sql注入,尽量避免使用
二.参数
1.多个参数
当我涉及到多个参数传参的时候,这个时候,我们直接使用变量名会发现控制台有错误提示
Parameter ‘XXX’ not found. Available parameters are [arg1, arg0, param1, param2]
这一行报错的意思是XXX变量没有生命,我们可以用的变量名为arg1,arg0,param1,param2
当我们有多个变量的时候,我们就需要通过arg0,arg1来获取对应的变量了
// 接口方法
int updateNickname( int id,String nickname);
<update id="updateNickname">
# 读取第二个变量nickname和第一个变量id
update t_user set nickname = #{arg1} where id = #{arg0}
</update>
这种方式不是特别直观,当我们调整顺序之后,相应的xml里的顺序也需要调整,故我们一般会通过第二种方式来解决这个问题。通过注解的方式
// 接口方法
int updateNickname( @Param("id") int id,@Param("nickname")String nickname);
<update id="updateNickname">
update t_user set nickname = #{nickname} where id = #{id}
</update>
2.包装类型单个参数
java有八个基本数据类型,我们在使用这些基本数据类型,可以直接取到对应的value,比如我们上次课程中涉及到的int类型。
但是当我们的参数是包装类型时,比如String或者是User的实体类,这时mybatis就或读取包装类型中的属性,比如我们在使用User实体类时,直接使用实体类中的#{id}属性。但是String类型并没有对应的属性,我们希望的是直接获取String中的值,那么我们在取值的时候,就会出现这个错误。
There is no getter for property named ‘xxx’ in ‘class java.lang.String’
这个报错的意思就是从String类型中获取不到xxx属性
这个使用我们也需要通过@Param的注解来解决这个问题
// 接口方法
List<User> selectList(@Param("orderBy") String orderBy);
<select id="selectList" parameterType="String" resultType="User">
select * from t_user ${orderBy}
</select>
3.实体类参数与基本类型参数混用
直接看例子就明白了
// 接口方法
List<User> selectList(@Param("orderBy") String orderBy,@Param("user") User user);
<select id="selectList" resultType="User">
select * from t_user where username = #{user.username} ${orderBy}
</select>
三.paramerterType , resultType , resultMap
1.paramerterType
参数的类型
单个基本类型可以不写
参数有多种类型的时候不写
实体类必须写
2.resultType
返回值类型
除了查询,其他的都可以不写,因为其他的返回值都是int(默认影响的行数)
3.resultMap
返回值map
使用场景:
实体类与数据库表字段不一致,例如表中的字段是user_id,实体中的是userId,那么就需要进行一下映射,方法如下
<resultMap id = "mapName" type="User" autoMapping="ture">
<result column="user_id" property="userId">
</resultMap>
type映射实体的类型,比如user表映射的是User实体类
autoMapping="true"会自动的将同名的字段映射
result标签中的column对应的数据表的字段名,property对应的是实体类中的属性
四.动态SQL
直接上代码
1.StudentMapper接口
package com.tl.mybatis02.mapper;
import com.tl.mybatis02.model.Student;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @author Antg
* @date 2021/8/39:59
*/
public interface StudentMapper {
/***************************** 动态sql ***********************************/
//使用if语句
public List<Student> find(Student student);
//使用choose when otherwise
public List<Student> useChoose(Student student);
//where
public List<Student> useWhere(Student student);
//set
public int useSet(Student student);
//foreach 循环插入
public int useForEach01(@Param("list01") List<Student> studentList);
//foreach 循环in
public List<Student> useForEach02(@Param("idList") Integer[] idList);
//根据id查询
public Student findStuById(@Param("id") Integer id);
}
2.StudentMapper.xml
<?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="com.tl.mybatis02.mapper.StudentMapper">
<resultMap id="stuResult" type="Student">
<id column="id" property="id"/>
<result column="username" property="username"></result>
<result column="nickname" property="nickname"></result>
</resultMap>
<!-- ############################### 动态sql ################################# -->
<!--动态sql 使用if-->
<select id="find" parameterType="Student" resultMap="stuResult">
select * from student_info where true
<if test="username != null and username != ''">
and username =
#{username}
</if>
<if test="nickname != null and nickname != ''">
and nickname like concat('%',
#{nickname},
'%'
)
</if>
</select>
<!--动态sql 使用choose-->
<select id="useChoose" parameterType="Student" resultType="Student">
select * from student_info where 1=1
<choose>
<when test="id != null">
and id = #{id}
</when>
<when test="username != null and username != ''">
and username = #{username}
</when>
<otherwise>
and nickname = #{nickname}
</otherwise>
</choose>
</select>
<!--动态sql 使用where-->
<select id="useWhere" parameterType="Student" resultMap="stuResult">
select * from student_info
<where>
<if test="username != null and username != ''">
and username =
#{username}
</if>
<if test="nickname != null and nickname != ''">
and nickname like concat('%',
#{nickname},
'%'
)
</if>
</where>
</select>
<!--动态sql 使用set-->
<update id="useSet">
update student_info
<set>
<if test="username != null and username != ''">
username =
#{username},
</if>
<if test="nickname != null and nickname != ''">
nickname =
#{nickname},
</if>
</set>
where id = #{id}
</update>
<!--动态sql 使用forEach循环插入-->
<insert id="useForEach01">
insert into student_info(username, password, nickname, age, birthday) values
<foreach collection="list01" item="item" separator=",">
(#{item.username}, #{item.password}, #{item.nickname}, #{item.age}, #{item.birthday})
</foreach>
</insert>
<!--动态sql 使用forEach in查询-->
<select id="useForEach02" resultType="Student">
select * from student_info where id in
<foreach collection="idList" item="item" separator="," open="(" close=")">
#{item}
</foreach>
</select>
</mapper>
五.联查
1.一对一
接口
package com.tl.mybatis02.mapper;
import com.tl.mybatis02.model.Address;
public interface AddressMapper {
/***************************** 一对一 ***********************************/
public Address findAddressById(Integer id);
public Address findAddressById2(Integer id);
public Address findAddressById3(Integer id);
/***************************** 一对多 ***********************************/
public Address findById(Integer id);
}
xml
<?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="com.tl.mybatis02.mapper.AddressMapper">
<!-- ############################### 联查之一对一 ################################# -->
<!-- 方法一: 使用select引入其他mapper中的方法-->
<resultMap id="addressMap" type="Address" autoMapping="true">
<!-- <!–因为实体类和数据库中的字段不一样,所以要在这里映射一下–>-->
<result column="stu_id" property="stuId"></result>
<association property="student" column="stu_id" javaType="Student"
select="com.tl.mybatis02.mapper.StudentMapper.findStuById"></association>
</resultMap>
<!--这里一定要写resultMap,切记不要写成resultType了,否则就不会找到上面写的Map-->
<select id="findAddressById" parameterType="Integer" resultMap="addressMap">
select *
from address
where id = #{id}
</select>
<!--方法二:直接进行联查-->
<!-- 可以使用resultMap配置映射字段,即数据库和javaBean中的对应字段,需要转换的字符可以在association中进行配置 -->
<!-- 这里设置autoMapping可以进行自动封装-->
<resultMap id="addressMap2" type="Address" autoMapping="true">
<result column="id" property="id"/>
<association property="student" column="stu_id" javaType="Student" autoMapping="true">
<id column="stu_id" property="id"></id>
<!-- 这里的id必须加,因为在进行联查的时候将Student的id是stu_id,而在实体类中是id,所以得进行一下转换,否则就将address中的id映射到了student中了 -->
</association>
</resultMap>
<select id="findAddressById2" resultMap="addressMap2">
select *
from address a
inner join student_info s on a.stu_id = s.id
where a.id = #{id}
</select>
<!--方法三:嵌套的resultType-->
<resultMap id="addressMap3" type="Address" autoMapping="true">
<association property="student" column="stu_id" resultMap="stuMap"></association>
</resultMap>
<resultMap id="stuMap" type="Student" autoMapping="true">
<id column="stu_id" property="id"></id>
</resultMap>
<select id="findAddressById3" parameterType="Integer" resultMap="addressMap3">
select a.id,
stu_id,
address,
phone,
consignee,
username,
password,
nickname,
age,
birthday,
del_state,
create_time,
update_time
from address a
inner join student_info s on a.stu_id = s.id
where a.id = #{id}
</select>
</mapper>
2.一对多
接口
package com.tl.mybatis02.mapper;
import com.tl.mybatis02.model.Student;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @author Antg
* @date 2021/8/39:59
*/
public interface StudentMapper {
/***************************** 一对多联查 ***********************************/
//方法一:调用别的mapper中的方法
public Student findoneToMany1(Integer id);
//方法二:直接进行联查,在association中进行转换
public Student findoneToMany2(Integer id);
//方法三:嵌套resultMap
public Student findoneToMany3(Integer id);
}
xml
<?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="com.tl.mybatis02.mapper.StudentMapper">
<!-- ############################### 一对多联查################################# -->
<!-- 方法一:调用别的mapper中的方法 -->
<resultMap id="studentMap1" type="Student" autoMapping="true">
<id column="id" property="id"></id><!--这里的id有合并的作用,去掉后会查询出多条记录,就不对了-->
<collection property="addressList" column="id" autoMapping="true"
select="com.tl.mybatis02.mapper.AddressMapper.findById"></collection>
</resultMap>
<select id="findoneToMany1" parameterType="Integer" resultMap="studentMap1">
select *
from student_info
where id = #{id}
</select>
<!-- 方法二:直接进行联查,在collection中进行转换 -->
<resultMap id="studentMap2" type="Student" autoMapping="true">
<id column="id" property="id"></id><!--这里的id有合并的作用,去掉后会查询出多条记录,就不对了-->
<collection property="addressList" ofType="Address" autoMapping="true">
<id column="address_id" property="id"></id>
</collection>
</resultMap>
<select id="findoneToMany2" parameterType="Integer" resultMap="studentMap2">
select s.id as id,
username,
password,
nickname,
age,
birthday,
a.id as address_id,
stu_id,
address,
phone,
consignee
from student_info s
left join address a
on s.id = a.stu_id
where s.id = #{id}
</select>
<resultMap id="findoneToMany3" type="Student" autoMapping="true">
<id column="id" property="id"></id><!--这里的id有合并的作用,去掉后会查询出多条记录,就不对了-->
<collection property="addressList" column="id" ofType="Address" resultMap="addressMap3"></collection>
</resultMap>
<resultMap id="addressMap3" type="Address">
<id column="address_id" property="id"></id>
</resultMap>
<!-- 方法三:嵌套resultMap -->
<select id="findoneToMany3" parameterType="Integer" resultMap="findoneToMany3">
select s.id as id,
username,
password,
nickname,
age,
birthday,
a.id as address_id,
stu_id,
address,
phone,
consignee
from student_info s
left join address a
on s.id = a.stu_id
where s.id = #{id}
</select>
</mapper>