MyBatis_01


typora-copy-images-to: img

MyBatis_01

学习目标

  • 能够了解什么是框架
  • 掌握Mybatis框架开发快速入门
  • 掌握Mybatis框架的基本CRUD操作
  • 掌握SqlMapConfig.xml配置文件
  • 掌握Mybatis的parameterType的配置
  • 掌握Mybatis的resultType的配置
  • 了解Mybatis连接池与事务操作
  • 掌握Mybatis动态SQL

第一章-框架概述

知识点-框架概述

1.目标

  • 能够了解什么是框架

2.路径

  1. 什么是框架
  2. 框架要解决的问题

3.讲解

3.1什么是框架

​ 框架(Framework)是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法;另一种定义认为,框架是可被应用开发者定制的应用骨架。前者是从应用方面而后者是从目的方面给出的定义。

​ 简而言之,框架是软件(系统)的半成品,框架封装了很多的细节,使开发者可以使用简单的方式实现功能,大大提高开发效率。

​ 开发好比表演节目, 开发者好比演员, 框架好比舞台.

3.2框架要解决的问题

​ 框架要解决的最重要的一个问题是技术整合的问题,在 J2EE 的 框架中,有着各种各样的技术,不同的软件企业需要从J2EE 中选择不同的技术,这就使得软件企业最终的应用依赖于这些技术,技术自身的复杂性和技术的风险性将会直接对应用造成冲击。而应用是软件企业的核心,是竞争力的关键所在,因此应该将应用自身的设计和具体的实现技术解耦。这样,软件企业的研发将集中在应用的设计上,而不是具体的技术实现,技术实现是应用的底层支撑,它不应该直接对应用产生影响。

​  框架一般处在低层应用平台(如 J2EE)和高层业务逻辑之间的中间层。

4.小结

  1. 框架: 框架可以封装重复代码,提供更简洁的API;框架可以实现代码间的解耦
  2. SSM框架

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eoOtJY0L-1681046137601)(img/image-20191226084539029.png)]

ssh: strus2、spring、hibernate

知识点-MyBatis框架概述

1.目标

  • 能够了解什么是MyBatis

2.路径

  1. jdbc 程序回顾
  2. MyBatis框架概述

3.讲解

3.1jdbc 程序回顾
3.1.1程序回顾
  • 注册驱动
  • 获得连接
  • 创建预编译sql语句对象
  • 设置参数, 执行
  • 处理结果
  • 释放资源
public static void main(String[] args) {
    Connection connection = null;
    PreparedStatement preparedStatement = null;
    ResultSet resultSet = null;
    try {
        //1.加载数据库驱动
        Class.forName("com.mysql.jdbc.Driver");
        //2.通过驱动管理类获取数据库链接
        connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "123"); 
        //3.定义 sql 语句 ?表示占位符
        String sql = "select * from user where username = ?";
        //4.获取预处理 statement
        preparedStatement = connection.prepareStatement(sql);
        //5.设置参数,第一个参数为 sql 语句中参数的序号(从 1 开始),第二个参数为设置的参数值
        preparedStatement.setString(1, "王五");
        //6.向数据库发出 sql 执行查询,查询出结果集
        resultSet = preparedStatement.executeQuery();
        //7.遍历查询结果集
        while (resultSet.next()) {
            System.out.println(resultSet.getString("id") + "
                               "+resultSet.getString("username"));
                               }
                               } catch (Exception e) {
                                   e.printStackTrace();
                               } finally {
                                   //8.释放资源
                                   if (resultSet != null) {
                                       try {
                                           resultSet.close();
                                       } catch (SQLException e) {
                                           e.printStackTrace();
                                       }
                                   }
                                   if (preparedStatement != null) {
                                       try {
                                           preparedStatement.close();
                                       } catch (SQLException e) {
                                           e.printStackTrace();
                                       }
                                   }
                                   if (connection != null) {
                                       try {
                                           connection.close();
                                       } catch (SQLException e) {
                                           e.printStackTrace();
                                       }
                                   }
                               }
                               }
3.1.2 jdbc 问题分析
  1. 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
  2. Sql 语句在代码中硬编码,造成代码不易维护,实际应用 sql 变化的可能较大, sql 变动需要改变java 代码。
  3. 使用 preparedStatement 向占有位符号传参数存在硬编码,因为 sql 语句的 where 条件不一定,可能多也可能少,修改 sql 还要修改代码,系统不易维护。
  4. 对结果集解析存在硬编码(查询列名), sql 变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成 pojo 对象解析比较方便
3.2 MyBatis框架概述

​ mybatis 是一个优秀的基于 java 的持久层框架,它内部封装了 jdbc,使开发者只需要关注 sql 语句本身,而不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。

​ mybatis 通过xml 或注解的方式将要执行的各种statement 配置起来,并通过java 对象和statement 中sql的动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql并将结果映射为 java 对象并返回。

​ 采用 ORM 思想解决了实体和数据库映射的问题,对jdbc 进行了封装,屏蔽了jdbc api 底层访问细节,使我们不用与 jdbc api打交道,就可以完成对数据库的持久化操作。

​ 官网: http://www.mybatis.org/mybatis-3/

4.小结

  1. MyBatis: 持久层的一个框架, 封装了JDBC. 操作数据库
  2. 为什么要学习MyBatis?
    • JDBC和DBUtils都有一些很明显的缺点, JDBC和DBUtils不适合做项目
    • MyBatis是工作里面的主流的持久层框架, 使用几率特别大

第二章-Mybatis入门

案例-Mybatis快速入门

1.需求

  • 使用MyBatis查询所有的用户, 封装到List集合

2.分析

  1. 创建Maven工程(jar), 添加坐标
  2. 创建pojo
  3. 创建UserDao接口
  4. 创建UserDao映射文件
  5. 创建MyBatis核心配置文件SqlMapConfig.xml
  6. 编写java代码测试

3.实现

3.1准备工作
  • 数据库
CREATE DATABASE mybatis_day;
USE mybatis;
CREATE TABLE t_user(
		uid int PRIMARY KEY auto_increment,
		username varchar(40),
	 	sex varchar(10),
		birthday date,
		address varchar(40)
);

