五:Day03_Mybatis01

一、框架介绍

1. 框架的作用

按照面向对象思想对Java SEJava EE里面的内容进行封装,把一些重复性的代码进行深度封装,在封装同时还添加了一些额外功能,这样可以写更少的代码,实现更强的功能,程序员可以将更多的精力放在业务上。这些封装随着不停的更新更迭就形成了框架(Framework),很多的框架也是开源的。

2. Java中的常框架

Java项目无论是否使用框架,多采用MVC开发模型,一个项目被分为多层。一个Java框架可能只负责里面的一层。

常见Java框架分类(不仅仅就这些,列举一些常见的):

(1)持久层框架:MyBatis、Hibernate、Spring Data、iBatis。

(2)MVC框架:Spring MVC、Struts1、Struts2。

(3)项目管理框架:Spring Framework、Spring Boot。

(4)微服务框架:Spring Cloud。

(5)权限管理框架:Spring Security、Shiro。

并不是每个项目都需要把上面所有分类都使用上,不同的项目可能只会使用里面几个分类,但是只要使用了其中某个分类,只会选择其中一个。

常见的组合:

(1)SSM:Spring Framework + Spring MVC + MyBatis。最常见组合,属于Java程序员必须掌握的内容。

(2)SSMP:Spring Framework + Spring MVC + MyBatis+MyBatis Plus。对SSM的增强,减少SQL的编写。

(3)SSI:Spring Framework + Spring MVC/Struts1/Struts2 + iBatis。SSM的上代组合,目前很少出现。

(4)SSH:Spring Framework + Struts1/Struts2 + Hibernate。和SSI属于同时代产品,只有在老项目维护时可能出现的技术栈。

(5)Spring Boot + Spring Cloud。微服务架构项目常用组合。

(6)Spring Boot+Mybatis+MybatisPlus。新项目最先选择,比SSM组合使用起来更加方便。

(6)Spring Boot + Shiro/Spring Security。具有权限控制时的组合。

(7)SSM + Shiro/Spring Security。具有权限控制时的组合。

二、软件分层开发:持久层

1. Java EE 三层模型 和 MVC模型

Java EE 三层模型和MVC模型属于两种分层模型,一些同学可能认为这是同一个概念,其实并不然。

Java EE中最经典的是三层模型。包含表示层(Presentation)、业务逻辑层(Business Logic)、持久层(Persistence)

MVC 模型也是三层模型。包含模型层(Model)、视图层(View)、控制层(Controller)。

Java EE 三层模型和MVC模型最主要的区别是:

(1)Java EE三层模型中没有控制层,MVC中有控制层。

(2)Java EE三层模型中业务模型层是单独一部分,就是service层,MVC中模型层包含:业务模型(业务逻辑层)和数据模型(实体类,持久层)。

(3)Java EE三层模型中持久层就是dao层。MVC中虽然持久层在项目中是单独的包,但是在MVC概念中持久层属于模型层中。

2. 目前Java中最常见的六层模型

目前在软件开发过程中最常见的是六层模型,我们讲解的也是六层模型:

(1)视图层。简单点说就是页面,可以是客户端页面技术,也可以是服务端页面技术。例如:HTML、JSP。

(2)控制层。处于业务层和视图层之间,根据业务层结果,控制视图层显示。例如:Servlet。

(3)实体层。就是实体类,负责封装数据,在各个层之间进行数据传递的载体。常见包名:pojo、domain、entity等。

(4)业务逻辑层。专门编写业务逻辑代码。(5)数据持久层/数据访问层。负责编写调用数据库的代码。具体技术:JDBC、MyBatis等。

6)数据源层。一些持久化工具,负责存储数据的。例如:MySQL、Oracle等。

3. 为什么要有持久层

 持久层是分层开发中专门负责访问数据源的一层,Java项目中每一层都有自己的作用,持久层的作用就是访问数据源,把访问数据源的代码和业务逻辑代码分离开,有利于后期维护和团队分工开发。同时也增加了数据访问代码的复用性。

4. ORM

ORM(Object/Relation Mapping),中文名称:对象/关系 映射。是一种解决数据库发展和面向对象编程语言发展不匹配问题而出现的技术。

使用JDBC技术时,手动实现ORM映射:

使用ORM时,自动关系映射:

(1)ORM的具体实现可以认为是一个整体。

(2)SQL执行结果后,如果执行的是增删改,不需要去编写拆卸对象的代码,而是由ORM把对象中属性值取出放入到SQL中。

