Mybatis相关知识(2)

Mybatis相关知识

今天接着上期mybatis相关知识进行讲解,今天主要是讲解mybatis和数据库相关的映射,标签和SQL编写等。
会结合实际业务和代码进行讲解。

1 占位符和传参的相关问题
先来看两条xml的SQL。第一条SQL从id名称可知,是根据id删除数据,数据表t_address地址表,参数是Integer类型的id。第二条SQL根据年龄查询用户,参数是Integer类型的age。

<delete id="deleteById" parameterType="Integer">
        delete from t_address where id=#{id}
    delete>

<mapper namespace="com.boger.dao.UserMapper">
    
    <select id="getUsersByAge" resultType="User">
        SELECT * FROM User WHERE age = ${age}
    select>
mapper>

那么来看 两者传参的区别:

#{}是占位符,预编译处理;${}是拼接符,字符串替换,没有预编译处理。
Mybatis在处理#{}时,会将SQL中的#{}替换为?号,调用PreparedStatement的set方法来赋值。#{} 可以有效的防止SQL注入,提高系统安全性;${} 不能防止SQL 注入

单个参数,我们可以这样传递,那么是多个参数该怎么传递呢?
传递多个参数有以下几种方法:
业务需求: 根据院系Id和用户名查询用户。 都是在UserMapper.java文件中定义方法selectUser。
(1) 按照顺序进行传参

public User selectUser(String name, int deptId);  
<select id="selectUser" resultMap="UserResultMap">    
select * from user    where user_name = #{0} and dept_id = #{1}
select>

#{}里面的数字代表传入参数的顺序。这种方法表达不直观,一旦顺序调整就容易出错。因此,不建议使用。

(2) 使用@Param注解进行传递参数

public User selectUser(@Param("userName") String name, int @Param("deptId")deptId);
<select id="selectUser" resultMap="UserResultMap">    
select * from user    where user_name = #{userName} and dept_id = #{deptId}
select>

#{}里面的名称对应的是注解@Param括号里面修饰的名称
可以看到在参数不多的情况推荐使用。

(3) 将参数封装到map传参

public User selectUser(Map<String, Object> paramsMap);
<select id="selectUser" parameterType="java.util.Map" resultMap="UserResultMap">    
select * from user    where user_name = #{userName} and dept_id = #{deptId}
select>

#{}里面的名称对应的是Map里面的key名称
可以看到这种方法适合传递多个参数(尤其是三个及其三个以上),同时参数能灵活传递

(4) 通过Java实体类(javaBean)传参

public User selectUser(User user);
<select id="selectUser" parameterType="com.jourwon.pojo.User"resultMap="UserResultMap">    
select * from user    where user_name = #{userName} and dept_id = #{deptId}
select>

参数User就是java实体类,#{}里面的名称对应的是User类里面的成员属性。此方法扩展不易,但代码可读性强,推荐使用。