INSERT INTO `t_user` VALUES (null, 'zs', '男', '2018-08-08', '北京');
INSERT INTO `t_user` VALUES (null, 'ls', '女', '2018-08-30', '武汉');
INSERT INTO `t_user` VALUES (null, 'ww', '男', '2018-08-08', '北京');
3.2.MyBatis快速入门

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fXqjaxa6-1681046137603)(img/tu_10-1574303439390.png)]

3.2.1创建Maven工程(jar)导入坐标
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
    <!--引入lombok的依赖-->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.10</version>
      <scope>provided</scope>
    </dependency>
    <!--mysql驱动-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.47</version>
    </dependency>
    <!--mybatis的依赖-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.3</version>
    </dependency>
  </dependencies>
3.2.2创建User实体类
  • User .java
public class User implements Serializable{
    private int uid; //用户id
    private String username;// 用户姓名
    private String sex;// 性别
    private Date birthday;// 生日
    private String address;// 地址
	
}
3.2.3 创建 UserDao 接口
  • UserDao 接口就是我们的持久层接口(也可以写成 UserMapper) .我们就写成UserDao ,具体代码如下:
public interface UserDao {
    public List<User> findAll();
}
3.2.4 创建 UserDao.xml 映射文件

注意:

  1. 映射配置文件存储的路径在resources里面,要和对应的Dao接口的路径保持一致
  2. 映射配置文件的文件名必须和Dao接口名保持一致
  3. 一定要引入约束文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aoM7UNX0-1681046137603)(img/1544705827942-1574303439289.png)]

<?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,一个映射配置文件,就对应一个dao接口
    根标签的namespace属性的值就对应dao接口的全限定名
-->
<mapper namespace="com.itheima.dao.UserDao">
    <!--
        根标签的每一个子标签就对应dao接口的每一个方法:
            select标签就对应查询方法

        标签的id的值对应方法的名字
        标签的resultType的值就对应封装结果的类型,如果封装结果的类型是List就对应其泛型的类型
        标签体的内容就是要执行的SQL语句
    -->
    <select id="findAll" resultType="com.itheima.pojo.User">
        select * from t_user
    </select>
</mapper>
3.2.5 创建 SqlMapConfig.xml 配置文件(核心配置文件)

注意事项

  1. 存放路径必须是resources的根路径
  2. 配置文件的名字,随便写
  3. 一定要引入约束文件
<?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
-->
<configuration>
    <!--
        配置数据库的环境信息:
        environments: 表示里面可以配置多个环境,default表示使用哪个环境
            environment: 每一个environment表示一种环境
        为什么要配置多个环境: 因为我们有多个环境(开发环境、生产环境(真正项目之后运行的环境)、测试环境)
    -->
    <environments default="dev">
        <!--开发环境-->
        <environment id="dev">
            <!--
                事务管理者,type为JDBC表示使用JDBC的事务管理者(了解)
            -->
            <transactionManager type="JDBC"></transactionManager>
            <!--
                dataSource表示数据源,1. POOLED表示使用自带连接池  2. UNPOOLED表示不使用连接池  3. JNDI表示使用JNDI的连接池
            -->
            <dataSource type="POOLED">
                <!--连接池的配置信息-->
                <property name="username" value="root"/>
                <property name="password" value="123"/>
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///mybatis_day01?characterEncoding=utf8"/>
            </dataSource>
        </environment>
        <!--生产环境-->
        <environment id="pro">
            <transactionManager type=""></transactionManager>
            <dataSource type=""></dataSource>
        </environment>
        <!--测试环境-->
        <environment id="test">
            <transactionManager type=""></transactionManager>
            <dataSource type=""></dataSource>
        </environment>
    </environments>

    <!--
        指定加载哪些映射配置文件: mappers
            mapper标签: 每一个mapper标签负责加载一个映射配置文件;resource指定要加载的映射配置文件的路径
    -->
    <mappers>
        <mapper resource="com/itheima/dao/UserDao.xml"></mapper>
    </mappers>
</configuration>
3.2.6测试
package com.itheima;

import com.itheima.dao.UserDao;
import com.itheima.pojo.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 org.junit.Test;

import java.io.InputStream;
import java.util.List;

/**
 * 包名:com.itheima
 * @author Leevi
 * 日期2020-10-29  09:53
 */
public class TestMybatis {
    @Test
    public void testFindAll() throws Exception {
        //1. 让mybatis框架去加载主配置文件
        //1.1 将主配置文件SqlMapConfig.xml转换成字节输入流
        InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
        //1.2 创建一个SqlSessionFactoryBuilder
        SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
        //1.3 使用factoryBuilder对象加载字节输入流,创建SqlSessionFactory对象
        SqlSessionFactory sessionFactory = factoryBuilder.build(is); //使用了构建者模式
        //1.4 使用sessionFactory对象创建出sqlSession对象
        SqlSession sqlSession = sessionFactory.openSession(); //使用了工厂模式

        //2. 使用sqlSession对象创建出UserDao接口的代理对象
        UserDao userDao = sqlSession.getMapper(UserDao.class); //使用了动态代理

        //3. 调用userDao代理对象的findAll()方法进行查询
        List<User> userList = userDao.findAll();
        for (User user : userList) {
            System.out.println(user);
        }

        //4. 关闭资源
        sqlSession.close();
        is.close();
    }
}

4.小结

4.1步骤

​ 1. 创建maven工程(javase)

2. 引入依赖:mysql、mybatis、Junit、lombok
3. 创建POJO类、创建Dao接口
4. 创建Dao接口对应的映射配置文件
      	1. 路径要在resources里面和Dao接口的路径一致,而且在resources目录中创建目录的时候要使用"/"而不是"."
      	2. 映射配置文件的文件名要和对应的Dao接口的名字一致
5. 创建mybatis的核心配置文件
6. 编写mybatis的测试代码进行测试 

知识点-Mapper动态代理方式规范

1.目标

  • 掌握Mapper动态代理方式规范

2.路径

  1. 入门案例回顾
  2. 规范

3.讲解