(3)SQL执行结果后,如果执行的是查询,会由ORM将数据库中查询到的结果,转换为对象。

(4)ORM技术相当于一个转换器,是面向对象语言和数据库之间的纽带。

(5)ORM框架封装了对象/关系的自动映射。

5.常见的ORM框架

对于Java程序员来说,整个职业生涯可能听说过或可能用上的ORM框架:

(1)MyBatis:目前使用最多的ORM框架。

(2)Hibernate:零SQL的ORM框架,N年前使用最多的ORM框架。目前只能在一些老的项目中看到。

(3)Spring Data JPA:目前个别公司中使用的ORM框架。是Spring Data家族中的一员。是对JPA(Java Persistence API,JDK5.0)的封装。

(4)Spring Data JDBC:Spring Data中的二级项目,类似Spring Data JPA,但框架的功能要比Spring Data JPA少一些。

三、MyBatis介绍

1. 介绍

MyBatis 是一款优秀的ORM框架,MVC分层开发中的持久层框架,它支持自定义 SQL、存储过程以及高级映射。

MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。

MyBatis可以通过简单的XML或注解来配置,把数据库和Java POJO(Plain Old Java Objects,普通老式 Java 对象)进行映射

四、MyBatis项目创建

1. 创建Maven项目并添加依赖

创建一个Maven项目(示例中叫做:maven1),并配置pom.xml。

需要添加MyBatis的依赖和MySQL驱动的依赖。

小提示:

  1. MyBatis框架只有一个依赖,但不要以为所有框架都是一个依赖。以后的框架可能需要很多依赖。

  2. 驱动包需要自己导入的,MyBatis并没有依赖数据库驱动,因为MyBatis研发者并不知道以后使用这个框架的人使用了哪款数据库。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.bjsxt</groupId>
    <artifactId>mybatis1</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!-- MyBatis 框架依赖 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.9</version>
        </dependency>
        <!-- 数据库驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
        </dependency>
    </dependencies>

</project>

2. 创建MyBatis全局配置文件

在项目的src/main/resources目录下新建mybatis.cfg.xml文件。并在配置文件中填写下面内容。

<?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>
    <environments default="mysql">
        <environment id="mysql">
            <!--配置事务管理器 -->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 配置数据源-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/ssm?useUnicode=true&amp;characterEncoding=utf-8&amp;useSSL=false&amp;serverTimezone=GMT%2B8&amp;allowPublicKeyRetrieval=true"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
<!-- 配置加载mapper映射文件 -->
    <mappers>
        <mapper resource="mybatis/suiyi.xml"/>
    </mappers>
</configuration>

小提示:

  1. 无论如何封装JDBC,数据库连接的四个参数是无法封装的。如果一个框架可以自动获取本地数据库账号和密码,那就别叫框架了,叫木马更合适。

  2. 框架学习过程中配置文件绝大多数都是XML类型。

配置文件解释:

  1. XML文档头是XML文件必须有的。

  2. DOCTYPE声明文档类型,引入外部约束。

  3. <configuration>是根节点。

  4. <environments>的default属性取值必须是下面某个<environment>标签的id属性值。表示当前MyBatis框架到底使用哪个环境。

  5. <environment>的id值是自定义的。表示当前数据库环境的名称。在全局配置文件中<environment>标签可以有多个,里面分别配置上数据源相关参数。例如一个里面配置连接本地MySQL的参数,另一个配置连接服务器中MySQL的参数,还有一个配置连接Oracle数据库的相关参数。都准备好了以后可以通过修改<environments>中default的值来切换连接的数据库,这样要比修改里面具体的连接参数更加方便。

  6. <transactionManager>中type属性用于配置事务的类型。可取值:

    • JDBC:使用原生JDBC的事务管理进行提交和回滚。

    • MANAGED:MyBatis不参与事务管理。交给其他人管理事务。

  7. <dataSource>中type属性值用于配置数据源类型。可取值:

    • UNPOOLED:不使用数据库连接池。每次执行SQL都会打开数据库连接,执行SQL结束都会关闭连接。适用于简单小型应用。

    • POOLED:使用MyBatis内置数据库连接池。对于频繁访问数据库的应用程序来说,这个取值是很适合的。

    • JNDI:使用本地目录接口技术连接容器外部的数据源。这种方式很少使用,一般都是极其复杂的项目,对数据源要求极高的情况下才能使用。

  8. <properties>配置具体属性和值

    • driver、url、username、password四个属性名称是固定的,但是没有顺序要求,添加到<properties>的name属性中即可。分别代表驱动类、连接字符串、用户名、密码。value属性的值为连接数据库的具体参数值。

