MyBatis02

MyBatis(第2天)-基本使用

项目结构

  1. mybatis_day02_01_xml用户的增删改查操作

  2. mybatis_day02_02_old传统DAO实现类方式

  3. mybatis_day02_03_anno注解方式

  4. mybatis_day02_04_dynamic_sql动态SQL

mybatis框架的学习,不要纠结,不要老想wsm,我们的目标使用mybatis,等我们框架使用熟练后,看源码学习.

三种开发方式

  1. mapper接口代理的开发方式(重点)
  2. 使用注解的开发方式
  3. 传统DAO实现类的开发方式(目前基本淘汰)

接口代理方式:搭建项目环境

目标

搭建Mybatis项目环境

[外链图片转存失败(img-Zc8ozGUQ-1565188451528)(/1562577845493.png)]

数据库SQL语句
CREATE TABLE USER (
  id INT PRIMARY KEY AUTO_INCREMENT,
  username VARCHAR(20) NOT NULL,
  birthday DATE,
  sex CHAR(1) DEFAULT '男',
  address VARCHAR(50)
);

INSERT INTO USER VALUES (NULL, '孙悟空','1980-10-24','男','花果山水帘洞');
INSERT INTO USER VALUES (NULL, '白骨精','1992-11-12','女','白虎岭白骨洞');
INSERT INTO USER VALUES (NULL, '猪八戒','1983-05-20','男','福临山云栈洞');
INSERT INTO USER VALUES (NULL, '蜘蛛精','1995-03-22','女','盤丝洞');
实现步骤
  1. 创建模块,加入依赖包
  2. 复制核心配置文件sqlMapConfig.xml和log4j.properties到src下
创建模块,加入依赖包

[外链图片转存失败(img-9AaWdtuM-1565188451532)(/)]

准备核心配置文件

sqlMapConfig.xml和log4j.properties

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--可以配置多个环境,可以访问不同种类的数据库:mysql, oracle-->
    <environments default="default">
        <!-- 其中的一个配置环境,这个配置方案的唯一标识 -->
        <environment id="default">
            <!--
            指定事务管理器的类型:
            JDBC:使用JDBC来管理事务
            -->
            <transactionManager type="JDBC"/>
            <!--
            数据源的类型:
            1. POOLED:使用mybatis创建的连接池
            2. UNPOOLED:不使用连接池,每次都创建和关闭连接
            -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <!--加载接口映射文件-->
    <mappers>
        
    </mappers>
</configuration>

小结

搭建mybatis项目步骤

[外链图片转存失败(img-gWqcUfIV-1565188451532)(/)]

  1. 创建模块
  2. 导入jar包
  3. 复制核心配置文件到src下
  4. 修改数据库的参数

接口代理方式:根据用户ID查询用户

目标

根据用户 ID 查询用户

步骤分析
  1. 编写用户User的实体类
  2. 编写用户UserMapper接口
  3. 配置接口映射文件UserMapper.xml
  4. 使用SqlSession来执行Mapper的方法
编写用户User的实体类
package com.itheima.entity;

import java.sql.Date;

/**
 用户实体类对象 */
public class User {
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;

   // 省略构造方法/getter/setter/toString
}
编写用户UserMapper接口
public interface UserMapper {
    /*
    通过id查询到一个用户
    */
    User findUserById(Integer id);
}
创建UserMapper.xml文件

在com.itheima.dao包下创建UserMapper.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.itheima.dao.UserMapper">
    <!--parameterType:方法参数的类型-->
    <!--resultType:方法返回值类型-->
    <!--#{}:相当于?占位符,#{id}:得到方法的id参数放在这个位置-->
    <select id="findUserById" parameterType="java.lang.Integer" resultType="com.itheima.entity.User">
        SELECT * FROM USER WHERE id=#{id};
    </select>
</mapper>

在mapper中配置上面的UserMapper.xml文件

<!--配置接口映射文件-->
<mappers>
    <mapper resource="com/itheima/dao/UserMapper.xml"/>
</mappers>
测试
public class TestUserMapper {
    @Test
    public void test01() throws IOException {
        InputStream in = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sessionFactory = builder.build(in);
        SqlSession sqlSession = sessionFactory.openSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User userById = mapper.findUserById(2);
        System.out.println("userById = " + userById);
    }
}

[外链图片转存失败(img-FA62pyXt-1565188451532)(/)]

小结

  1. 如何取到方法的参数放到sql中

[外链图片转存失败(img-jWeL7kSy-1565188451532)(/)]

[外链图片转存失败(img-O0bXrr6H-1565188451536)(/)]

#{id}: 先使用?占位,再取出方法的id这个参数,放到这个位置

[外链图片转存失败(img-1fX5WGuc-1565188451536)(/)]

核心配置文件:properties标签

目前我们将数据库相关的信息都是配置在核心配置文件中,如果核心配置文件中的内容很多,那么修改的时候就不是很方便。我们可以将数据库的配置信息专门放到一个单独的文件中,使用properties标签引入即可。

目标

学习properties标签的作用

sqlMapConfig.xml元素概述

sqlMapConfig.xml是mybatis框架的核心配置文件,目前我们在其中配置了运行环境(数据源)和加载映射文件。该配置文件中还有其它的一些配置。 [外链图片转存失败(img-g2dXnj0n-1565188451536)()]

properties的作用

将外面的属性文件(.properties)加载进来。在后面就可以引用属性文件中的键和值

操作步骤

编写数据库连接属性资源文件(jdbc.properties)

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=root

在核心配置文件中通过properties标签加载jdbc.properties属性资源文件

<!--
    属性:
    resource: 指定类路径下Java的属性文件
    url: 在指定的地址上得到一个Java的属性文件。 协议名://地址/资源名. 
    <properties url="http://www.itheima.com/db.properties"/>
    如果内部和外部有相同的键,使用外部的
    -->
    <properties resource="db.properties">
        <property name="jdbc.password" value="root"/>
    </properties>

小结

  1. properties作用是什么?

    引入外部.properties文件.

    [外链图片转存失败(img-jEmuEoVy-1565188451536)(/)]

  2. 内部配置的property和外面配置的properties如果同名,使用哪个?

    使用外部的

核心配置文件:typeAliases别名

[外链图片转存失败(img-xT1CJUB6-1565188451536)(/)]