3.1入门案例回顾
3.1.2Mapper.xml(映射文件)
  1. 映射配置文件存储的路径在resources里面,要和对应的Dao接口的路径保持一致

  2. 映射配置文件的文件名必须和Dao接口名保持一致

  3. 一定要引入约束文件

  4. namespace属性的值和对应Dao接口的全限定名一致

  5. 每一个子标签,就对应Dao接口中的一个方法
    查询方法就对应select标签
    添加方法就对应insert标签
    删除方法就对应delete标签
    修改方法就对应update标签
    
    标签的id就对应方法的名字
    
    标签的parameterType就对应方法的参数类型
    
    标签的resultType(只有select标签才有)就对应方法的返回值类型,如果返回值类型是List,那么
    resultType就是List的泛型类型
    
    标签体中的内容就是要执行的sql语句
    
<?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.UserDao">
    <select id="findAll" resultType="User">
        SELECT *FROM t_user
    </select>
</mapper>
3.1.2Mapper.java(dao接口)
public interface UserDao {

    /**
     * 查询所有的用户
     * @return
     */
    List<User> findAll();

}
3.2规范

Mapper接口开发需要遵循以下规范:

  1. 存储路径建议和对应的Dao接口保持一致
  2. 文件名建议和对应Dao接口的名字保持一致
  3. 配置文件的根标签的namespace属性必须和对应的Dao接口的全限定名保持一致
  4. 接口中的每一个方法,就对应映射配置文件中的一个标签:
    1. 查询方法,对应select标签
    2. 添加方法,对应insert标签
    3. 删除方法,对应delete标签
    4. 修改方法,对应update标签
  5. 映射配置文件中的标签的id属性,就必须和对应的方法的方法名保持一致
  6. 映射配置文件中的标签的parameterType属性,必须和对应的方法的参数类型(全限定名)保持一致
  7. 映射配置文件中的标签的resultType属性,必须和对应的方法的返回值类型(全限定名)保持一致,但是如果返回值是List则和其泛型保持一致

4.小结

  1. 我们使用MyBatis 遵循这些规范

知识点-核心配置文件详解

1.目标

  • 掌握SqlMapConfig.xml配置文件

2.路径

  1. 核心配置文件里面的标签的顺序
  2. properties
  3. typeAliases
  4. Mapper

3.讲解

3.1.核心配置文件的顺序

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fiHCLtK5-1681046137605)(img/image-20191226095424936.png)]

properties(引入外部properties文件)

settings(全局配置参数)

typeAliases(类型别名)

typeHandlers(类型处理器)

objectFactory(对象工厂)

plugins(插件)

environments(环境集合属性对象)

​ environment(环境子属性对象)

​ transactionManager(事务管理)

​ dataSource(数据源)

mappers(映射器)

3.2.properties
  • jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis_day01?characterEncoding=utf-8
jdbc.user=root
jdbc.password=123
  • 引入到核心配置文件
<configuration>
   <properties resource="jdbc.properties">
    </properties>
    <!--数据源配置-->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="UNPOOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.user}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    ....
</configuration>
3.3.typeAliases(类型别名)
3.3.1定义单个别名
  • 核心配置文件
<typeAliases>
      <typeAlias type="com.itheima.bean.User" alias="user"></typeAlias>
 </typeAliases>
  • 修改UserDao.xml
<select id="findAll" resultType="user">
    SELECT  * FROM  user
</select>
3.3.2批量定义别名

使用package定义的别名:就是pojo的类名,大小写都可以

  • 核心配置文件
<typeAliases>
    <package name="com.itheima.bean"/>
</typeAliases>
  • 修改UserDao.xml
<select id="findAll" resultType="user">
         SELECT  * FROM  user
</select>
3.4.Mapper
3.4.1方式一:引入映射文件路径
<mappers>
     <mapper resource="com/itheima/dao/UserDao.xml"/>
 </mappers>
3.4.2方式二:扫描接口
  • 配置单个接口
<mappers>
 	<mapper class="com.itheima.dao.UserDao"></mapper>
</mappers>
  • 批量配置
<mappers>
   <package name="com.itheima.dao"></package>
</mappers>

4.小结

  1. 核心配置文件的顺序

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lNrrHEcm-1681046137605)(img/image-20191226101317581.png)]

  1. properties 引入properties文件的
    • 创建properties文件
    • 使用 <properties resource="文件的路径"/>
    • 使用 ${key}
  2. typeAliases(类型别名) 在Dao映射文件里面 直接写类(pojo)的名字, 不需要写类全限定名了
<typeAliases>
    <package name="com.itheima.bean"/>
</typeAliases>
  1. Mapper 引入Dao映射文件的
<mappers>
   <package name="com.itheima.dao"></package>
</mappers>

第三章-MyBatis进阶

知识点-日志的使用(只要会用就行)

1.目标

​ 我们在使用MyBatis的时候, 其实MyBatis框架会打印一些必要的日志信息, 在开发阶段这些日志信息对我们分析问题,理解代码的执行是特别有帮助的; 包括项目上线之后,我们也可以收集项目的错误日志到文件里面去; 所有我们采用专门的日志系统来处理.

2.步骤

  1. 导入坐标
  2. 拷贝日志配置文件到项目

3.讲解

  • 导入坐标
<!-- log start -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.12</version>
</dependency>

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.6.6</version>
</dependency>

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.6.6</version>
</dependency>
<!-- log end -->
  • 拷贝log4j.properties到resources目录
log4j.rootLogger=DEBUG,stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
#[%-5p] %t %l %d %rms:%m%n
#%d{yyyy-MM-dd HH:mm:ss,SSS\} %-5p [%t] {%c}-%m%n
log4j.appender.stdout.layout.ConversionPattern=[%-5p] %t %l %d %rms:%m%n
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=D:\\idea_project\\itheima_mm_backend.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS\} %-5p [%t] {%c}-%m%n

级别:error > warn > info>debug>trace

4.小结

  1. 日志系统就是一个工具

    • 拷贝坐标
    • 拷贝log4J.properties到项目
  2. 配置文件一般的配置

    • 开发阶段: log4j.rootLogger= debug,std,file
    • 上线之后: log4j.rootLogger= error ,file