3. 创建Mapper映射文件

在src/main/resources目录中新建mybatis目录。这个文件夹可以新建也可以不建立,名称也是随意的。以后mapper文件会比较多,建立一个文件夹项目结构比较好看,名称叫做mybatis也好记。

在mybatis文件夹下新建xml文件,文件名称随意。示例中就叫做suiyi.xml

在suiyi.xml文件中完成下面代码。

小提示:

在没有和接口绑定时,namespace中内容是随意的,而且多个mapper文件的namespace可以相同的。但是不能没有namespace,值也是不能为空的。

<mapper>是根节点,必须存在的。

<insert>专门用于新增的标签

id属性值是自定义的。只要保证标签的namespace+id没有重复的就可以了。

<?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="a.b.c">
    <insert id="add">
        insert into people values(default,'张三')
    </insert>
</mapper>

4. 编写测试类,启动项目

测试代码核心思想:MyBatis是对JDBC的封装,所有封装的方法都放入到了SqlSession类中。想要执行映射文件中SQL就必须创建SqlSession对象。

每次调用MyBatis的方法都需要创建SqlSession对象,所以MyBatis使用了工厂设计模式,由SqlSessionFactory负责创建SqlSession。

SqlSessionFactory需要加载全局配置文件,通过构造方法创建代码较负责,所以MyBatis使用了构建者设计模式,提供了更加简单的方式实例化工厂对象。

在类中主方法写上MyBatis操作流程代码。

public class Test {
    public static void main(String[] args) throws IOException {
        // 1. 获取全局配置文件输入流
        InputStream is = Resources.getResourceAsStream("mybatis.cfg.xml");
        // 2. 加载全局配置文件后创建工厂类
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
        // 3. 使用工厂创建SqlSession。SqlSession里面封装了所有增删改查和事务的方法。
        SqlSession session = factory.openSession();
        // 4. 执行映射文件中id="add"标签中SQL,并返回结果。如果当前项目中只有一个id="add",前面命名空间可以省略
        int index = session.insert("a.b.c.add");
        // 输出受影响行数,听过结果查看是否执行成功。
        System.out.println(index);
        // 5. 提交事务。DML操作必须提交事务,DQL不需要提交事务。
        session.commit();
        // 6. 关闭连接,释放资源
        session.close();
    }
}

五、MyBatis属性加载

MyBatis支持加载属性文件(.properties文件),可以通过在属性文件中配置数据库连接属性然后加载。这种方式要比直接写稍微麻烦一点点,但是却把所有的数据库连接书写到了统一的文件中,以后查看或修改时更加方便。

1. 创建属性文件

在src/main/resources目录中创建db.properties文件

注意:需要将$amp;转义字符变为&,否则运行报错

db.url=jdbc:mysql://localhost:3306/ssm?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
db.driver=com.mysql.cj.jdbc.Driver
db.username=root
db.password=root

2. 修改全局配置文件

修改mybatis.cfg.xml文件,设置加载属性。

 <properties resource="db.properties"></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>
    <!-- 加载属性文件,当前文件和db.properties在同一个目录中,使用相对路径 -->
    <properties resource="db.properties"></properties>
    <environments default="mysql">
        <environment id="mysql">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <!-- 通过${key}获取属性文件中配置的值 -->
                <property name="driver" value="${db.driver}"/>
                <property name="url" value="${db.url}"/>
                <property name="username" value="${db.username}"/>
                <property name="password" value="${db.password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="mybatis/suiyi.xml"/>
    </mappers>
</configuration>

六、常见Java日志工具包

1. 日志介绍

日志是项目开发非常重要的一项。项目部署到服务器以后,并不能所有信息都通过控制台或命令窗口进行查看。把日志信息输入到文件中更有利于项目的维护。

Java项目的日志是可以输入到控制台、可以输入到文件中、甚至可以输入到某个数据源中。但是常用的还是控制台和文件。

在Java项目中常见的日志工具包:

  • Log4j:Apache推出的日志工具。
  • Logback:属于Log4j的继承者。Spring Boot默认日志文件支持类型。
  • Log4j2:属于Log4j升级版,同时里面还包含了Logback的很多改进。
  • commons-logging:Apache早期基于门面(Facade)设计模式的日志包,提供了日志解构能力,按照顺序寻找当前项目日志接口实现,Log4j、JDK Log、SimpleLog。
  • Slf4j( Simple Logging Facade for Java ):目前使用非常多的门面日志。统一项目中日志。
  • JDK Logging:JDK自带的日志API