我们在接口映射文件中指定参数或返回值类型时,需要写出具体的包名和类名,是比较麻烦的。我们可以通过别名更简单,比如中华人民共和国,简称中国。

目标

学习typeAliases标签的使用

typeAliases作用

typeAliases别名,简化类型的书写。

内置别名
别名映射类型
stringString
byteByte
longLong
shortShort
intInteger
integerInteger
doubleDouble
floatFloat
booleanBoolean
dateDate
decimalBigDecimal
bigdecimalBigDecimal
objectObject
mapMap
hashmapHashMap
listList
arraylistArrayList
collectionCollection
iteratorIterator

说明:

  • 内置别名可以直接使用

  • 别名不区分大小写

自定义类取别名方式一:typeAlias
  1. 在配置文件中将用户指定别名为user
  2. 将结果类型设置为user
  3. 省略alias的情况
<typeAlias type="com.itheima.entity.User" alias="User"/>
<typeAlias type="com.itheima.entity.User"/>

[外链图片转存失败(img-eRK6Fqca-1565188451536)(/)]

自定义类取别名方式二:包扫描配置别名package

如果有很多类,那么都需要取别名,一个一个取别名太麻烦了。可以使用包扫描方式。

 <!--
    定义别名
    typeAlias 子元素
        type: 类全名
        alias: 别名,可以省略。默认使用类名做为别名,不区分大小写
    package子元素:
        给包里面所有类取别名, 别名就是类名,不区分大小写
 -->
 <typeAliases>
      <package name="com.itheima.entity"/>
</typeAliases>

小结

typeAlias标签的作用:

​ 给类取别名

package标签的作用:

​ 包扫描,将这个包里面所有的类都取别名,别名就是类名

[外链图片转存失败(img-X9GVqTr2-1565188451536)(/)]

核心配置文件:mappers(映射器)

目标

学习mappers标签的使用

作用

作用:加载接口映射文件

方式一:加载单个映射文件

mapper标签的属性

<!--映射器-->
<mappers>
    <!--
    resource: 指定类路径下映射文件,注:路径使用/做为分隔符,而不是点号
    class: 指定使用注解的接口名字
     -->
    <mapper resource="mapper/UserMapper.xml"/>
</mappers>

注:如果是多级目录,是/而不是点号

方式二:包扫描加载多个映射文件

包扫描方式加载mapper映射文件

  1. 要求接口映射文件,与接口要放在同一个目录

  2. 要求接口映射文件的名称,与接口的名称要一致

<!--配置接口映射文件-->
<mappers>
    <!--
    package标签:
        接口映射文件与接口文件在同一个目录
        接口映射文件的名称与接口文件的名称相同
    -->
    <package name="com.itheima.dao"/>
</mappers>

小结

properties作用?

引入外部.properties文件,可以将一部分的配置信息放到另外的文件

[外链图片转存失败(img-ouJn2e3E-1565188451536)(/)]

typeAliases作用?

给类取别名,使用简单,建议使用包扫描的方式

[外链图片转存失败(img-XXAkWLxJ-1565188451540)(/)]

mappers作用?

配置接口映射文件的位置,推荐使用包扫描

[外链图片转存失败(img-oanKvTXL-1565188451540)(/)]

接口代理方式:新增用户

目标

  1. 添加用户
  2. 学习mybatis处理事务
效果

[外链图片转存失败(img-Q879pmhv-1565188451540)()]

实现步骤
  1. 在mapper接口定义新增用户方法
  2. 配置mapper映射文件
  3. 测试
在mapper接口定义新增用户方法
/**
 * 新增用户
 */
void addUser(User user);
配置mapper映射文件
  1. 新增用户使用insert标签
  2. 放置新增sql语句,参数类型使用User
  3. 占位符使用user对象的各个#{属性名}