案例-使用Mybatis完成CRUD

1.需求

  • 使用Mybatis完成CRUD

2.分析

  1. 在Dao接口定义方法
  2. 在Dao映射文件配置

3.实现

3.1新增用户
3.1.1实现步骤
  • UserDao中添加新增方法
public interface UserDao {
    /**
     * 添加用户
     * @param user 要添加进数据库的数据
     * @return 受到影响的行数
     */
    int addUser(User user);
}
  • 在 UserDao.xml 文件中加入新增配置
    <insert id="addUser" parameterType="User">
        insert into t_user (username,sex,birthday,address) values (#{username},#{sex},#{birthday},#{address})
    </insert>

	<!--我们可以发现, 这个 sql 语句中使用#{}字符, #{}代表占位符,我们可以理解是原来 jdbc 部分所学的?,它们都是代表占位符, 具体的值是由 User 类的 username 属性来决定的。
	parameterType 属性:代表参数的类型,因为我们要传入的是一个类的对象,所以类型就写类的
全名称。-->
  • 添加测试类中的测试方法
package com.itheima;

import com.itheima.dao.UserDao;
import com.itheima.pojo.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 org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;

/**
 * 包名:com.itheima
 *
 * @author Leevi
 * 日期2020-10-29  11:13
 */
public class TestMybatis {

    private UserDao userDao;
    private SqlSession sqlSession;
    private InputStream is;

    @Before
    public void init() throws Exception {
        //1. 让mybatis框架去加载主配置文件
        //1.1 将主配置文件SqlMapConfig.xml转换成字节输入流
        is = Resources.getResourceAsStream("SqlMapConfig.xml");
        //1.2 创建一个SqlSessionFactoryBuilder
        SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
        //1.3 使用factoryBuilder对象加载字节输入流,创建SqlSessionFactory对象
        SqlSessionFactory sessionFactory = factoryBuilder.build(is); //使用了构建者模式
        //1.4 使用sessionFactory对象创建出sqlSession对象
        //使用了工厂模式
        sqlSession = sessionFactory.openSession();

        //2. 使用sqlSession对象创建出UserDao接口的代理对象
        //使用了动态代理
        userDao = sqlSession.getMapper(UserDao.class);
    }
    @Test
    public void testAddUser(){
        //3. 调用userDao对象的addUser方法添加用户
        User user = new User(null, "贾克斯", "召唤师峡谷", "女", new Date());
        //用户添加之前的id为null
        userDao.addUser(user);

        //目标是添加完用户之后,获取到该用户的id : 在以后的多表中,进行关联添加
        System.out.println(user.getUid());
    }
    @After
    public void destroy() throws IOException {
        //提交事务
        sqlSession.commit();

        //4. 关闭资源
        sqlSession.close();
        is.close();
    }
}
3.1.2 新增用户 id 的返回值

​ 新增用户后, 同时还要返回当前新增用户的 id 值,因为 id 是由数据库的自动增长来实现的,所以就相当于我们要在新增后将自动增长 auto_increment 的值返回。

  • SelectKey获取主键
属性描述
keyPropertyselectKey 语句结果应该被设置的目标属性。
resultType结果的类型。MyBatis 通常可以算出来,但是写上也没有问题。MyBatis 允许任何简单类型用作主键的类型,包括字符串。
order这可以被设置为 BEFORE 或 AFTER。如果设置为 BEFORE,那么它会首先选择主键,设置 keyProperty 然后执行插入语句。如果设置为 AFTER,那么先执行插入语句,然后是 selectKey 元素-这和如 Oracle 数据库相似,可以在插入语句中嵌入序列调用。

UserDao.xml

	<!--
        resultType只有select标签才有

        我们需要在标签体的SQL语句中,获取pojo类型的参数的属性: #{属性名}


        selectKey标签: 查询主键
            keyColumn 表示要查询的列名
            keyProperty 表示要赋值的属性名
            resultType 表示查询出来的结果的类型
            order 表示在前或者在后执行
        select last_insert_id() 查询最后一个自增长的id的值
    -->
<insert id="addUser" parameterType="User">
    <selectKey resultType="int" order="AFTER" keyProperty="uid" keyColumn="uid">
        select last_insert_id()
    </selectKey>
    insert into t_user (username,sex,birthday,address) values (#{username},#{sex},#{birthday},#{address})
</insert>
3.2根据id查询用户
  • UserDao添加根据id查询方法
User findById(Integer id);
  • UserDao.xml文件中新增配置
<select id="findById" parameterType="int" resultType="User">
    select * from t_user where uid=#{id}
</select>
3.3修改用户
  • UserDao中添加修改方法
public interface UserDao {
    /**
     * 更新用户
     * @param user
     */
    void  updateUser(User user);
}
  • 在 UserDao.xml 文件中加入新增配置
<update id="updateUser" parameterType="User">
    update t_user set username=#{username},sex=#{sex},address=#{address} where uid=#{uid}
</update>
  • 添加测试类中的测试方法
@Test
public void testUpdate(){
    User user = userDao.findById(6);
    user.setUsername("aobama");
    user.setAddress("召唤师峡谷");

    userDao.updateUser(user);
}
3.3删除用户
  • UserDao中添加新增方法
public interface UserDao {

    /**
     * 根据id删除
     * @param id
     * @return
     */
    int deleteById(int id);
}
  • 在 UserDao.xml 文件中加入新增配置
<delete id="deleteById" parameterType="int">
    DELETE FROM t_user WHERE uid = #{id}
</delete>
  • 添加测试类中的测试方法
@Test
public void testDeleteById(){
    //根据id删除用户
    userDao.deleteById(1);
}
3.4模糊查询
3.4.1 方式一(工作中不会采用这种做法)
  • UserDao 中添加新增方法
public interface UserDao {
    /**
     * 模糊查询
     * @param name
     * @return
     */
    List<User> searchByUsername(String name);
}
  • 在 UserDao.xml 文件中加入新增配置
<select id="searchByUsername" parameterType="string" resultType="User">
  	SELECT * FROM t_user WHERE username LIKE #{name}
</select>
  • 添加测试类中的测试方法
@Test
public void testSearch(){
    List<User> userList = userDao.searchByUsername("%a%");
    for (User user : userList) {
        System.out.println(user);
    }
}
3.4.2 方式二
  • UserDao 中添加新增方法
public interface UserDao {
    /**
     * 根据用户名进行模糊查询
     * @param username
     * @return
     */
    List<User> searchByUsername(String username);
}
  • 在 UserMapper.xml 文件中加入新增配置
	<!--
        模糊查询
        另外一种在SQL语句中引用方法的参数的方式:${}
            1. 引用pojo中的属性: '${属性名}'
            2. 引用简单类型的参数: '${value}',但是高版本的mybatis中可以'${任意字符串}'
    -->
<select id="searchByUsername" parameterType="string" resultType="User">
    <!--select * from t_user where username like "%"#{username}"%"-->
    <!--select * from t_user where username like concat("%",#{username},"%")-->

    select * from t_user where username like '%${value}%'
</select>

我们在上面将原来的#{}占位符,改成了${value}。注意如果用模糊查询的这种写法,那么${value}的写法就是固定的,不能写成其它名字。

  • 添加测试类中的测试方法
@Test
public void testSearch(){
    List<User> userList = userDao.searchByUsername("a");
    for (User user : userList) {
        System.out.println(user);
    }
}
3.4.3 #{}与${}的区别【面试】
  1. #{}一定不能写在引号里面,${}一定要写在引号里面
  2. 如果是pojo、map类型的参数,无论是#{}还是${}里面都是些属性名
  3. 如果是简单类型的参数,#{}里面可以写任意字符串,但是${}里面只能写value(以前的版本)
  4. 如果使用#{}引入参数的话,其实是先使用?占位符,然后再设置参数;而使用${}引入参数的话,是直接拼接SQL语句
3.5.SqlSessionFactory工具类的抽取

步骤:

  1. 创建SqlSessionFactoryUtils
  2. 定义一个getSqlSession()方法获得sqlSession
  3. 定义释放资源方法
  4. 保证SqlSessionFactory只有一个(静态代码块)

实现

package com.itheima.utils;

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;
import java.io.InputStream;

/**
 * 包名:com.itheima.utils
 * @author Leevi
 * 日期2020-10-29  12:08
 * 1. 类加载的时候就创建出来了一个SqlSessionFactory对象
 * 2. 我们得声明一个方法,用于创建SqlSession对象,因为每次执行SQL语句的sqlSession对象不能是同一个
 */
public class SqlSessionFactoryUtil {
    private static SqlSessionFactory sqlSessionFactory;
    static {
        try {
            //1 将主配置文件SqlMapConfig.xml转换成字节输入流
            InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
            //2 创建一个SqlSessionFactoryBuilder
            SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
            //3 使用factoryBuilder对象加载字节输入流,创建SqlSessionFactory对象
            sqlSessionFactory = factoryBuilder.build(is); //使用了构建者模式

            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 创建SqlSession对象
     * @return
     */
    public static SqlSession openSqlSession(){
        return sqlSessionFactory.openSession();
    }

    /**
     * 提交事务并且关闭sqlSession
     * @param sqlSession
     */
    public static void commitAndClose(SqlSession sqlSession){
        sqlSession.commit();
        sqlSession.close();
    }

    /**
     * 回滚事务并且关闭sqlSession
     * @param sqlSession
     */
    public static void rollbackAndClose(SqlSession sqlSession){
        sqlSession.rollback();
        sqlSession.close();
    }
}

4.小结

4.1增删改查
  • 增加
<insert id="" parameterType="" resultType="" keyProperty="" useGeneratedKeys="true">
	sql语句
</insert>
  • 更新
<update id="" parameterType="" resultType="" >
	sql语句
</update>
  • 删除
<delete id="" parameterType="" resultType="" >
	sql语句
</delete>
  • 查询
<select id="" parameterType="" resultType="" >
	sql语句
</select>

知识点-parameterType深入

1.目标

  • 掌握Mybatis的参数深入(parameterType)

2.路径

  1. 传递简单类型
  2. 传递 pojo 对象、或者是Map类型
  3. 传递 pojo 包装对象类型

3.讲解

3.1 传递简单类型

单个参数,方法就以简单类型传入即可,那么在映射配置文件中的parameterType的值就是这个简单类型的别名;在SQL语句中引入简单类型的参数#{任意字符串}

User findById(int id);
<select id="findById" parameterType="int" resultType="User">
    select * from t_user where uid=#{id}
</select>
3.2 传递 pojo 对象 或者 Map
  1. 将多个参数封装到一个POJO中,那么在映射配置文件中parameterType的值就是这个POJO的全限定名或者别名; 在SQL语句中引入参数#{POJO的属性名}或者’${POJO的属性名}’
  2. 将多个参数封装到一个Map中(要封装的参数没有对应的POJO),那么在映射配置文件中parameterType的值是map; 在SQL语句中引入参数#{map的key}或者’${map的key}’
void addUser(User user);

void updateUser(Map map);
<insert id="addUser" parameterType="User">
    insert into t_user(username,sex,birthday,address) values (#{username},#{sex},#{birthday},#{address})
</insert>

<update id="updateUser" parameterType="map">
    update t_user set username=#{username},sex=#{sex} where uid=#{uid}
</update>
3.3 传递多个参数

​ 使用Param注解指定参数名称

User findByUsernameAndAddress(@Param("uname") String username, @Param("addr") String address);
<select id="findByUsernameAndAddress" resultType="User">
    select * from t_user where username=#{uname} and address=#{addr}
</select>
3.4传递 pojo 包装对象类型

​ 开发中通过 pojo 传递查询条件 ,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(比如将用户购买商品信息也作为查询条件),这时可以使用包装对象传递输入参数。Pojo 类中包含 pojo。

​ 京东查询的例子:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BnQpP7kw-1681046137607)(img/1539830569011.png)]

​ 需求:根据用户id查询用户信息并进行分页,查询条件放到 QueryVo 的 user 属性中。

  • QueryVo
package com.itheima.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 包名:com.itheima.pojo
 * @author Leevi
 * 日期2020-10-29  14:45
 * Query 查询
 * Vo  ViewObject 视图对象
 * QueryVo 就是封装查询视图的数据
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class QueryVo {
    public QueryVo(Long currentPage, Integer pageSize, User queryCondition) {
        this.currentPage = currentPage;
        this.pageSize = pageSize;
        this.queryCondition = queryCondition;
    }

    private Long currentPage;
    private Integer pageSize;
    /**
     * 查询条件
     */
    private User queryCondition;

    private Long offset;

    public Long getOffset() {
        return (currentPage - 1)*pageSize;
    }
}
  • UserDao接口
public interface UserDao {
    List<User> searchByCondition(QueryVo queryVo);
}
  • UserDao.xml文件
<select id="searchByCondition" parameterType="QueryVo" resultType="User">
    select * from t_user where sex=#{queryCondition.sex} and address=#{queryCondition.address}
    limit #{offset},#{pageSize}
</select>
  • 测试代码
@Test
public void test03(){
    SqlSession sqlSession = SqlSessionFactoryUtil.openSqlSession();
    UserDao mapper = sqlSession.getMapper(UserDao.class);

    User user = new User();
    user.setSex("男");
    user.setAddress("北京");

    QueryVo queryVo = new QueryVo(1l,5,user);
    List<User> userList = mapper.searchByCondition(queryVo);

    for (User user1 : userList) {
        System.out.println(user1);
    }

    SqlSessionFactoryUtil.commitAndClose(sqlSession);
}

4.小结

  1. 如果我们执行的SQL语句需要一个参数,那么我们可以使用简单类型的参数

    1. 如果我们执行的SQL语句需要多个参数
      1. 使用多个参数
      2. 使用pojo对象类型
      3. 使用map类型
      4. 我们使用map类型
    2. 如果我们执行的SQL语句需要的数据很复杂,pojo里面的属性还是pojo类型,那么我们就使用pojo的包装类型

知识点 - resultType深入

1.目标

  • 掌握Mybatis的参数深入(resultType)

2.路径

  1. 输出简单类型
  2. 输出pojo对象
  3. 输出pojo列表
  4. resultMap结果类型

3.讲解

3.1输出简单类型

查询的结果是单个数据, 映射配置文件中的resultType属性的值就是这个数据的类型

/**
  * 查询用户的总个数
  * @return
  */
Long findTotal();
<select id="findTotal" resultType="long">
    select count(*) from t_user
</select>
3.2输出pojo对象(一个pojo对象就对应一行数据)或者一个Map

查询的结果是一行数据:

  • 将这一行数据存储到POJO对象中, 映射配置文件的resultType的值就是POJO的全限定名或者别名,此时就要求查询结果的字段名和类型 要和POJO的属性名和类型一致
  • 将这一行数据存储到Map对象,映射配置文件的resultType的值就是map,那么此时查询结果中的字段名就是 map的key,字段值就是map的value
/**
  * 根据id查询一条数据
  * @param id
  * @return
  */
User findById(int id);

/**
  * 根据用户名查询用户
  * @param username
  * @return
  */
Map findByUsername(String username);
<select id="findById" parameterType="int" resultType="User">
    select * from t_user where uid=#{id}
</select>

<select id="findByUsername" parameterType="string" resultType="map">
    select * from t_user where username=#{username}
</select>
3.3输出pojo列表(一个pojo列表就对应多行数据)或者Map的列表

查询的结果是多行数据:

  • 将多条数据存储到List中,映射配置文件的resultType的值就是POJO的别名

  • 将多条数据存储到List中,映射配置文件的resultType的值就是map

3.4 resultMap结果类型

resultType可以指定pojo将查询结果映射为pojo,但需要pojo的属性名和sql查询的列名一致方可映射成功。

如果sql查询字段名和pojo的属性名不一致,可以通过resultMap将字段名和属性名作一个对应关系 ,resultMap实质上还需要将查询结果映射到pojo对象中。

resultMap可以实现将查询结果映射为复杂类型的pojo,比如在查询结果映射对象中包括pojo和list实现一对一查询和一对多查询。(下次课讲)

​ 那我们今天就来看返回的列名与实体类的属性不一致时的情况. 下次课再接着研究复杂的封装(多表查询) , 将查询到的t_user表的信息封装到UserInfo对象中

  • UserInfo.java
package com.itheima.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

/**
 * 包名:com.itheima.pojo
 *
 * @author Leevi
 * 日期2020-10-29  15:19
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserInfo implements Serializable {
    private Integer userId;
    private String username;
    private String userSex;
    private String userBirthday;
    private String userAddress;
}

  • UserDao.java
public interface UserDao {
    /**
     * 查询所有用户信息,封装到UserInfo对象
     * @return
     */
    List<UserInfo> findAllUserInfo();
}
  • UserDao.xml
<!--
        resultType属性会进行自动映射: 根据结果集的字段名和POJO的属性名的对应关系进行映射

        resultMap属性: 结果集映射(手动映射),我们要先使用resultMap标签编写一个手动映射规则,然后使用这个映射规则
    -->
<!--
        id就是这个映射规则的唯一标识
        type就是要进行手动映射的类型:UserInfo

        autoMapping="true" 表示能自动映射的就会进行自动映射,不能自动映射的属性,才进行手动映射
    -->
<resultMap id="userInfoMap" type="UserInfo" autoMapping="true">
    <!--
            id标签表示对主键进行映射
                column属性是要进行映射的主键的字段名(列名)
                property是要进行映射的POJO的属性名
        -->
    <id column="uid" property="userId"></id>
    <!--
            result标签就是对其它的非主键进行映射
        -->
    <result column="sex" property="userSex"></result>
    <result column="birthday" property="userBirthday"></result>
    <result column="address" property="userAddress"></result>
</resultMap>

<select id="findAllUserInfo" resultMap="userInfoMap">
    select * from t_user
</select>

4.小结

  1. 输出简单类型 直接写 java类型名 eg: int
  2. 输出pojo对象 直接写 pojo类型名 eg: User
  3. 输出pojo列表类型 写 列表里面的泛型的类型 eg: List 写User
  4. ResultMap
    • 解决查询出来的结果的列名和javaBean属性不一致的请求
    • 复杂的pojo复杂(明天讲)

第五章-Mybatis 连接池与事务(了解)

知识点-Mybatis 的连接池技术【了解】

1.目标

​ 我们在前面的 WEB 课程中也学习过类似的连接池技术,而在 Mybatis 中也有连接池技术,但是它采用的是自己的连接池技术 。

​ 在 Mybatis 的 SqlMapConfig.xml 配置文件中, 通过 <dataSource type=”pooled”>来实现 Mybatis 中连接池的配置.

2.路径

  1. Mybatis 连接池的分类
  2. Mybatis 中数据源的配置
  3. Mybatis 中 DataSource 配置分析

3.讲解

3.1Mybatis 连接池的分类
  • 可以看出 Mybatis 将它自己的数据源分为三类:

    • UNPOOLED 不使用连接池的数据源
    • POOLED 使用连接池的数据源
    • JNDI 使用 JNDI 实现的数据源,不要的服务器获得的DataSource是不一样的. 注意: 只有是web项目或者Maven的war工程, 才能使用. 我们用的是tomcat, 用的连接池是dbcp.

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CGbKa6wv-1681046137607)(img/tu_2-1572948297061.png)]

  • 在这三种数据源中,我们目前阶段一般采用的是 POOLED 数据源(很多时候我们所说的数据源就是为了更好的管理数据库连接,也就是我们所说的连接池技术),等后续学了Spring之后,会整合一些第三方连接池。

3.2Mybatis 中数据源的配置
  • 我们的数据源配置就是在 SqlMapConfig.xml 文件中, 具体配置如下:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M5fbCh5N-1681046137608)(img/tu_3-1572948297061.png)]

  • MyBatis 在初始化时,解析此文件,根据的 type 属性来创建相应类型的的数据源DataSource,即:

    ​ type=”POOLED”: MyBatis 会创建 PooledDataSource 实例, 使用连接池
    ​ type=”UNPOOLED” : MyBatis 会创建 UnpooledDataSource 实例, 没有使用的,只有一个连接对象的
    ​ type=”JNDI”: MyBatis 会从 JNDI 服务上查找 DataSource 实例,然后返回使用. 只有在web项目里面才有的,用的是服务器里面的. 默认会使用tomcat里面的dbcp