2. JDK Logging

JDK Logging 是JDK自带的日志工具。存在于java.uti.logging包中。

日志的级别: OFF > SEVERE > WARNING > INFO > CONFIG > FINE > FINER > FINEST > ALL

注意:

1. 默认级别为INFO。

2. 只会显示该级别及该级别以上日志信息。

package com.bjsxt;

import java.io.IOException;
import java.util.logging.*;

public class Demo {
    public static void main(String[] args) throws IOException {
        //参数通常设置为所在的类名
        Logger logger = Logger.getLogger("Demo");
        // 默认为INFO级别,同时设置当前和父处理器级别才能修改
        // OFF > SEVERE > WARNING > INFO > CONFIG > FINE > FINER > FINEST > ALL
        logger.setLevel(Level.FINEST);
        Handler[] handlers = logger.getParent().getHandlers();// 获取输出控制台的处理器
        handlers[0].setLevel(Level.FINEST);// 设置控制台输出级别

        // 默认没有输出到文件,只输出到控制台,通过添加Handler增加输出目的地,输出到文件中
        FileHandler fh = new FileHandler("my.log");// 如果路径夹会不存在文件夹会报错
        fh.setFormatter(new SimpleFormatter());// 设置输出内容为普通格式
        logger.addHandler(fh);

        logger.severe("severe");// 严重
        logger.warning("warning");// 警告
        logger.info("info");// 信息
        logger.config("config");// 配置
        logger.fine("fine");// 详细
        logger.finer("finer");// 较详细
        logger.finest("finest");// 非常详细
    }
}

3. Log4j的使用

Log4j会自动寻找classpath下log4j.properties作为配置文件。

具体使用步骤:

3.1 配置pom.xml

<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

3.2 编写配置文件

在resources中新建log4j.properties,名称不要写错了。

log4j中定义的级别:fatal(致命错误) > error(错误) > warn(警告) > info(普通信息) > debug(调试信息) > trace(跟踪信息)

# log4j中定义的级别:fatal(致命错误) > error(错误) > warn(警告) > info(普通信息) > debug(调试信息) > trace(跟踪信息)
log4j.rootLogger = DEBUG , console , file

### console ###(日志显示在控制台的配置)
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern = [%p] [%-d{yyyy-MM-dd HH\:mm\:ss}] %C.%M(%L) | %m%n

### log file ###(日志输出在文件中的配置)
log4j.appender.file = org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.File = D:/log4j.log
log4j.appender.file.Append = true
# 级别只能比根日志界别高,比根日志级别低不生效
#log4j.appender.file.Threshold = info 
log4j.appender.file.layout = org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern = [%p] [%-d{yyyy-MM-dd HH\:mm\:ss}] %C.%M(%L) | %m%n
3.3 编写测试类
package com.bjsxt;
// 不要导错包
import org.apache.log4j.Logger;

public class TestLog4j {
    public static void main(String[] args) {
        Logger logger = Logger.getLogger(TestLog4j.class);
        logger.trace("跟踪级别");
        logger.debug("调试信息");
        logger.info("普通信息");
        logger.warn("警告信息");
        logger.error("错误信息");
        logger.fatal("重大错误信息");
    }
}

4. Log4j2

4.1 配置pom.xml

虽然只导入了log4j-core,但是实际导入log4j-core和log4j-api。

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.17.2</version>
</dependency>

4.2 编写配置文件

Log4j2不再支持Log4j的.properties格式配置文件。而是支持.xml、.json、jsn。

 Log4j2中定义的级别:fatal(致命错误) > error(错误) > warn(警告) > info(普通信息) > debug(调试信息) > trace(跟踪信息)

在resource目录新建log4j2.xml。

<?xml version="1.0" encoding="utf-8" ?>
<Configuration >
    <!-- 定义输出的目的地 -->
    <Appenders>
        <!-- Console 定义控制台输出 name:自定义名称 target:输出方式,支持SYSTEM_OUT SYSTEM_ERR -->
        <Console name="console" target="SYSTEM_OUT">
            <!-- 输出信息表达式 -->
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
        <!-- File 定义文件输出 fileName 文件路径  append是否允许追加 -->
        <File name="file" fileName="D:/log4j2.log" append="true">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </File>
    </Appenders>

    <Loggers>
        <!-- 控制总体级别 -->
        <!-- fatal > error > warn > info > debug > trace -->
        <Root level="info">
            <!-- 引用输出位置的配置,Appenders中直接子标签的name属性值 -->
            <AppenderRef ref="console"/>
            <AppenderRef ref="file"/>
        </Root>
    </Loggers>