2 模糊匹配的SQL
推荐常使用的两种模糊查询写法。
第一种: “%”#{param}“%”
第二种: CONCAT(’%’,#{param},’%’) 使用CONCAT()函数
例如: 业务要求: 根据输入的字符串用户名查询用户。在UserMapper.java文件定义方法selectByCondition。

User selectByCondition(String queryString);

第一种写法:

<select id="selectByCondition" parameterType="String" resultType="com.boger.User">
        select * from t_user
            where queryString like "%"#{value}"%"
    select>

第二种写法:

<select id="selectByCondition" parameterType="String" resultType="com.boger.User">
        select * from t_user
            where queryString CONCAT(’%’,#{value},’%’) 
    select>

3 Mybatis如何获取生成的主键
在标签中使用 useGeneratedKeys 和 keyProperty 两个属性来获取自动生成的主键值
示例:

<insert id=”AddUser” usegeneratedkeys=”true”   keyproperty=”id”>  
  insert into user(name) values (#{name})  
insert>  

当然,除了使用 useGeneratedKeys 和 keyProperty,还可以使用下面的标签。

<selectKey resultType="int" order="AFTER" keyProperty="id">
     SELECT LAST_INSERT_ID()
    selectKey>

于是上面的写法,就变为了下面的完整的SQL.

<insert id=”AddUser” >  
  <selectKey resultType="int" order="AFTER" keyProperty="id">
     SELECT LAST_INSERT_ID()
    selectKey>
  insert into user(name) values (#{name}) 
insert>  

4 Mybatis的批量操作
在 MyBatis 中执行批量操作,可以使用批量插入(batchInsert)、批量更新(batchUpdate)等方法来提高数据库操作的效率。下面用一个批量插入学生到数据库作为案例。


<mapper namespace="com.boger.dao.UserMapper">
    
    <insert id="batchInsertUsers" parameterType="java.util.List">
        INSERT INTO User (name, age) VALUES
        <foreach collection="list" item="user" separator=",">
            (#{user.name}, #{user.age})
        foreach>
    insert>
mapper>

使用的是foreach标签。foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合
上述sql语句中,collection表示的是接收的集合数据,item表示的是集合中每一个元素进行迭代时的别名。separator 表示在每次进行迭代之间以什么符号作为分隔符,常用“,”;

这里collection的属性需要特别注意:
传入的是单参数且参数类型是一个List的时候,collection属性值为list
传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array
传入的参数是多个的时候,就需要把它们封装成一个Map,map的key就是参数名,所以这个时候collection属性值就是传入的List或array对象在自己封装的map里面的key。

5 当实体类中的属性名和数据库表中的字段名不一样的解决方案
(1) 通过在查询的SQL语句中定义字段名的别名,让字段名的别名和实体类的属性名一致
(2) 通过resultMap标签来映射字段名和实体类属性名的一一对应的关系,其中,property表示实体类属性,column表示数据库列名。通常这里容易忽视主键id的映射。id映射需要单独映射。如下图:
Mybatis相关知识(2)_第1张图片
6 mapper接口的原理
通常我们在建立好mapper接口(也称为Dao接口),就需要建立好对应的mapper的xml。例如,UserMapper.java或者UserDao.java。就会有对应的UserMapper.xml或者UserDao.xml。我们注意到,这个接口,没有实现类。
mapper接口的原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为Dao(mapper)接口生成代理proxy对象,代理对象proxy会拦截接口方法,转而执行MappedStatement所代表的sql,然后将sql执行结果返回

同时,也需要注意,mapper对应的xml文件,里面通常会设置命名空间(namespace)。即

<mapper namespace="com.boger.DictMapper"> mapper>

如果没有配置命名空间,id就不能重复。但是,在实际运用中,我们都会配置命名空间,让代码更规范。此时id就能重复。举个例子,有UserMapper TeacherMapper,我们就会创建对应的UserMapper.xml和TeacherMapper.xml。里面配置命名空间,但UserMapper和TeacherMapper里面都可以有id为selectAll的方法(查询所有)。只不过一个查询所有用户,一个查询所有讲师。职责更明确。

7 Mybatis的动态SQL
动态SQL是MyBatis的强大特性之一, 基于功能强大的OGNL表达式
动态SQL主要是来解决查询条件不确定的情况,在程序运行期间,根据提交的条件动态的完成查询

mybatis常用的动态SQL标签:
if choose when otherwise foreach set where

下面通过举例来说明:
案例1:
if:用于条件判断,根据条件决定是否包含某部分SQL语句
where: 使用where标签生成WHERE子句


<mapper namespace="com.boger.dao.UserMapper">
    
    <select id="getUsersByCondition" resultType="User">
        SELECT * FROM User
        <where>
            <if test="name != null">
                AND name = #{name}
            if>
            <if test="age != null">
                AND age = #{age}
            if>
        where>
    select>
mapper>

如果name参数不为null,则在SQL语句中添加AND name = #{name}的条件;如果age参数不为null,则在SQL语句中添加AND age = #{age}的条件。这样可以根据不同的条件生成不同的SQL查询语句。

案例2:
choose、when、otherwise元素:类似于Java中的switch语句,用于根据不同的条件选择执行不同的分支


<mapper namespace="com.boger.dao.UserMapper">
    
    <select id="getUsersByCondition" resultType="User">
        SELECT * FROM User
        <where>
            <choose>
                <when test="name != null">
                    AND name = #{name}
                when>
                <when test="age != null">
                    AND age = #{age}
                when>
                <otherwise>
                    AND status = 'active'
                otherwise>
            choose>
        where>
    select>
mapper>

如果name参数不为null,则在SQL语句中添加AND name = #{name}的条件;如果age参数不为null,则在SQL语句中添加AND age = #{age}的条件;如果以上条件都不满足,则在SQL语句中添加AND status = 'active’的条件。

案例3:
foreach元素:用于遍历集合或数组,并将元素应用到SQL语句中 ,在上述批量插入已讲解,这里不多赘述。

案例4:
使用 set 标签可以方便地生成 UPDATE 语句中的 SET 子句,根据不同的条件动态设置更新的字段。

<mapper namespace="com.boger.dao.UserMapper">
    
    <update id="updateUser" parameterType="User">
        UPDATE User
        <set>
            <if test="name != null">
                name = #{name},
            if>
            <if test="age != null">
                age = #{age},
            if>
        set>
        WHERE id = #{id}
    update>
mapper>

如果传入的 User 对象中的 name 属性不为 null,则将 name 字段包含在 SET 子句中;如果传入的 User 对象中的 age 属性不为 null,则将 age 字段包含在 SET 子句中。

8 Mybatis执行一对一和一对多的查询
实现方式:
(1) 单独发送一个SQL去查询关联对象,赋给主对象,然后返回主对象
(2) 嵌套查询和关联映射。 (推荐使用)

首先是一对一 使用标签 association
案例如下: 假设有两个表,User 表和 Address 表,一个用户对应一个地址。


<mapper namespace="com.boger.dao.UserMapper">
    
    <select id="getUserWithAddress" resultMap="userWithAddressResultMap"  parameterType="Integer">
        SELECT u.id, u.name, u.age, a.id AS address_id, a.city, a.street
        FROM User u
        LEFT JOIN Address a ON u.id = a.user_id
        WHERE u.id = #{userId}
    select>

    
    <resultMap id="userWithAddressResultMap" type="User">
        <id property="id" column="id" />
        <result property="name" column="name" />
        <result property="age" column="age" />
        <association property="address" javaType="Address">
            <id property="id" column="address_id" />
            <result property="city" column="city" />
            <result property="street" column="street" />
        association>
    resultMap>
mapper>

getUserWithAddress 方法通过 LEFT JOIN 连接 User 表和 Address 表,查询指定用户及其地址信息。
使用 resultMap 标签定义了 userWithAddressResultMap 结果映射,将查询结果映射到 User 对象,并通过 association标签将 Address 对象关联到 User 对象的 address 属性上。

java代码如下:

UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.getUserWithAddress(1);

执行 getUserWithAddress 方法,将会查询指定 userId为1 的用户及其关联的地址信息,将结果映射到 User 对象中。

一对多使用标签collection
案例如下: 假设有两个表,User 表和 Order 表,一个用户可以有多个订单。


<mapper namespace="com.boger.dao.UserMapper">
    
    <select id="getUserWithOrders" resultMap="userWithOrdersResultMap">
        SELECT u.id, u.name, u.age, o.id AS order_id, o.order_number, o.order_date
        FROM User u
        LEFT JOIN Orders o ON u.id = o.user_id
        WHERE u.id = #{userId}
    select>

    
    <resultMap id="userWithOrdersResultMap" type="User">
        <id property="id" column="id" />
        <result property="name" column="name" />
        <result property="age" column="age" />
        <collection property="orders" ofType="Order">
            <id property="id" column="order_id" />
            <result property="orderNumber" column="order_number" />
            <result property="orderDate" column="order_date" />
        collection>
    resultMap>
mapper>

getUserWithOrders 方法通过 LEFT JOIN 连接 User 表和 Order 表,查询指定用户及其订单信息。
使用 resultMap标签定义了 userWithOrdersResultMap 结果映射,将查询结果映射到 User 对象,并通过 collection标签将多个 Order 对象关联到 User 对象的 orders 属性上。

Java 代码如下:

UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.getUserWithOrders(1);

执行 getUserWithOrders 方法,将会查询指定 userId 为1的用户及其关联的订单信息,将结果映射到 User 对象中,并通过 orders 属性获取用户的订单列表。

关于mybatis相关的SQL编写 标签大致等就差不多到此为止了。欢迎收看,下期再见。

你可能感兴趣的:(java,mybatis,java,数据库)