3.3Mybatis 中 DataSource 配置分析
  • 代码,在21行加一个断点, 当代码执行到21行时候,我们根据不同的配置(POOLED和UNPOOLED)来分析DataSource

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7n2OiAyr-1681046137609)(img/1533783469075.png)]

  • 当配置文件配置的是type=”POOLED”, 可以看到数据源连接信息

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VO6mYNL6-1681046137610)(img/1533783591235.png)]

  • 当配置文件配置的是type=”UNPOOLED”, 没有使用连接池

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f2WhPSGS-1681046137610)(img/1533783672422.png)]

4.小结

  1. 配置

    type=“POOLED” 使用连接池(MyBatis内置的)
    type=“UNPOOLED” 不使用连接池

  2. 后面做项目, 工作里面的连接池, 我们都是使用的第三方的(C3P0,Druid,光连接池), 都有让Spring管理.此章节只做了解

知识点-Mybatis 的事务控制 【了解】

1.目标

  • 了解MyBatis事务操作

2.路径

  1. JDBC 中事务的回顾
  2. Mybatis 中事务提交方式
  3. Mybatis 自动提交事务的设置

3.讲解

3.1JDBC 中事务的回顾

​ 在 JDBC 中我们可以通过手动方式将事务的提交改为手动方式,通过 setAutoCommit()方法就可以调整。通过 JDK 文档,我们找到该方法如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g1crDKWu-1681046137611)(img/tu_8-1572948297061.png)]