</Configuration>
4.3 编写测试类

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class TestLog4j {
    public static void main(String[] args) {
        Logger logger = LogManager.getLogger(TestLog4j.class);
        logger.trace("跟踪级别");
        logger.debug("调试信息");
        logger.info("普通信息");
        logger.warn("警告信息");
        logger.error("错误信息");
        logger.fatal("重大错误信息");
    }
}

5. SLF4j

SLF4j是日志的接口声明,不参与日志的具体实现,需要配合其它日志具体实现工具包才能进行使用。

每次添加其它日志工具包时,不要忘记SLF4j整合这个日志的依赖。

5.1 整合Log4j
5.1.1 导入依赖

导入3个依赖,分别代表slf4j依赖、整合依赖、log4j的依赖。

<!--slf4j整合log4j的依赖,版本要和slf4j的版本对应 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.36</version>
</dependency>
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

5.1.2 编写log4j的配置文件

在resources下新建log4j.properties文件。

5.1.3 编写测试类

小提示:

SLF4J作为门面设计模式的具体实现,无论使用哪种日志具体实现,都是下面的API。

  Logger logger = LoggerFactory.getLogger(所在类名.calss);

public class TestSlf4j {
    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger(TestSlf4j.class);

        logger.trace("trace");
        logger.debug("debug");
        logger.info("info");
        logger.warn("warn");
        logger.error("error");
    }
}
5.2 整合Log4j2
5.2.1 配置pom.xml

与SLF4J整合Log4j的整合包是不一样的。

 <dependencies>
    <!-- SLF4j整合Log4j2的依赖 -->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-slf4j-impl</artifactId>
        <version>2.17.2</version>
    </dependency>
    <!-- Log4j2工具的依赖-->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.17.2</version>
    </dependency>
</dependencies>

5.2.2 添加Log4j2的配置文件

在src/main/resources

5.2.3 运行测试类

测试类的API和整合Log4j的API是完全相同的,直接运行即可。

5.3 即整合Log4j又整合Log4j2

SLF4J支持多种日志实现,但是在项目中整合依赖最好只有一个,否则会出现警告。

中新建log4j2.xml文件。

七、MyBatis启用日志功能

1. MyBatis支持的日志(疑问)

MyBatis框架内置日志工厂。日志工厂负责自动加载项目中配置的日志。MyBatis支持以下日志,当存在多个日志工具时,严格按照从上往下顺序使用,且只会使用一个。

  • SLF4J

  • Apache Commons Logging

  • Log4j 2

  • Log4j (deprecated since 3.5.9)

  • JDK logging

其中Log4j是MyBatis中之前使用较多的一个日志实现。但是从3.5.9版本被替换了,在目前3.5.9版本中还能使用,但是在将来的版本中会被移除。下面分别演示MyBatis整合Log4j和Log4j2的实现方案。

2. MyBatis结合Log4j实现打印执行的SQL

2.1 增加Log4J依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.bjsxt</groupId>
    <artifactId>beike1</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!-- MyBatis 框架依赖 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.9</version>
        </dependency>
        <!-- 数据库驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
        </dependency>
        <!-- log4j -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>
</project>
2.2 创建Log4j配置文件

在resources中新建log4j.properties。名称必须叫这个名字,扩展名必须是.properties。

在配置文件中填写下面内容

log4j.rootLogger=ERROR, stdout
# log4j.logger是固定的,xxx是命名空间的名字可以只写一部分。
log4j.logger.xxx=TRACE

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

2.3 运行类,观察结果

运行测试类,观察控制台输出结果。发现SQL打印到控制台了。

Preparing: 执行的SQL,里面可以有占位符( ?)。

Parameters:占位符按照顺序的值。

Updates:影响行数。

3. MyBatis结合Log4j2实现打印执行SQL

3.1 编写pom.xml
<dependencies>
    <!-- MyBatis 框架依赖 -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.9</version>
    </dependency>
    <!-- 数据库驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.28</version>
    </dependency>
    <!-- log4j2 -->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.17.2</version>
    </dependency>
</dependencies>
3.2 创建配置文件

在resources目录下新建log4j2.xml文件

<?xml version="1.0" encoding="utf-8" ?>
<Configuration >
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
    </Appenders>

    <Loggers>
        <Root level="info">
            <AppenderRef ref="Console"/>
        </Root>
        <!-- namespace的值 -->
        <logger name="a.b.c" level="debug"></logger>
    </Loggers>