<!--
insert标签:表示添加记录
id: 方法名
如果参数是实体类,#{属性名}
-->
<insert id="addUser" parameterType="user">
   INSERT INTO user VALUES (null, #{username}, #{birthday},#{sex},#{address})
</insert>
测试
new User(null,"白龙马",Date.valueOf("2019-05-01"),"男","东海龙宫");
  • 事务的处理:如果Java程序代码执行成功,但是数据库中并没有新增记录。原因是没有提交事务,在对数据库的更新操作中(增、删、改)要求提交事务。
提交事务
方式一:手动提交事务
sqlSession.commit();  // 方式一:手动提交事务
方式二:自动提交事务
sqlSession = factory.openSession(true);  // 方式二:自动提交

说明:如果在同一个方法中,有多个数据库操作,需要使用手动提交的方式。

小结

添加一条记录,步骤:

  1. 在接口中新增一个方法

[外链图片转存失败(img-kIQMHreP-1565188451540)(/)]

  1. 在接口映射文件中添加SQL语句

    [外链图片转存失败(img-FImPR9lv-1565188451540)(/)]

  2. 参数是实体对象的时候,占位符#{}中的变量名是什么?

    写对象的成员变量名

  3. 作开启事务有哪两种方式?

    手动提交: sqlSession.commit();

    自动提交: 在得到SqlSession的时候,传入参数:true

    factory.openSession(true);

查询新增记录的主键值

上面的添加方法是返回影响的行数,如果要得到添加的主键值怎么操作?

说明:当数据库表中,主键字段值由数据库维护(比如mysql中的自增长),那么在新增完一条记录以后,如何获取到数据库维护的主键值呢?

目标

通过子元素<selectKey>得到新增记录的主键值

通过子元素useGeneratedKeys得到新增记录的主键值

需求效果

[外链图片转存失败(img-wjWjamB4-1565188451544)()]

方式一:子元素<selectKey>(常用)

mysql中的函数:**last_insert_id() **:得到最后添加的主键

原理:在insert语句执行后再执行一条查询语句,返回新增主键的id

属性说明
keyColumn主键在表中的字段:user表中id列
keyProperty实体类中主键的属性名 User中id
resultType主键类型,int类型
orderBEFORE: 在insert之前执行
AFTER: 在insert之后执行
<!--
insert标签:表示添加记录
id: 方法名
如果参数是实体类,#{属性名}
-->
<insert id="addUser2" parameterType="user">
    <!--
     keyColumn  主键在表中的字段:user表中id列
     keyProperty 实体类中主键的属性名 User中id
     resultType 主键类型,int类型
     order
        BEFORE: 在insert之前执行
        AFTER: 在insert之后执行
     -->
    <selectKey keyColumn="id" keyProperty="id" resultType="int">
        SELECT LAST_INSERT_ID();
    </selectKey>
   INSERT INTO user VALUES (null, #{username}, #{birthday},#{sex},#{address})
</insert>

测试代码

//添加记录
@Test
public void testAddUser() {
    //在mybatis中默认是手动提交事务,增删改要提交事务
    //Date.valueOf(字符串),将字符串转成日期,格式一定要是yyyy-MM-dd
    User user = new User(null,"白龙马", Date.valueOf("2019-05-01"),"男","东海龙宫");
    int row = userMapper.addUser(user);
    System.out.println("user = " + user);
}
方式二:在insert标签中增加属性
属性说明
useGeneratedKeystrue,使用mysql生成的主键
keyColumn表中主键对应的字段
keyProperty实体类中对应的属性

映射文件

<!--
insert标签:表示添加记录
id: 方法名
如果参数是实体类,#{属性名}
-->
<insert id="addUser" parameterType="user" keyColumn="id" keyProperty="id" useGeneratedKeys="true">
   INSERT INTO user VALUES (null, #{username}, #{birthday},#{sex},#{address})
</insert>
  • 说明:直接在insert标签中增加属性的方式,只适合于支持自动增长主键类型的数据库,比如MySQL或SQL Server。

小结

  1. 得到主键值有哪两种方式?

    1. <selectKey>
    

    [外链图片转存失败(img-lxdUNNvU-1565188451544)(/)]

2.在insert标签中添加 useGenerateKeys

[外链图片转存失败(img-NWGJzF2V-1565188451544)(/)]

接口代理方式:修改数据

目标

通过id修改用户数据

实现步骤
  1. 在接口中编写一个修改用户的方法
  2. 在接口映射文件中编写相应的SQL语句
  3. 测试
在接口中编写一个修改用户的方法
/**
 * 根据用户Id修改用户
 */
void updateUser(User user);
在接口映射文件中编写相应的SQL语句

使用update标签:放置修改sql语句,根据用户id修改用户其它属性

<!--
update标签更新记录
id: 方法名字
parameterType: 参数的类型
-->
<update id="updateUser" parameterType="user">
    UPDATE user set username=#{username}, birthday=#{birthday}, sex=#{sex}, address=#{address} where id=#{id}
</update>
测试
  1. 修改6号用户的名字,生日,性别,地址
  2. 更新用户对象
//更新记录
@Test
public void testUpdateUser() {
    User user = new User(6, "狐狸精",Date.valueOf("1996-05-10"),"女","狐狸洞");
    userMapper.updateUser(user);
}

小结

修改数据的步骤:

1.在接口定义一个修改的方法

[外链图片转存失败(img-DOSG4FZb-1565188451544)(/)]

2.在接口映射文件中添加对应SQL语句

[外链图片转存失败(img-OGcYb1JL-1565188451544)(/)]

3.测试

编写修改的SQL语句使用哪个标签?

update标签

接口代理方式:删除数据

目标

根据id删除数据

效果

[外链图片转存失败(img-McBJKZen-1565188451544)()]

实现步骤
  1. 在接口中编写一个删除用户的方法
  2. 在接口映射文件中编写相应的SQL语句
  3. 测试
在接口中编写一个删除用户的方法
/**
 * 根据用户id删除用户
 */
void deleteUser(int id);
在接口映射文件中编写相应的SQL语句

delete标签:放置删除sql语句,根据用户Id删除用户

<!--
delete标签用于删除记录
-->
<delete id="deleteUser" parameterType="int">
     DELETE from user where id=#{id}
</delete>
测试

删除11号用户

//删除记录
@Test
public void testDeleteUser() {
    userMapper.deleteUser(11);
}

接口代理开发方式小结

  1. mapper映射文件中namespace属性值写?接口的类全名

  2. mapper映射文件

    1. sql语句标签中的id属性值写?方法名

    2. sql语句标签中的parameterType属性值写?方法参数类型

    3. sql语句标签中resultType属性值写?方法返回值类型

      如果方法参数或返回值是基本数据类型可以省略不写

mybatis模糊查询

目标

使用接口代理方式模糊查询用户

[外链图片转存失败(img-mxZ4uTAC-1565188451544)()]

实现步骤
  1. 在接口中编写一个模糊查询的方法
  2. 在接口映射文件中编写相应的SQL语句
  3. 测试

方式一

在接口中编写一个模糊查询的方法
/**
 通过用户名模糊查询用户
*/
List<User> findUsersByName(String username);
在接口映射文件中编写相应的SQL语句
SELECT * FROM user WHERE username LIKE '%精%';
<select id="findUserByname" parameterType="string" resultType="user">
    SELECT * FROM user WHERE username LIKE #{name};
</select>
测试

查询名字中包含"精"字的用户

// 按名字模糊查询用户
@Test
public void testFindUsersByName() {
    List<User> list = mapper.findUserByname("%精%");
    for (User user : userList) {
        System.out.println(user);
    }
}

[外链图片转存失败(img-s9cwa3th-1565188451548)(/)]

方式二

在接口映射文件中编写相应的SQL语句
<select id="findUserByname" parameterType="string" resultType="user">
    SELECT * FROM user WHERE username LIKE '%${value}%';
</select>
测试2

查询名字中包含"精"字的用户

// 按名字模糊查询用户
@Test
public void testFindUsersByName() {
    List<User> list = mapper.findUserByname("精");
    for (User user : userList) {
        System.out.println(user);
    }
}

[外链图片转存失败(img-DdmiyEXs-1565188451548)(/)]

小结

[外链图片转存失败(img-w08jx3NE-1565188451548)()]

接口映射文件:三种参数类型

目标

  1. Java简单类型

  2. POJO实体类型

  3. POJO包装类型

简单类型

什么是简单类型:基本数据类型的8种+String,包括对应的包装类

[外链图片转存失败(img-ppVk0h1X-1565188451548)()]

POJO类型

POJO(Plain Ordinary Java Object)简单的Java对象,实际就是普通JavaBean,即我们前面封装数据使用的实体类

[外链图片转存失败(img-caNcigQB-1565188451548)()]

POJO包装类型

什么是POJO包装类型:就是在实体类中包含了其它的实体类

public class QueryVo {
    private User user;
    private String start;
    private String end;
}

案例: POJO包装类型的演示

目标

实现多条件查询,出生日期在start属性和end属性之间

方法定义多个参数方式实现实现多条件查询

SELECT * FROM user WHERE birthday BETWEEN1 AND2;

接口

List<User> findUsersByBirthday(String start, String end);

接口映射文件

<select id="findUsersByBirthday" parameterType="string" resultType="user">
    SELECT * FROM user WHERE birthday BETWEEN #{arg0} AND #{arg1};
</select>

测试

@Test
public void test10() throws IOException {
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    List<User> list = mapper.findUsersByBirthday("1990-01-01", "2018-01-01");
    for (User user : list) {
        System.out.println("user = " + user);
    }

    sqlSession.close();
}

存在的问题,SQL语句可读性太差

POJO包装类型实现多条件查询

编写POJO包装类型

VO: Value Object 值对象,实体类

package com.itheima.entity;

/**
 包装类
 */
public class QueryVo {
    private User user;  // 包含用户对象
    private String start; // 开始日期
    private String end; // 结束日期

	// 省略getter/setter
}
声明mapper接口方法
/**
 * 使用POJO包装类型,根据用户名称,开始和结束生日,模糊查询用户
 */
List<User> findUsersByCondition(QueryVo queryVo);
配置mapper映射文件
<!--
queryVo:要定义别名
占位符,拼接符要使用实体类的属性名
-->
<select id="findUsersByCondition" parameterType="queryvo" resultType="user">
    SELECT * FROM user WHERE id < #{user.id} AND birthday BETWEEN #{start} AND #{end};
</select>
测试
@Test
public void testFindUsersByCondition() {
	UserMapper mapper = sqlSession.getMapper(UserMapper.class);
	QueryVo vo = new QueryVo();
	User u = new User(10, "老宋", Date.valueOf("2000-02-02"), "男", "东莞");
	vo.setUser(u);
	vo.setStart("1990-01-01");
	vo.setEnd("2018-01-01");
	List<User> list = mapper.findUsersByCondition(vo);
	for (User user : list) {
	    System.out.println("user = " + user);
	}

	// 手动提交事务
	sqlSession.commit();
	sqlSession.close();
}

小结

三种参数输入类型分别是:

  1. 简单类型

    8种基本数据类型/包装类 + String
    
  2. POJO类型

    简单的Java类型。POJO类型就是JavaBean
    
  3. POJO包装类型

    优点是方便传入多个参数。
    
    public class QueryVo {
        private User user;  // 包含用户对象
        private String start; // 开始日期
        private String end; // 结束日期
    
    	// 省略getter/setter
    }
    

接口映射文件:resultType输出类型

目标

学习输出结果resultType的两种类型

  1. 简单类型
  2. POJO类型
resultType的两种类型

java简单类型
[外链图片转存失败(img-ploKec4l-1565188451552)(/)]

POJO类型
[外链图片转存失败(img-pLZyTpSr-1565188451552)(/)]

java简单类型练习

统计用户表中女生的数量

[外链图片转存失败(img-3ur5vRkV-1565188451552)()]

声明mapper接口方法

/**
 * 统计用户表中某种性别的数量
 */
int getAmountBySex(String sex);

配置mapper映射文件

<!-- 统计用户表中的女生的用户数量 -->
<select id="getAmountBySex" resultType="int" parameterType="string">
    select count(*) from user where sex=#{sex}
</select>

测试

// 查询有多少个女生
@Test
public void testGetAmountBySex() {
    int amount = userMapper.getAmountBySex("女");
    System.out.println("女生数量是:" + amount);
}

小结

resultType的输出类型有哪两种?

  1. POJO类型

  2. 简单类型

    resultType是简单类型也不能省略

接口映射文件:resultMap输出映射

mybatis可以把查询的结果自动封装为对象。但是有要求:数据库中的列名称,要与对象的属性一致。否则不能正确封装数据。

当查询的列与对象属性不一致时候,使用resultMap解决。resultMap可以建立查询的列与对象属性的对应关系。

SELECT id id2, username username2, birthday birthday2, sex, address FROM user WHERE id = 2;

查询一张表时,查询的字段名字和类的中的成员变量不一样,设置为null,名称一样的就有值

目标

使用resultMap对查询结果进行映射

配置mapper映射文件
  1. 定义resultMap标签
  2. id标签:映射主键字段,如果列名与属性名相同可以省略
  3. result标签:映射普通字段,指定哪个属性对应哪个列
  4. 在查询的结果中使用resultMap
<!--
   定义结果映射
       id: 映射的唯一标识
       type: 最终结果转换后的类型

   子元素:
       id: 定义主键字段的映射
       result: 定义普通的字段的映射
           属性:property: 实体类中属性名,column: 表中列名,如果相同可以不写。
->
<resultMap id="u1" type="user">
    <id column="id2" property="id"/>
    <result column="username2" property="username"/>
    <result column="birthday2" property="birthday"/>
</resultMap>
<select id="findUserByIdUseResultMap" parameterType="int" resultMap="u1">
    SELECT id id2, username username2, birthday birthday2, sex, address FROM user WHERE id = #{id};
</select>

测试,查询id为1的用户

@Test
public void test09() throws IOException {
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User user = mapper.findUserByIdUseResultMap(2);
    System.out.println("user = " + user);
    // 手动提交事务
    sqlSession.close();
}
映射流程

[外链图片转存失败(img-C2JIsY6b-1565188451552)(/)]

映射文件的标签小结

<select>
用于执行查询的SQL

<insert>
用于执行插入的SQL

<update>
用于执行修改的SQL

<delete>
用于执行删除的SQL

<resultMap>
对查询的结果进行映射

传统的DAO实现类的开发方式[了解]

目标

使用传统的DAO实现类开发方式

  1. 查询id的用户
  2. 添加1条记录
复制新的项目
  1. 在 windows 下将 mybatis-day02-01-xml 复制成 mybatis-day02-02-old
  2. 在 windows 下将 mybatis-day02-01-xml.iml 的文件名改成 mybatis-day02-02-old.iml
  3. 导入mybatis-day02-02-old项目
编写UserMapper接口
public interface UserMapper {
    /*
    通过id查询到一个用户
    */
    User findUserById(Integer id);

    void addUser(User user);
}
编写UserMapper接口映射文件
<?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.itheima.dao.UserMapper">
    <select id="findUserById" parameterType="int" resultType="uSer">
        SELECT * FROM USER WHERE id=#{id};
    </select>

    <insert id="addUser" parameterType="user">
        INSERT INTO user (username, birthday, sex, address) VALUES (#{username}, #{birthday}, #{sex}, #{address});
    </insert>
</mapper>
编写接口实现类UserMapperImpl
package com.itheima.dao;

import com.itheima.entity.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;

public class UserMapperImpl implements UserMapper {
    private static SqlSessionFactory factory;

    static {
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        factory = builder.build(UserMapperImpl.class.getResourceAsStream("/sqlMapConfig"));
    }

    @Override
    public User findUserById(Integer id) {
        SqlSession session = factory.openSession();
        User user = session.selectOne("com.itheima.dao.UserMapper.findUserById", id);
        session.close();
        return user;
    }

    @Override
    public int addUser(User user) {
        SqlSession session = factory.openSession();
        int insert = session.insert("com.itheima.dao.UserMapper.addUser", user);
        session.commit();
        session.close();
        return insert;
    }
}
编写测试类
public class TestUserMapper {
    @Test
    public void test01() {
        UserMapperImpl dao = new UserMapperImpl();

        User user = dao.findUserById(7);
        System.out.println("user = " + user);
    }

    @Test
    public void test02() {
        UserMapperImpl dao = new UserMapperImpl();
        User u = new User(10, "小王", Date.valueOf("2022-02-02"), "男", "深圳");
        dao.addUser(u);
    }
}

小结

传统的DAO实现类的开发方式和接口实现类的方式区别?

DAO实现类多需要接口的实现类,在实现类中找到SQL语句执行.

注解开发方式:搭建项目环境

目标

搭建注解项目环境

新建项目

项目名为:mybatis02_03_anno_crud
[外链图片转存失败(img-Ioa54Rf1-1565188451552)(/)]

<!--我们没有编写UserMapper.xml,会扫描UserMapper接口,得到接口里面的注解和方法也能生成代理对象-->
<mappers>
    <package name="com.itheima.dao"/>
</mappers>

注解开发方式:查询

目标

通过注解方式实现:根据用户id查询用户

编写UserMapper接口,在方法上配置注解

public interface UserMapper {
    /*
     通过id查询1个用户
     会执行方法上面的注解里面的SQL语句
     Select表示执行查询的SQL
     */
    @Select("SELECT * FROM user WHERE id=#{id};")
    User findUserById(Integer id);
}

编写测试类

// 查询1个用户对象
@Test
public void testFindUserById() throws IOException {
    SqlSession sqlSession = sessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User user = mapper.findUserById(4);
    System.out.println("user = " + user);
}

小结

注解方式操作Mybatis步骤

  1. 在接口中定义操作数据库的方法

  2. 在方法上配置注解:@Select(“SQL语句”)

  3. 测试

    [外链图片转存失败(img-hxhWOLU4-1565188451552)(/)]

使用@Results和@Result属性

需求变化

通过注解方式实现:根据id查询user表中一条记录,对结果封装

注解说明

注解属性说明
@Results相当于resultMap表示要对结果进行映射
@Result对一个字段进行映射
column查询的字段名
property类中的成员变量名
idtrue 表示是主键
<resultMap id="u1" type="user">
    <id column="id2" property="id"/>
    <result column="username2" property="username"/>
    <result column="birthday2" property="birthday"/>
</resultMap>

<select id="findUserByIdUseResultMap" parameterType="int" resultType="user">
    SELECT id id2, username username2, birthday birthday2, sex, address FROM user WHERE id = #{id};
</select>

UserMapper接口代码

// 查询的SQL语句
@Select("SELECT id id2, username username2, birthday birthday2, sex, address FROM user WHERE id = #{id};")
// 将结果集封装成对象
@Results({
        // 一个字段转成一个对象的属性
        @Result(id = true, column = "id2", property = "id"),
        @Result(column = "username2", property = "username"),
        @Result(column = "birthday2", property = "birthday")
})
User findUserById2(Integer id);

小结

@Select注解作用?

存放查询的SQL语句

@Results注解作用?

表示对查询的结果进行映射

@Result注解作用?

对一个字段进行映射

[外链图片转存失败(img-ogSmEAij-1565188451552)(/)]

注解开发方式:修改和删除

目标

通过注解方式实现:

  1. 根据用户id修改用户

  2. 根据用户id删除用户

  3. 添加新的用户

根据用户id修改用户(@Update)

UserMapper接口:写修改方法,在方法上使用注解@Update(“SQL语句”)

/*
根据用户Id修改用户
 */
@Update("UPDATE user SET username=#{username}, birthday=#{birthday}, sex=#{sex}, address=#{address} WHERE id=#{id}")
void updateUser(User user);

测试

@Test
public void testupdateUser() throws IOException {
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User u = new User(12, "老宋222", Date.valueOf("2000-02-02"), "男", "东莞");
    mapper.updateUser(u);
    sqlSession.commit();
}
根据用户id删除用户(@Delete)

UserMapper接口:使用注解,编写删除方法@Delete(“SQL”)

/*
根据用户id删除用户
 */
@Delete("DELETE FROM user WHERE id=#{id}")
void deleteUser(Integer id);

测试

@Test
public void testDeleteUser() throws IOException {
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    // 根据用户id删除用户
    mapper.deleteUser(11);
    sqlSession.commit();
}
新增用户(@Insert)

UserMapper接口:使用注解,编写新增用户方法@Insert(“SQL语句”)

/*
新增用户
 */
@Insert("INSERT INTO user VALUES (NULL, #{username}, #{birthday}, #{sex}, #{address});")
void addUser(User user);

测试代码

@Test
public void testInsertUser() throws IOException {
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User u = new User(0, "老刘", Date.valueOf("2012-02-02"), "女", "东莞");
    // 添加记录
    mapper.addUser(u);
    sqlSession.commit();
}

小结

注解开发的步骤

  1. 在接口中定义方法
  2. 在方法头上配置相应注解,写SQL语句

[外链图片转存失败(img-oF6zqAr7-1565188451552)(/)]

获取新增主键值@SelectKey

目标

使用注解方式获取添加数据后的主键

<insert id="addUser2" parameterType="user">
    INSERT INTO user (username, birthday, sex, address) VALUES (#{username}, #{birthday}, #{sex}, #{address});

    <selectKey resultType="int" keyColumn="id" keyProperty="id">
        SELECT last_insert_id();
    </selectKey>
</insert>
@SelectKey说明
属性说明
statement要执行的SQL语句:select last_insert_id()
keyProperty实体类中主键的属性
keyColumn表中主键的列名
resultType主键的数据类型
beforefalse 表示after,true表示before

UserMapper接口

/*
新增用户
 */
@Insert("INSERT INTO user VALUES (NULL, #{username}, #{birthday}, #{sex}, #{address});")
@SelectKey(statement = "SELECT LAST_INSERT_ID();", keyColumn = "id", keyProperty = "id", resultType = int.class, before = false)
void addUser(User user);

测试

// 添加记录
public void testInsertUser() throws IOException {
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User u = new User(0, "老刘", Date.valueOf("2012-02-02"), "女", "东莞");
    mapper.addUser(u);
    System.out.println("新增后u = " + u);
    sqlSession.commit();
}

Mybatis注解小结

在注解方式实现基本CRUD操作中,使用的注解有:

注解描述
@Selectp配置查询的SQL语句
@Results对查询结果映射
@Result对每个字段进行映射
@Update配置修改的SQL语句
@Delete配置删除的SQL语句
@Insert配置插入的SQL语句
@SelectKey得到添加的数据的主键

动态SQL的概念和环境搭建

之前我们编写SQL语句的时候都是将SQL语句固定写好的

SELECT * FROM product WHERE brand='小米' AND type='ai' AND size=55;

UPDATE user SET username=#{username}, birthday=#{birthday}, sex=#{sex}, address=#{address} WHERE id=#{id};

目标

学习动态SQL的概念

搭建动态SQL的环境

什么是动态SQL

动态SQL指的是:在程序运行时,根据传入的参数情况,拼接最终执行的sql语句。

[外链图片转存失败(img-ACI7JN3I-1565188451552)(/)]

搭建动态SQL的环境

模块名:mybatis_day02_04_dynamic_sql

配置mybatis核心配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration  
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"  
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <properties resource="jdbc.properties"/>

    <typeAliases>
        <package name="com.itheima.entity"/>
    </typeAliases>

    <environments default="mysql">
        <environment id="mysql">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="dirver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    
    <mappers>
        <package name="com.itheima.dao"/>
    </mappers>
</configuration>
测试
public class TestApp {
    // 省略其他sqlSession的创建
    
    @Test
    public void testFindUserBySex() {
        List<User> list = userMapper.findUserByNameAndSex(new QueryVo("%王%", "女"));
        for (User user : list) {
            System.out.println("user = " + user);
        }
    }
}

小结

  1. 搭建mybatis环境

动态SQL:if标签

目标

用户名和性别查询用户

学习动态SQL语句:if标签的使用

if标签的格式
<if test="条件">
  SQL语句
</if>
if标签的作用

如果满足条件,就会拼接这个SQL。

需求实现

定义QueryVo实体类

public class QueryVo {
    private String username;
    private String sex;
    
    // 省略构造方法/getter/setter
}

声明UserMapper接口方法

package com.itheima.dao;

import com.itheima.entity.User;
import java.util.List;

public interface UserMapper {
    /*
     根据用户名称和性别查询用户
     */
    List<User> findUserByNameAndSex(QueryVo vo);
}

配置mappr映射文件

<?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.itheima.dao.UserMapper">
    <select id="findUserByNameAndSex" parameterType="queryvo" resultType="User">
        SELECT * FROM user WHERE username LIKE #{username} AND sex=#{sex};
    </select>
</mapper>

UserMapper.xml

  1. if:判断用户名称不为空,且不为空字符串,则用户名称作为查询条件
  2. if:判断用户性别不为空,且不为空字符串,则用户性别作为查询条件
<?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.itheima.dao.UserMapper">
    <!--直接根据用户名和性别查询-->
<!--    <select id="findUserByNameAndSex" parameterType="queryvo" resultType="User">
        SELECT * FROM user WHERE username LIKE #{username} AND sex=#{sex};
    </select>-->
    
    <!--
        判断用户名称不为空,且不为空字符串,则用户名称作为查询条件
        判断用户性别不为空,且不为空字符串,则用户性别作为查询条件
    -->
    <select id="findUserByNameAndSex" parameterType="User" resultType="User">
        select * from user where
        <if test="username!=null and username!=''">
          username like '%${username}%'
        </if>
        <!-- &&表示与操作,要转义 -->
        <if test="sex!=null &amp;&amp; sex!=''">
          and sex = #{sex}
        </if>
    </select>
</mapper>

测试

  1. 通过用户名和性别查询多个用户
  2. 只设置性别
  3. 名字和性别一个都不设置
@Test
public void testFindUserBySex() {
    List<User> list = userMapper.findUserByNameAndSex(new QueryVo("", ""));
    for (User user : list) {
        System.out.println("user = " + user);
    }
}

疑问:if标签如果第1个条件没有,会出现什么情况?如何解决这个问题?

因为SQL语句拼接语句不正确,出现问题。

[外链图片转存失败(img-QC79xwXm-1565188451552)(/)]

小结

动态SQL中if标签

if标签的含义做判断如果条件为true就拼接SQL

if标签的格式:

<if test"条件">
	SQL
</if>

动态SQL:where标签的作用

目标

学习where标签的使用

where标签作用
  1. 相当于where关键字,自动补全where这个关键字
  2. 去掉多余的and和or关键字
需求实现
UserMapper.xml

if标签写在where标签内部

  1. if:判断用户名称不为空,且不为空字符串,则用户名称作为查询条件
  2. if:判断用户性别不为空,且不为空字符串,则用户性别作为查询条件
<select id="findUserByNameAndSex" parameterType="queryvo" resultType="User">
    SELECT * FROM user
    <where>
        <if test="username != null and username != ''">
            AND username LIKE #{username}
        </if>

        <!--&&表示与操作,要转义-->
        <if test="sex != null &amp;&amp; sex != ''">
            AND sex=#{sex};
        </if>
    </where>
</select>

小结

  1. if标签的作用:

    做判断,如果满足条件就拼接SQL

  2. where标签的作用

    1. 替代WHERE关键字
    2. 如果有条件会自动添加WHERE关键字
    3. 如果没有条件就不添加WHERE关键字
    4. 去掉多余的AND OR

动态SQL:set标签

目标

set标签的使用

编写修改SQL语句存在的问题

之前我们编写修改的SQL语句时是根据用户ID更新用户所有字段的数据

<!--根据用户ID更新用户所有字段的数据, 这样存在问题,没有值的字段也会被更新为null,最好是有数据的字段更新,没有数据的字段不更新-->
<update id="updateUser" parameterType="user">
	UPDATE user SET username=#{username}, birthday=#{birthday}, sex=#{sex}, address=#{address}
	WHERE id=#{id};
</update>

更新数据的时候,有些为空则不用更新,怎么来处理呢?

set标签的作用
  1. 用在update语句中,相当于set关键字
  2. 去掉SQL代码片段中后面多余的逗号
需求

根据id修改用户部分数据

实现

声明mapper接口方法

/**
 更新用户
 */
int updateUser(User user);

配置mapper映射文件:根据id修改用户部分数据

<!--这样存在问题,没有值的字段也会被更新为null,最好是有数据的字段更新,没有数据的字段不更新-->
<update id="updateUser" parameterType="user">
    UPDATE user SET username=#{username}, birthday=#{birthday}, sex=#{sex}, address=#{address} WHERE id=#{id};
</update>

测试

@Test
public void testUpdateUser() throws IOException {
    User u = new User();
    u.setId(26);
    u.setUsername("大王");
    userMapper.updateUser(u);
}

这样存在问题,没有值的字段也会被更新为null,最好是有数据的字段更新,没有数据的字段不更新。

[外链图片转存失败(img-Lls5IvFS-1565188451556)(/)]

[外链图片转存失败(img-GMhMhNq1-1565188451556)(/)]

使用set标签进行判断,如果有值就更新,没有值就不更新。

<update id="updateUser" parameterType="user">
    UPDATE user
        <set>
            <if test="username != null and username != ''">
                username=#{username},
            </if>

            <if test="birthday != null and birthday != ''">
                birthday=#{birthday},
            </if>

            <if test="sex != null and sex != ''">
                sex=#{sex},
            </if>

            <if test="address != null and address != ''">
                address=#{address}
            </if>
        </set>
        WHERE id=#{id};
</update>

set标签,可以按照条件拼接set后面的内容
[外链图片转存失败(img-Bgda6AEy-1565188451556)(/)]

小结

set标签的作用是?

用于更新,相当于set关键字,去掉多余的逗号

foreach标签:遍历集合1

MyBatis得到数组中的数据动态拼接SQL

int row = userMapper.deleteUsers(new int[]{1, 3, 6});

delete from user where id in (136);
使用数组来封装要删除的所有的id

目标

foreach标签:遍历集合得到基本类型的数据

需求

遍历集合拼接SQL语句,实现批量删除用户

foreach标签介绍
foreach标签的属性作用
collection要遍历的集合,2个取值:list或array
item设置变量名,代表每个遍历的元素
separator每次遍历完后添加一个分隔符
#{变量名.属性}来引用每个属性中值
实现

声明mapper接口方法

/**
 批量删除用户
 */
int deleteUsers(int[] ids);

配置mapper映射文件

<delete id="deleteUsers" parameterType="list">
    <!--DELETE FROM user WHERE id in (1, 2, 3);-->
    DELETE FROM user WHERE
    <!--
        collection: 取值为array表示遍历的是数组
        open: 遍历前添加的符号
        close: 遍历最后添加的符号
        separator:分隔符
        item: 表示每个元素的变量名
    -->
    <foreach collection="array" open="id in (" close=");" separator="," item="temp">
        #{temp}
    </foreach>
</delete>

测试

@Test
public void testDeleteUser() throws IOException {
    int row = userMapper.deleteUsers(new int[]{24, 25, 26});
    System.out.println("row = " + row);
}

效果
[外链图片转存失败(img-YAttxLnN-1565188451556)(/)]

小结

foreach:遍历数组

  • collection:取值为array
  • open:开始的符号
  • close:结束的符号
  • item:每个元素变量名
  • separator:分隔符

foreach标签:遍历集合2

目标

foreach标签:遍历集合得到自定义类型的数据

需求

使用list集合保存多个User对象,添加到数据库中

[外链图片转存失败(img-dZl9HylR-1565188451556)(/)]

提问:一条insert语句插入多条记录的MySQL语句如何编写?

-- 同时插入多条记录
insert into user (username,birthday,sex,address) values 
(#{username},#{birthday},#{sex},#{address}),
(#{username},#{birthday},#{sex},#{address}),
(#{username},#{birthday},#{sex},#{address});

/*
(#{username},#{birthday},#{sex},#{address}) 要循环的内容
*/
实现

mapper接口批量添加用户的方法

/**
  批量添加用户
  */
int addUsers(List<User> users);

配置mapper映射文件

批量新增用户,参数类型是:list

<!--批量添加多条记录-->
<insert id="addUsers" parameterType="list">
    insert into user (username,birthday,sex,address) values
    <!--
    collection 要遍历的集合使用list
    item 设置变量名,代表每个遍历的元素
    separator 每次遍历完后添加一个分隔符
    #{变量名.属性} 来引用每个属性中值
    -->
    <foreach collection="list" item="user" separator=",">
        (#{user.username},#{user.birthday},#{user.sex},#{user.address})
    </foreach>
</insert>

测试

@Test
public void testAddUsers() throws IOException {
    List<User> users = new ArrayList<>();
    users.add(new User(null,"牛魔王", Date.valueOf("1980-01-30"),"男","火焰山"));
    users.add(new User(null,"红孩儿", Date.valueOf("2009-05-08"),"男","火云洞"));
    users.add(new User(null,"玉面狐狸", Date.valueOf("2005-11-01"),"女","狐狸洞"));

    int row = userMapper.addUsers(users);
    System.out.println("添加数据影响的行数 = " + row);
}

结果

[外链图片转存失败(img-0pJvCw5c-1565188451556)(/)]

小结

foreach:循环添加1个代码片段

  • collection:2个取值list或array
  • item:每次循环变量名
  • separator:每次循环添加的分隔符
  • 占位符: #{变量名.属性名}

sql和include标签

我们发现在接口映射文件中会出现很多相同的SQL语句,每个地方都写一遍有些麻烦。我们可以把相同的SQL语句抽取出来,在需要的地方引入即可。

目标

学习sql和include标签的使用

sql和include标签的作用
  1. sql标签:定义一段SQL语句,起个名字可以重用。
  2. include标签:引入上面定义的SQL代码段。
需求实现

UserMapper.xml

<!--抽取重复的SQL并取个名字-->
<sql id="commont">
    INSERT INTO user (username,birthday,sex,address) VALUES
</sql>
<insert id="addUsers" parameterType="list">
    <!--INSERT INTO user (username,birthday,sex,address) VALUES-->
    <!--引入上面的的SQL-->
    <include refid="commont"/>

    <foreach collection="list" close=";" separator="," item="user">
        (#{user.username},#{user.birthday},#{user.sex},#{user.address})
    </foreach>
</insert>

小结

  1. sql标签的作用:定义代码片段

    id属性:唯一标识

  2. include标签的作用:引用代码片段

    refid属性:引用上面标识

学习总结

  1. 掌握sqlMapConfig.xml中常用标签

    properties:引入外部的properties文件

    typeAliases: 给类取别名,常用包扫描,别名就是类名

    mappers: 配置接口映射文件的位置,常用包扫描。注意,接口和接口映射文件在同一个包,名字要相同

  2. 掌握mybatis框架在DAO层的开发

    增删改查

    3步走:

    1.在接口中定义方法

    2.在接口映射文件中配置SQL语句

    3.测试

  3. 能够完成单表的CRUD操作

    <insert> 表示插入数据
    <select> 表示查询
    <update> 表示修改
    <delete> 表示删除
    
    参数类型
    返回值类型
    
  4. 掌握mybatis框架的输入输出映射

    输入类型映射
    简单类型: 基本类型8种/包装类 + String
    POJO: 简单的Java对象, JavaBean
    POJO包装类:
    class QueryVo {
    	private User user;
    	private String start;
    	private String end;
    }
    
    输出映射类型
    简单类型: 基本类型8种/包装类 + String
    POJO: 简单的Java对象, JavaBean
    
  5. 掌握mybatis注解开发

    2步骤

    1.在接口种定义方法

    2.在接口的方法上配置SQL语句

    @Insert 表示插入数据
    @Select 表示查询
    @Update 表示修改
    @Delete 表示删除 
    
  6. 掌握 MyBatis 动态 sql 常用标签

    <if test=”条件“>
    	SQL
    </if>
    满足条件就会拼接这个SQL
    
    <where>
    	<if test=”条件“>
    	</if>
    </where>
    
    如果有条件就添加WHERE关键字
    如果没有条件就不添加WHERE关键字
    自动去掉多余的 and or
    

,“火焰山”));
users.add(new User(null,“红孩儿”, Date.valueOf(“2009-05-08”),“男”,“火云洞”));
users.add(new User(null,“玉面狐狸”, Date.valueOf(“2005-11-01”),“女”,“狐狸洞”));

int row = userMapper.addUsers(users);
System.out.println("添加数据影响的行数 = " + row);

}



### 小结

foreach:循环添加1个代码片段

- collection:2个取值list或array
- item:每次循环变量名
- separator:每次循环添加的分隔符
- 占位符:  #{变量名.属性名}



## sql和include标签

我们发现在接口映射文件中会出现很多相同的SQL语句,每个地方都写一遍有些麻烦。我们可以把相同的SQL语句抽取出来,在需要的地方引入即可。

### 目标

学习sql和include标签的使用

#### sql和include标签的作用

1. sql标签:定义一段SQL语句,起个名字可以重用。
2. include标签:引入上面定义的SQL代码段。

#### 需求实现

UserMapper.xml

```xml
<!--抽取重复的SQL并取个名字-->
<sql id="commont">
    INSERT INTO user (username,birthday,sex,address) VALUES
</sql>
<insert id="addUsers" parameterType="list">
    <!--INSERT INTO user (username,birthday,sex,address) VALUES-->
    <!--引入上面的的SQL-->
    <include refid="commont"/>

    <foreach collection="list" close=";" separator="," item="user">
        (#{user.username},#{user.birthday},#{user.sex},#{user.address})
    </foreach>
</insert>

小结

  1. sql标签的作用:定义代码片段

    id属性:唯一标识

  2. include标签的作用:引用代码片段

    refid属性:引用上面标识

org.apache.ibatis.binding.BindingException是MyBatis框架中的一个异常,它表示绑定语句无效或未找到。在你提供的引用中,出现了两个不同的错误信息,分别是com.mybatis.mapper.OrdersMapper.finarray和com.cloud.lowcode.mapper.UserMapper.queryByParam。 这些错误信息表明在MyBatis的映射文件中找不到对应的绑定语句。绑定语句是指在映射文件中定义的SQL语句,用于执行数据库操作。 要解决这个问题,你可以按照以下步骤进行操作: 1. 确保映射文件中存在对应的绑定语句。检查com.project_mybatis02.mapper.Mkk映射文件中是否定义了名为list的绑定语句。 2. 检查绑定语句的命名是否正确。确保绑定语句的名称与映射文件中定义的名称完全一致,括大小写。 3. 检查映射文件的路径是否正确。确认映射文件的路径与MyBatis配置文件中的路径一致。 4. 检查映射文件是否正确加载。确保映射文件已经正确加载到MyBatis的配置中。 5. 检查映射文件中的命名空间是否正确。确认映射文件中的命名空间与Mapper接口的路径一致。 6. 检查Mapper接口的方法名是否与绑定语句的id一致。确保Mapper接口中的方法名与映射文件中绑定语句的id一致。 7. 检查Mapper接口的路径是否正确。确认Mapper接口的路径与映射文件中的命名空间一致。 8. 检查MyBatis的配置文件是否正确加载了映射文件。确认MyBatis的配置文件中已经正确加载了映射文件。 9. 检查数据库连接是否正常。确保数据库连接配置正确,并且数据库中存在对应的表和字段。 10. 如果以上步骤都没有解决问题,可以尝试重新编译和部署项目,确保所有的文件都已经正确部署。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值