​ 那么我们的 Mybatis 框架因为是对 JDBC 的封装,所以 Mybatis 框架的事务控制方式,本身也是用 JDBC的 setAutoCommit()方法来设置事务提交方式的。

3.2Mybatis 中事务提交方式
  • Mybatis 中事务的提交方式,本质上就是调用 JDBC 的 setAutoCommit()来实现事务控制。我们运行之前所写的代码:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pidVPHjR-1681046137612)(img/tu_9-1572948297061.png)]

  • userDao 所调用的 saveUser()方法如下:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-opKZlDyZ-1681046137613)(img/tu_10-1572948297061.png)]

  • 观察在它在控制台输出的结果:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-blPrBAap-1681046137614)(img/tu_11-1572948297061.png)]

    ​ 这是我们的 Connection 的整个变化过程, 通过分析我们能够发现之前的 CUD操作过程中,我们都要手动进行事务的提交,原因是 setAutoCommit()方法,在执行时它的值被设置为 false 了,所以我们在CUD 操作中,必须通过 sqlSession.commit()方法来执行提交操作。

3.3 Mybatis 自动提交事务的设置

​ 通过上面的研究和分析,现在我们一起思考,为什么 CUD 过程中必须使用 sqlSession.commit()提交事务?主要原因就是在连接池中取出的连接,都会将调用 connection.setAutoCommit(false)方法,这样我们就必须使用 sqlSession.commit()方法,相当于使用了 JDBC 中的 connection.commit()方法实现事务提交。明白这一点后,我们现在一起尝试不进行手动提交,一样实现 CUD 操作。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nwPj5PiJ-1681046137615)(img/tu_12-1572948297062.png)]