</Configuration>

4. 指定生效的日志

在MyBatis中默认按照顺序寻找,如果项目中存在多个日志。可以通过mybatis全局配置文件进行设置哪个日志生效。

在mybatis.cfg.xml中配置<settings>的标签

<?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">
        <property name="mykey" value="com.mysql.cj.jdbc.Driver"/>
    </properties>
    <!-- 位置为properties下面,typeAlias的上面,具体可以Ctrl+mybatis-3-config.dtd查看 -->
    <settings>
        <!-- 配置生效的日志 -->
        <setting name="logImpl" value="LOG4J"/>
    </settings>
    <environments default="suiyi1">
        <environment id="suiyi1">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="${mykey}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="mybatis/suiyi.xml"></mapper>
        <mapper resource="mybatis/suiyi2.xml"></mapper>
    </mappers>
</configuration>

MyBatis的settings中logImpl支持:

  • SLF4J

  • LOG4J

  • LOG4J2

  • JDK_LOGGING

  • COMMONS_LOGGING

  • STDOUT_LOGGING

  • NO_LOGGING (不启用日志)

八、SQL参数

1. MyBatis中的占位符

MyBatis中最常用的占位符为 #{},在MyBatis的mapper文件的SQL中使用#{}作为占位符。最终解析时会解析成JDBC的占位符?。

2. 当参数为简单数据类型

当参数为一个简单数据类型时。例如:八大基本数据类型、String类型等。可以通过#{任意内容}获取到。

1. 任意内容代表着,随意写,只要不是特殊字符即可。

2. 但是要注意不能不写。

2.1 修改Test类

SqlSession的insert()方法有两种。

int insert(String statement);// 参数:调用SQL的名称。a.b.c.add
int insert(String statement, Object parameter);// 第一个参数:调用SQL的名称。第二个参数:参数值

在第一个MyBatis项目中使用的是insert(String statement)。如果想要传递参数就需要使用insert(String,Object)的方法。

 修改Test类中代码,传递参数值给mapper文件中的SQL。