​ 我们发现,此时事务就设置为自动提交了,同样可以实现 CUD 操作时记录的保存。虽然这也是一种方式,但就编程而言,设置为自动提交方式为 false 再根据情况决定是否进行提交,这种方式更常用。因为我们可以根据业务情况来决定提交是否进行提交。

4.小结

  1. MyBatis的事务使用的是JDBC事务策略.
    • 通过设置autoCommit()去控制的
    • 默认情况下, MyBatis使用的时候 就把autoCommit(false)
      • 也就是意味着, 我们要进行增删改的时候, 需要手动的commit
  2. 后面做项目, 工作里面的事务管理, 基本上都是交给Spring管理. 所以此章节只做了解

第六章-Mybatis 映射文件的 SQL 深入【重点】

​ Mybatis 的映射文件中,前面我们的 SQL 都是比较简单的,有些时候业务逻辑复杂时,我们的 SQL是动态变化的,此时在前面的学习中我们的 SQL 就不能满足要求了。

知识点-动态 SQL 之 if标签

1.目标

​ 我们根据实体类的不同取值,使用不同的 SQL 语句来进行查询。

​ 比如在 id 如果不为空时可以根据 id查询,如果 username 不为空时还要加入用户名作为条件。这种情况在我们的多条件组合查询中经常会碰到

2.讲解

  • UserDao.java
public interface UserDao {
   /**
     * 根据address查询用户,如果没有传入地址则查询出所有用户
     * @param address
     * @return
     */
    List<User> findUserListByAddress(@Param("address") String address);

    /**
     * 根据用户的地址和性别查询用户, 如果有address才考虑address的条件,如果有sex才考虑sex的条件
     * @param user
     * @return
     */
    List<User> findUserListByAddressAndSex(User user);
}
  • UserDao.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.UserDao">
    <select id="findUserListByAddress" parameterType="string" resultType="User">
        select * from t_user
        <!--
            加入一个判断,判断传入的address是否为空,使用if标签进行判断,该标签中的test属性就编写判断条件
        -->
        <if test="address != null">
            where address=#{address}
        </if>
    </select>

    <select id="findUserListByAddressAndSex" parameterType="User" resultType="User">
        select * from t_user
        where 1=1
        <if test="address != null">
            and address=#{address}
        </if>

        <if test="sex != null">
            and sex=#{sex}
        </if>
    </select>
</mapper>
  • 测试
@Test
public void test01(){
    SqlSession sqlSession = SqlSessionFactoryUtil.openSqlSession();
    UserDao mapper = sqlSession.getMapper(UserDao.class);

    List<User> userList = mapper.findUserListByAddress(null);

    for (User user : userList) {
        System.out.println(user);
    }

    SqlSessionFactoryUtil.commitAndClose(sqlSession);
}

@Test
public void test02(){
    SqlSession sqlSession = SqlSessionFactoryUtil.openSqlSession();
    UserDao mapper = sqlSession.getMapper(UserDao.class);

    User user = new User();
    user.setAddress("北京");
    user.setSex("男");
    mapper.findUserListByAddressAndSex(user);

    SqlSessionFactoryUtil.commitAndClose(sqlSession);
}

知识点-动态 SQL 之where标签

1.目标

​ 为了简化上面 where 1=1 的条件拼装,我们可以采用标签来简化开发。

2.讲解

修改 UserDao.xml 映射文件如下:

注意: 可以自动处理第一个 and

<select id="findUserListByAddressAndSex" parameterType="User" resultType="User">
    <include refid="select_all"/>

    <!--
            where标签的作用:
                1. 可以在条件之前添加where关键字
                2. 可以去掉第一个条件前的and
        -->
    <where>
        <if test="address != null">
            and address=#{address}
        </if>

        <if test="sex != null">
            and sex=#{sex}
        </if>
    </where>
</select>

3.小结

  1. where标签用在自己写sql语句的时候 where关键字不好处理的情况,代替where ‘1’ = ‘1’
  2. 可以自动处理第一个 and , 建议全部加上and

知识点-动态标签之foreach标签

1.目标

  • 掌握foreach标签的使用

2.讲解

2.1需求
  • 批量删除: 根据id的集合删除所有元素
2.2 LinkManDao代码
/**
  * 批量删除
  * @param ids
  */
void deleteByIds(List<Integer> ids);
2.3 LinkManDao映射配置文件
<delete id="deleteByIds" parameterType="int">
    delete from t_user

    <!--
            将传入的集合中的数据遍历出来,放到()里面
            使用foreach标签遍历
                collection属性:要遍历的集合,如果要遍历的是一个List则写成list
                item属性: 遍历出来的每一个元素
                separator属性: 遍历出来的每一个元素之间的分隔符
                index属性: 遍历出来的每一个元素的索引
                open属性: 在遍历出来的第一个元素之前拼接字符串
                close属性: 在遍历出来的最后一个元素之后拼接字符串
        -->
    <foreach collection="list" item="id" separator="," open="where uid in(" close=")">
        #{id}
    </foreach>

</delete>
2.4 测试代码
@Test
public void test03(){
    SqlSession sqlSession = SqlSessionFactoryUtil.openSqlSession();
    UserDao mapper = sqlSession.getMapper(UserDao.class);
    List<Integer> ids = new ArrayList<>();

    ids.add(1);
    ids.add(2);
    ids.add(3);
    ids.add(4);

    mapper.deleteByIds(ids);

    SqlSessionFactoryUtil.commitAndClose(sqlSession);
}

知识点-动态标签之Sql片段

1.目标

​ Sql 中可将重复的 sql 提取出来,使用时用 include 引用即可,最终达到 sql 重用的目的。我们先到 UserDao.xml 文件中使用标签,定义出公共部分.

2.讲解

  • 使用sql标签抽取
<!--
    使用sql标签将重复的sql语句部分封装起来

    在需要使用这个sql片段的地方,就用include标签引入就行了
 -->
<sql id="select_all">
    select uid,username,sex,address,birthday from t_user
</sql>
  • 使用include标签引入使用
<select id="findUserListByAddress" parameterType="string" resultType="User">
    <include refid="select_all"/>
    <!--
            加入一个判断,判断传入的address是否为空,使用if标签进行判断,该标签中的test属性就编写判断条件
        -->
    <if test="address != null">
        where address=#{address}
    </if>
</select>

<select id="findUserListByAddressAndSex" parameterType="User" resultType="User">
    <include refid="select_all"/>

    <!--
            where标签的作用:
                1. 可以在条件之前添加where关键字
                2. 可以去掉第一个条件前的and
        -->
    <where>
        <if test="address != null">
            and address=#{address}
        </if>

        <if test="sex != null">
            and sex=#{sex}
        </if>
    </where>
</select>

3.小结

  1. sql标签可以把公共的sql语句进行抽取, 再使用include标签引入. 好处:好维护, 提示效率
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值