public class Test {
    public static void main(String[] args) throws IOException {
        InputStream is = Resources.getResourceAsStream("mybatis.cfg.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
        SqlSession session = factory.openSession();
        // 给定了insert方法的第二个参数。
        int index = session.insert("a.b.c.add","参数值");
        System.out.println(index);
        session.commit();
        session.close();
    }
}

2.2 修改mapper文件内容

SQL语句中使用#{}获取Test类中传递过来的参数值。

<?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="a.b.c">
    <insert id="add">
        insert into people values(default,#{suiyixie})
    </insert>
</mapper>

3. 当参数为多个值时

由于insert(String,Object)方法只有一个Object类型方法能作为SQL参数,如果希望传递多个值,可以创建一个对应类,通过对象进行传递。如果不想创建一个类,也可以把所有SQL参数放入到一个Map中。

4. 当参数为对象类型参数

当参数对象类型时,可以使用#{对象中属性名}获取对象属性值。

5. ${} 的使用(重点)

  • ${}在被MyBatis进行解析时,不会解析为占位符?,而是直接解析成对应的值。也就是说使用${}时有点类似字符串拼接。
  • 学习JDBC时我们知道SQL中存在字符串拼接时,会有SQL注入问题。
  • JDBC中占位符?是不允许代替列名和表名的,也就意味着MyBatis的#{}不允许代替表名和列名,但是使用${}可以动态设置列名或表名。
  • ${}和#{}获取参数的写法完全相同。如果参数是对象通过${属性名}获取。如果参数时Map,通过${key}获取。如果参数是简单数据类型,通过${任意不为空的内容}进行获取。

例如:

 insert into   ${table}   values(#{id},#{name}) 

通过结果可以观察到${table}被直接解析为people,#{id}和#{name}被解析成

6. #{}和${}的区别(经典面试题)

  • #{}被解析为?,用在设置列的值或条件值时,也可以使用在分页等需要设置具体值的情况。
  • ${}表示字符串拼接,用在动态设置表名和动态设置列名的情况下。

注意:

  无论 使用 #{}还是${},其底层在执行Sql操作时都 PreparedStatement​​​​​​​

九、MyBatis中DQL操作

1. MyBatis中DQL操作总体说明

MyBatis的DQL操作在映射文件都是通过<select>标签实现的。

SqlSession根据根据查询结果类型不同,提供了五种查询方法:

方法名解释说明
selectOne()查询一行数据时,返回值为Object。如果没有查询到,但是不能查询到多行。
selectMap()查询多行数据时,把其中某列结果当做key,每行结果为Value
selectList()当查询多行数据时,返回值为List。如果没有查询到返回长度为零的List对象。
selectCursor()使用游标查询时使用,在大量数据时可以代替分页
select()万能方法,需要自己定义结果处理器

2. selectOne()方法使用

selectOne()方法要求查询结果是一行或没有查询到。如果查询结果是多行会报异常。

如果这行数据有多个值,可以放在实体类对象中。如果这行数据只有一列,可以使用简单数据类型接收

2.1 修改映射文件
  •  在映射中添加<select>标签,resultType属性是<select>标签必须有的属性,表示查询结果最终类型。取值为类型的全限定路径。
  • resultType是<select>必须写的属性。如果不写resultType属性执行时会报错。
  • 如果使用selectOne()方法,对应的SQL查询到多行数据会报错。

3. selectList()方法使用

selectList()方法主要用在多行查询时,查询时把每行结果按照resultType类型进行封装,最终放入到List中。

3.1 修改映射文件
  • 注意:resultType的类型为每行结果的类型,也就是List的泛型的类型。
  • 如果没有查询到结果,返回长度为0的集合,而不是null。

4. selectMap()方法使用

selectMap(String statement,Object param,String key);比上面多了String key参数。

String key:指定查询结果中哪列的值作为map的key。map的value是整行数据,类型和resultType类型一致。

5. selectCursor()方法使用

cursor 表示游标。属于对查询结果集的一种遍历方式。MyBatis底层使用JDBC,在MyBatis封装的Cursor中只有遍历功能。

selectCursor()返回值为Cursor,提供了forEach()遍历和iterator()两种遍历方式。 

public class Test {
    public static void main(String[] args) throws IOException {
        InputStream is = Resources.getResourceAsStream("mybatis.cfg.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
        SqlSession session = factory.openSession();
        Map<String,Object> param = new HashMap<>();
        param.put("id",1);
        // 返回游标
        Cursor<People> cursors = session.selectCursor("a.b.c.cursor", param);
        // 遍历游标
        cursors.forEach(System.out::println);
        session.commit();
        session.close();
    }
}

6. select()方法使用

select(String statement,Object param,ResultHandler resultHandler);方法中第三个参数表示结果处理。

在ResultHandler接口中只有一个方法,表示如何处理。

public interface ResultHandler<T> {
  void handleResult(ResultContext<? extends T> resultContext);
}

在MyBatis中提供了几个实现类,以DefaultResultHandler举例。

DefaultResultHandler中实现了把结果添加到全局属性list中。所以使用DefaultResultHandler作为结果处理器时,和selectList()结果类型类似。

通过DefaultResultHandler源码也可以看出,MyBatis在处理结果时是按照行为单位,每行数据填充为某种特定类型,然后放入到List集合中。

public class DefaultResultHandler implements ResultHandler<Object> {

  private final List<Object> list;

  public DefaultResultHandler() {
    list = new ArrayList<>();
  }

  @SuppressWarnings("unchecked")
  public DefaultResultHandler(ObjectFactory objectFactory) {
    list = objectFactory.create(List.class);
  }
    //查询到一条数据,调用一次此方法
  @Override
  public void handleResult(ResultContext<?> context) {
    list.add(context.getResultObject());
  }

  public List<Object> getResultList() {
    return list;
  }

}
6.1 修改映射文件
<?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="a.b.c">
    <insert id="add">
        insert into people values(#{id},#{name})
    </insert>
    <update id="update">
        update people set name=#{name} where id=#{id}
    </update>
    <delete id="remove">
        delete from people where id=#{id}
    </delete>
    <select id="one" resultType="com.bjsxt.pojo.People">
        select * from people where id = #{id}
    </select>
    <select id="list" resultType="com.bjsxt.pojo.People">
        select * from people
    </select>
    <select id="map" resultType="com.bjsxt.pojo.People">
        select * from people
    </select>
    <select id="cursor" resultType="com.bjsxt.pojo.People">
        select * from people
    </select>
    <!-- DQL:select -->
    <select id="select" resultType="com.bjsxt.pojo.People">
        select * from people
    </select>
</mapper>
6.2 修改Test类
public class Test {
    public static void main(String[] args) throws IOException {
        InputStream is = Resources.getResourceAsStream("mybatis.cfg.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
        SqlSession session = factory.openSession();
        Map<String,Object> param = new HashMap<>();
        param.put("id",1);

        // 定义结果处理器
        DefaultResultHandler handler = new DefaultResultHandler();
        // 把查询到的结果交给handler处理,DefaultResultHandler把结果存储到全局list属性中
        session.select("a.b.c.select", param, handler);
        // 获取全局list属性值
        System.out.println(handler.getResultList());

        session.commit();
        session.close();
    }
}

十、分页查询

1. MyBatis实现分页查询的几种方式

在MyBatis中实现查询有两种方式:

  1. 根据对应的数据库,编写SQL。这种方式与数据库耦合度较高,移植性差。但是确实我们平时使用的方式,因为大部分项目是没有修改数据库类型的场景。

  2. 使用MyBatis提供的RowBounds实现分页​​​​​​​

1. RowBounds方式进行分页

RowBounds是MyBatis中提供的一种"假分页"实现方式。对从数据库中查询到的结果进行截取。所以如果数据库中数据量特别大的时候可能会出现OOM等问题。

但是由于RowBounds不需要考虑底层数据库是什么,且使用简单,所以对于一些数据量不是特别大的应用还是有人选择使用的。

在SqlSession中select、selectMap、selectList中通过方法重载都提供了一个带有RowBounds。

  // RowBounds(偏移量,查询行数)
        RowBounds rowBounds = new RowBounds(0,2);
        List<People> list = session.selectList("a.b.c.rowBounds",null,rowBounds);

 

十一、模糊查询

1. 使用#{}实现模糊查询

        select * from people where name like #{name}

// 参数的值里面包含了%
        List<People> list = session.selectList("a.b.c.like", "%张%");

2. 使用${}实现模糊查询

使用${}时由于是字符串拼接,所以两侧需要带有双引号。

这种方式的SQL比较固定,两侧%已经写到SQL中,不能像#{}形式动态设置是包含、开头、结尾等形式的模糊查询。

 <!-- 模糊查询 -->
    <select id="like2" resultType="com.bjsxt.pojo.People">
        select * from people where name like '%${name}%'
    </select>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
学习笔记——mybatis的起步(1) 1.什么是框架? 他是我们软件开发中的一套解决方案,不同的框架解决的是不同的问题。 使用框架的好处: 框架封装了很多的细节,使开发者可以使用极简的方式实现功能。大大提高开发效率。 2.三层架构 表现层: 是用于展示数据的 业务层: 是处理业务需求的 持久层: 是和数据库交互的 3.持久层的技术解决方案 JDBC技术: Connection PreparedStatement ResultSet Spring的JdbcTemplate: Spring中对jdbc的简单封装 Apache的DBUtils: 它和Spring的JdbcTemplate很想,也是对Jdbc的简单封装 以上这些都不是框架 JDBC是规范 Spring的JdbcTemplate和Apache的DBUtils都只是工具类 4.mybatis的概述 mybatis是一个持久层框架,用java编写的。 它封装了jdbc操作的很多细节,开发者只需要关注sql语句本身,无需关注注册驱动,创建连接等繁杂过程 它使用了ORM思想实现了结果集的封装。 ORM: Object Relational Mappinng 对象关系映射 简单的说: 就是把数据库表和实体类及实体类的属性对应起来 让我们可以操作实体类就实现操作数据库表。 user User id userId user_name userName 今天我们需要做到 实体类中的属性和数据库表的字段名称保持一致 user User id id user_name user_name 5.mybatis的入门 mybatis的环境搭建 第一步:创建maven工程并导入坐标 第二步:创建实体类和dao接口 第三步:创建Mybatis的主配置文件 sqlMapConfig.xml 第四步:创建映射配置文件 IUserDao.xml 环境搭建的注意事项: 第一个:创建IUserDao.xml 和 IUserDao.java 时名称是为了和我们之前的只是保持一致。 在Mybatis中它把持久层的接口名称和映射文件叫做:Mapper 所以:IUserDao 和 IUsrMapper 是一样的 第二个:在idea中创建目录的时候,它的包是不一样的 包在创建时:com.itheima.dao它是三级结构 目录在创建时:com.itheima.dao是一级目录 第三个:mybatis的映射配置文件位置必须和到接口的包结构相同 第四个:映射配置文件的mapper标签namespace属性的取值必须是dao接口的全限定类名 第个:映射配置文件的操作配置(select),id属性的取值必须是dao接口的方法名 当我们遵从了第三、四、之后,我们在开发中就无需再写dao的实现了。 mybatis的入门案列

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值