MyBatis相关知识点总结

MyBatis学习笔记

一、简介

1.1 什么是MyBatis?

  • MyBatis 是一款优秀的持久层框架

    • 持久层:就是数据访问层DAL,主要功能就是负责数据库的访问。

      Dao层、Service层、Controller层

  • 它支持自定义 SQL、存储过程以及高级映射。免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。

  • MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

1.2 MyBatis的作用

  • 简化JDBC代码,提供持久化的能力,帮助开发人员将数据存入到数据库中

二、MyBatis程序

2.1 项目的创建

  1. 新建一个Maven项目

  2. 删除src文件,这样使当前工程成为父工程

  3. 导入依赖到项目的pom.xml文件中

    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.2</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    

2.2 模块的创建

在项目中创建一个Maven模块

从XML中构建SqlSessionFactory

由于每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的,SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。

1. 配置MyBatis工具类

通过 SqlSessionFactoryBuilder 获得SqlSessionFactory 的实例。在java文件下创建一个utils包,然后创建一个MybatisUtils类文件。

package com.rainlx.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;

public class MybatisUtils {

    private static SqlSessionFactory sqlSessionFactory;	//
    static {
        try {
            //构建获取sqlSessionFactory对象
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //SqlSession 提供了在数据库执行 SQL 命令所需的所有方法
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
}

2. MyBatis核心配置文件
  • 在resources文件中创建mybatis-config.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="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  </mappers>
</configuration>
  • DataSource中的"url"、“username”、"password"都是数据库的信息,具体的值和连接的数据库有关。

  • 配置好的mybatis-config.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="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/test01?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <!--所有的Mapper.xml配置文件都要在MyBatis核心配置文件中注册-->
    <mappers>
        <mapper resource="com/rainlx/dao/UserMapper.xml"/>
    </mappers>
</configuration>

PS:所有的Mapper.xml文件一定要在mybatis-config.xml中注册

2.3 项目代码

代码中要有实体类、接口、实现类

2.3.1 实体类

java文件下创建pojo包,再创建数据库的User实体类

实体类中声明数据库中的关键字,同时有构造器、get、set方法

public class User {
    private int id;
    private String username;
    private String pwd;

    public User() {
    }

    public User(int id, String username, String pwd) {
        this.id = id;
        this.username = username;
        this.pwd = pwd;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
    
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}

2.3.2 Mapper(Dao)接口

public interface UserMapper {
     List<User> getUserList();
}

2.3.3 接口实现类

  1. 接口实现类可以由一个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">
    
    <!--namespace实现接口绑定,包名要和接口名保持一致-->
    <mapper namespace="com.rainlx.dao.UserMapper">
        <!--id中写的是接口类中的方法名,resultType中写的是下面sql语句返回的结果类型-->
        <!--select返回一个查询结果的集合,集合的泛型是User类型-->
        <select id="getUserList" resultType="com.rainlx.pojo.User">
            select * from test01.user
        </select>
    </mapper>
    
  • 实现类中的命名空间,要用全限定名来实现接口绑定
  • 绑定接口之后,要在核心配置文件mybatis-config.xml中注册mapper
  1. 接口实现类也可以通过Java注解来配置完成语句映射。

2.3.4 测试

public class UserDaoTest {

    @Test
    public void test(){
        SqlSession session = MyBatisUtils.getSqlSession();  //首先获取SqlSession对象;
        UserMapper mapper = session.getMapper(UserMapper.class);  //执行SQL要先拿到SQL,所以去getMapper到UserDao接口
        List<User> userList = mapper.getUserList();         //上一步返回mapper对象之后,就可以执行接口中声明的方法了
        for (User user : userList) {
            System.out.println(user);
        }
        session.close();        //关闭SqlSession
    }
}
运行结果:
User{id=1, username='admin', pwd='admin'}
User{id=2, username='manager', pwd='123456'}
User{id=3, username='test', pwd='123'}

2.4 程序中出现的问题

  1. “[08S01] Communications link failure The last packet sent successfully to the server was 0 milliseconds ago"

**解决方法:**尝试在Windows的服务设置中启动MySQL服务
在这里插入图片描述

  1. IDEA连接MtSQL时可能出现“Server returns invalid timezone”的错误

    **解决方法:**设置MySQL驱动的时区
    在这里插入图片描述

  2. 执行测试后,如果出现“java.lang.ExceptionInInitializerError”

    **解决方法:**在项目和Module的pom.xml文件中,添加:

    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>
    
  3. 如果出现“lineNumber: 8; columnNumber: 19; 2 字节的 UTF-8 序列的字节 2 无效”

    **解决方法:**修改文件编码,setting -> Editor -> file Encodings
    在这里插入图片描述

  4. 如果出现“Error querying database. Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure”

    在网上看了各种解决方法都不行,最后找到一个不清楚原理的方法

    **解决方法:**在mybatis-config.xml配置文件中,将数据库url中的“useSSL=true&useUnicode=true&”修改为“useSSL=false&useUnicode=false”

    原内容为:

    <property name="url" value="jdbc:mysql://localhost:3306/test01?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
    

    ​ 修改后的内容为:

    <property name="url" value="jdbc:mysql://localhost:3306/test01?useSSL=false&amp;useUnicode=false&amp;characterEncoding=UTF-8"/>
    

    在这里插入图片描述

    一个MyBatis程序,需要有的7项内容,为了防止配置文件加载失败的错误发生,直接在项目和Module的pom.xml文件的中添加配置文件信息,详细内容见第2.4节第4部分。

  5. 执行测试时如果出现“class not found”的错误,先去检查target文件夹下是否有生成test-classes,该文件夹下是否有测试类文件的生成 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ah2yttS0-1630315183817)(C:\Users\liuxin\AppData\Roaming\Typora\typora-user-images\image-20210723104642460.png)]

    如果没有,可能是因为执行mvn clean后,编译好的class文件被删除掉了,这时直接在IDEA中运行Junit测试会出现上述错误。

    **解决方法:**执行mvn test,测试生成编译文件 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H57UPZJF-1630315183819)(C:\Users\liuxin\AppData\Roaming\Typora\typora-user-images\image-20210723104559357.png)]

三、增删改查

数据库的功能在接口实现类Mapper.xml中实现

3.1 CRUD基础

在MyBatis程序中新增功能,需要修改三个文件:接口类、接口实现类、测试类

  1. 接口类

    public interface  UserMapper {
         List<User> getUserList();
         
         User getUserById(int id);
    
         int addUser(User user);
    
         int deleteUserById(int id);
    
         int updateUser(User user);
    }
    
  2. 接口实现类

    id:接口类中的方法名

    resultType:Sql语句返回的结果类型

    parameterType:接口定义返回参数的参数类型

    <?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">
    
    <!--namespace-->
    <mapper namespace="com.rainlx.dao.UserMapper">
        <!--id中写的是接口类中的方法名,resultType中写的是下面sql语句返回的结果类型-->
        <!--select返回一个查询结果的List集合,集合的泛型是User类型-->
        <select id="getUserList" resultType="com.rainlx.pojo.User">
            select * from test01.user
        </select>
    
        <select id="getUserById" resultType="com.rainlx.pojo.User" parameterType="int">
            select * from test01.user where id = #{id}
        /*这里取id要通过#来取*/
        </select>
    
        <insert id="addUser" parameterType="com.rainlx.pojo.User">
            insert into test01.user (id, username, pwd) values (#{id},#{username},#{pwd})
        </insert>
    
        <delete id="deleteUserById" parameterType="int">
            delete from test01.user where id = #{id}
        </delete>
    
        <update id="updateUser" parameterType="com.rainlx.pojo.User">
            update test01.user set username = #{username},pwd = #{pwd} where id = #{id}
        </update>
    </mapper>
    
  3. 测试类

    “增删改”需要提交事务

    public class UserDaoTest {
    
        @Test
        public void test(){
            SqlSession session = MybatisUtils.getSqlSession();
            UserMapper mapper = session.getMapper(UserMapper.class);
            List<User> userList = mapper.getUserList();
            for (User user : userList) {
                System.out.println(user);
            }
            session.close();        //关闭SqlSession
        }
    
        @Test
        public void getUserById(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            User user = mapper.getUserById(1);
            System.out.println(user);
            sqlSession.close();
        }
    
        @Test
        public void insertUser(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            mapper.addUser(new User(4, "Aa", "666"));
    
            //“增删改”需要提交事务
            sqlSession.commit();
            sqlSession.close();
        }
    
    
        @Test
        public void deleteUserById(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            int i = mapper.deleteUserById(4);
            sqlSession.commit();
            sqlSession.close();
        }
    
        @Test
        public void updateUser(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            mapper.updateUser(new User(3,"Bb","111222333"));
            sqlSession.commit();
            sqlSession.close();
        }
    }
    

3.2 Map

假设实体类的参数或数据库表中字段很多,可以使用Map

  1. 接口类

    int updateUser2(Map<String,Object> map);
    

    Map的语法:

    Map<Key,Value>
    
  2. 接口实现类

    接口实现类中,参数类型为map,SQL语句中包括需要修改的字段和主键即可

    <update id="updateUser2" parameterType="map">
        update test01.user set pwd = #{password} where id = #{id}
        /*这里的password和id是map的Key*/
    </update>
    
  3. 测试类

    @Test
    public void updateUser2(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        Map<String, Object> map = new HashMap<>();
        map.put("password",12321);
        map.put("id",3);
        mapper.updateUser2(map);
        sqlSession.commit();
        sqlSession.close();
    }
    
  • Map传递参数,直接在sql中取出Key

    例如:

    Map<String, Object> map = new HashMap<>();
    map.put("pwd",12321);
    map.put("id",3);
    mapper.updateUser2(map);
    
  • 对象传递参数,直接在sql中取出对象的属性

    例如:

    mapper.updateUser(new User(3,"Bb","111222333"));
    
  • 只有一个基本类型参数的情况下,可以直接在sql中取到

    例如:

    mapper.deleteUserById(4);
    
  • 多个参数用Map或者是注解

3.3 模糊查询

  1. 接口类

    List<User> getUserListLike(String name);
    
  2. 接口实现类

    <select id="getUserListLike" resultType="com.rainlx.pojo.User">
        select * from test01.user where username like #{name}
    </select>
    
  3. 测试类

    @Test
    public void getUserListLike(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userListLike = mapper.getUserListLike("%m%");	//传递通配符% %
        for (User user:userListLike) {
            System.out.println(user);
        }
        sqlSession.close();
    }
    运行结果:
    User{id=1, username='admin', pwd='admin'}
    User{id=2, username='manager', pwd='123456'}
    

四、XML配置

4.1 核心配置文件

mybatis-config.xml文件,其顶层结构如下:

properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
	environment(环境变量)
		transactionManager(事务管理器)
		dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)

4.2 环境配置(environments)

MyBatis 可以配置成适应多种环境,可以将 SQL 映射应用于多种数据库之中。

连接N个数据库,就要创建N个SqlSessionFactory实例,每个数据库对应一个实例,为了制定创建哪种环境,只要将它作为可选的参数传递给 SqlSessionFactoryBuilder 即可。有下面两种方式:

SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, properties);

环境配置中有两个重要的元素,事务管理器(transactionManager)数据源(dataSource)

  1. 事务管理器(transactionManager)

    在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]")

    JDBC这个配置使用了JDBC的提交和回滚设施

    • PS:如果使用 Spring + MyBatis,则没有必要配置事务管理器,因为 Spring 模块会使用自带的管理器来覆盖前面的配置。
  2. dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源

    有三种内建的数据源类型(也就是 type="[UNPOOLED|POOLED|JNDI]")

    • POOLED利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。

4.3 属性(properties)

可以在典型的Java属性文件中配置这些属性,也可以在properties元素的子元素中设置。编写好外部文件后,在核心配置文件中引入。

在外部文件中设置好的属性,可以用来替换需要动态配置的属性值,两种方式:

  1. 引入配置文件后,增加一些属性
<properties resource="org/mybatis/example/config.properties">
  <property name="username" value="root"/>
  <property name="password" value="root"/>
</properties>
<environments default="development">
    <environment id="development">
        <transactionManager type="JDBC"/>
        <dataSource type="POOLED">
            <property name="driver" value="${driver}"/>
            <property name="url" value="${url}"/>
        </dataSource>
    </environment>
</environments>
  1. 直接引入外部配置文件
<!--引入外部配置文件-->
<properties resource="db.properties"/>

<environments default="development">
    <environment id="development">
        <transactionManager type="JDBC"/>
        <dataSource type="POOLED">
            <property name="driver" value="${driver}"/>
            <property name="url" value="${url}"/>
            <property name="username" value="${username}"/>
            <property name="password" value="${password}"/>
        </dataSource>
    </environment>
</environments>
  • 当外部文件和中存在相同字段时,优先使用外部配置文件的属性值。

4.4 设置(settings)

MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。

各项设置的含义可参考官方文档

4.5 类型别名(typeAliases)

可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。

  • 可以给实体类取别名
<typeAliases>
  <typeAlias alias="Author" type="domain.blog.Author"/>
  <typeAlias alias="Blog" type="domain.blog.Blog"/>
  <typeAlias alias="Post" type="domain.blog.Post"/>
  <typeAlias alias="Section" type="domain.blog.Section"/>
  <typeAlias alias="Tag" type="domain.blog.Tag"/>
</typeAliases>

这样配置后,Blog可以用在任何使用domain.blog.Blog的地方

  • 也可以指定一个包名,这时可以直接使用小写字母来做别名,例如
<typeAliases>
  <package name="domain.blog"/>
</typeAliases>

在包domain.blog中的类domain.blog.Author的别名为author,若有注解,则别名为其注解值,例如:

@Alias("author")
public class Author {
    ...
}

4.6 映射器(mappers)

定义 SQL 映射语句,告诉 MyBatis 到哪里去找到这些语句,在核心配置文件中添加绑定接口的语句。

  • 方式一
<!-- 使用相对于类路径的资源引用 -->
<mappers>
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
  <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
  <mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
  • 方式二
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
  <mapper class="org.mybatis.builder.AuthorMapper"/>
  <mapper class="org.mybatis.builder.BlogMapper"/>
  <mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
  • 方式三
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
  <package name="org.mybatis.builder"/>
</mappers>

其中,方式二和方式三要求,接口和Mapper配置文件必须同名,且必须在同一个包下

五、 ResultMap结果集映射

解决类中属性名和数据库字段名不一致的问题
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NrNvXV4J-1630315183822)(C:\Users\liuxin\AppData\Roaming\Typora\typora-user-images\image-20210824170126937.png)]
不一致时,直接执行查询,出现的结果为:

User{id=1, username='admin', password='null'}

因为根据password从数据库查询时,没有这个字段,所以取默认值null

  • 解决方法:

用元素实现结果集映射

<resultMap id="UserMap" type="User">
    <!--column对应数据库字段,property属性对应实体类的属性-->
    <result column="id" property="id"/>	        <!--没有映射的可以不写-->
    <result column="username" property="name"/>
    <result column="pwd" property="password"/>
</resultMap>

<select id="getUserById" resultMap="UserMap">
    select * from test01.user where id =#{id}
</select>

注意,这里将resultType 属性替换掉了原来的 resultMap属性

  • ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了

六、日志

6.1 日志工厂

Mybatis 通过使用内置的日志工厂提供日志功能。内置日志工厂将会把日志工作委托给下面的实现之一:

  • SLF4J
  • Apache Commons Logging
  • Log4j 2
  • Log4j
  • JDK logging

Mybatis内置日志工厂按照上面的顺序使用第一个查找到的实现。

如果想指定日志实现,可以在MyBatis 配置文件 mybatis-config.xml 里面添加一项 setting 来选择其它日志实现。可选的值有:SLF4J、LOG4J、LOG4J2、JDK_LOGGING、COMMONS_LOGGING、STDOUT_LOGGING、NO_LOGGING。

  • 例:选择STDOUT_LOGGING为日志的实现
<settings>
    <setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

执行JDBC查询,日志结果如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I6PChfVy-1630315183824)(C:\Users\liuxin\AppData\Roaming\Typora\typora-user-images\image-20210825141953307.png)]

6.2 日志配置

不同日志实现有不同的配置步骤,以Log4J为例。

步骤 1:添加 Log4J 包

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

步骤2:配置文件

在resources下建立一个log4j.properties文件

#设置
log4j.rootLogger = debug,stdout,D,E

#输出到控制台
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n

#输出DEBUG级别以上的日志到
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = ./log/rainlx.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG 
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

#输出ERROR级别以上的日志到
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File = ./log/rainlx.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR 
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n 

步骤3:选择log4j为日志的实现

<settings>
    <setting name="logImpl" value="Log4J"/>
</settings>

步骤4:测试日志实现[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sR6TtGtp-1630315183827)(C:\Users\liuxin\AppData\Roaming\Typora\typora-user-images\image-20210825172213214.png)]

6.3 Log4j使用方法

步骤1:在需要使用Log4j的类包中导入log4j.jar包

import org.apache.log4j.Logger;

步骤2:生成日志对象

日志对象的参数为当前类的class

static Logger logger = Logger.getLogger(UserDaoTest.class);

步骤3:设置日志的级别

@Test
public void log4j(){
    logger.info("信息级别");
    logger.debug("调试级别");
    logger.error("错误级别");
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JX21FtyY-1630315183829)(C:\Users\liuxin\AppData\Roaming\Typora\typora-user-images\image-20210825173302846.png)]

七、分页

7.1 SQL实现

语法:select * from test01.user limit startIndex,pageSize;
  1. 接口
List<User> limitUser(Map<String,Integer> map);
  1. Mapper
<!--这里用resultMap是因为使用了别名,否则需要使用全限定名-->
<select id="limitUser" parameterType="map" resultMap="UserMap">   
    select * from test01.user limit #{startIndex},#{pageSize}
</select>
  1. 测试
@Test
public void limitUser(){
    SqlSession session = MybatisUtils.getSqlSession();
    UserMapper mapper = session.getMapper(UserMapper.class);
    HashMap<String, Integer> hashMap = new HashMap<>();
    hashMap.put("startIndex",0);
    hashMap.put("pageSize",2);
    List<User> userList = mapper.limitUser(hashMap);
    for (User user : userList) {
        System.out.println(user);
    }

    session.close();
}

7.2 Java实现

RowBounds

7.3 插件实现

PageHelper官网介绍了插件的使用方法

八、注解

MyBatis注解开发,可以映射简单语句,但稍复杂的语句,Java注解不太使用,最好使用XML映射语句。

8.1 注解开发

对于像 BlogMapper 这样的映射器类来说,还有另一种方法来完成语句映射。 它们映射的语句可以不用 XML 来配置,而可以使用 Java 注解来配置。

  1. 接口类

    @Select("select * from test01.user")
    List<User> getUsers();
    
  2. xml文件

    <!--绑定接口-->
    <mappers>
        <mapper class="com.rainlx.dao.UserMapper"/>
    </mappers>
    
  3. 测试

    @Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> users = mapper.getUsers();
        for (User user : users) {
            System.out.println(user);
        }
        sqlSession.close();
    }
    

8.2 注解实现CRUD

SQL语句写在接口类中,然后在核心配置文件mybatis-config.xml中绑定接口文件,最后执行即可。

  1. 接口类

    public interface  UserMapper {
    
         //方法存在多个参数,所有的参数前必须加@Param("")注解
         @Select("select * from test01.user where id = #{id}")
         User getUserById(@Param("id") int id);
    
         //values取的值必须为实体类中定义的参数名
         @Insert("insert into test01.user(id,username,pwd) values (#{id},#{username},#{password})")
         int addUser(User user);
    
         @Update("update test01.user set username = #{username}, pwd = #{password} where id = #{id}")
         int updateUser(User user);
    
         //加了@Param注解之后,#取值的名字要和注解的名字相同
         @Delete("delete from test01.user where id = #{delid}")
         int deleteUser(@Param("delid") int id);
    
    }
    

    @Param()注解

    • 基本类型的参数或者String类型,需要加
    • 引用类型不加
    • 如果只有一个基本类型,可以不加
    • 加了之后,在SQL中使用的是注解中使用的属性名
  2. 测试

    @Test
    public void getUserById(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User userById = mapper.getUserById(1);
        System.out.println(userById);
        sqlSession.close();
    }
    
    @Test
    public void addUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.addUser(new User(6,"newuser", "123"));
    
        sqlSession.close();
    }
    
    @Test
    public void updateUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.updateUser(new User(6,"updateuser", "111"));
        sqlSession.close();
    }
    
    @Test
    public void deleteUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.deleteUser(6);
        sqlSession.close();
    }
    
    /*CRUD需要提交事务,但上面代码在执行CRUD之后没有commit,是因为将sqlSessionFactory中autocommit的值修改为了true*/
    public static SqlSession getSqlSession(){
            return sqlSessionFactory.openSession(true);
        }
    

九、Lombok

9.1 Lombok介绍

Lombok提供了一组注解,用来消除一些复杂的Java代码。提供的注解包括:

@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data
@Builder
@SuperBuilder
@Singular
@Delegate
@Value
@Accessors
@Wither
@With
@SneakyThrows
@val
@var
experimental @var
@UtilityClass
Lombok config system
Code inspections
Refactoring actions (lombok and delombok)

比较常用的:

@Data:提供无参构造、get、set、toString、hashcode、equals等方法
@NoArgsConstructor:提供无参构造方法
@AllArgsConstructor:提供有参构造方法
@ToString:提供toString方法

9.2 使用方法

  1. Lombok插件安装:File→settings→Plugins,搜索Lombok进行安装。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y4YxJtub-1630315183831)(C:\Users\liuxin\AppData\Roaming\Typora\typora-user-images\image-20210827091356530.png)]

  2. 导入依赖

    Maven仓库查找相应的依赖并导入pom.xml中。

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.20</version>
        <scope>provided</scope>
    </dependency>
    
  3. 在实体类中添加注解

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        
        private int id;
        private String username;
        private String password;
    
    }
    

    这段代码相比下面这段不添加注解的代码,确实要简化很多,但代码的可阅读性不高,所以不不建议新手经常使用这类插件。

    public class User {
    
        private int id;
        private String username;
        private String password;
    
        public User() {
        }
    
        public User(int id, String username, String password) {
            this.id = id;
            this.username = username;
            this.password = password;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", username='" + username + '\'' +
                    ", password='" + password + '\'' +
                    '}';
        }
    }
    

十、多表查询

10.1 多对一

数据库多表查询,查询每个学生对应的老师,设定现在有两张表student和teacher,student中有字段id、name、tid,其中tid为关联teacher的外键,teacher中有字段id、name。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jjEUskhP-1630315183832)(C:\Users\liuxin\AppData\Roaming\Typora\typora-user-images\image-20210827165913721.png)]

方式一:按照查询嵌套处理

思路:1. 列出student中所有学生的信息

​ 2. 根据查找到的tid去映射老师(子查询)

<select id="getStudent" resultMap="studentTeacher">
    select * from student
</select>
<resultMap id="studentTeacher" type="Student">
    <result property="id" column="id"/>
    <result property="name" column="name"/>
    <!--复杂的属性单独处理
        对象:association
        集合:collection-->
    <!--javaType设置对象teacher的类型,查询再嵌套一个select,即子查询-->
    <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
</resultMap>

<select id="getTeacher" resultType="Teacher">
    select * from teacher where id = #{id}
</select>

方式二:按照结果嵌套处理

思路:SQL联表查询

<select id="getStudent2" resultMap="studentTeacher2">
    select s.id sid,s.name sname,t.name tname 
    from student s,teacher t 
    where s.tid = t.id
</select>
<resultMap id="studentTeacher2" type="Student"> <!--查询结果实质上还是一个Student-->
    <result property="id" column="sid"/>
    <result property="name" column="sname"/>
    <association property="teacher" javaType="Teacher"> <!--复杂映射用association-->
        <result property="name" column="tname"/>
    </association>
</resultMap>

10.2 一对多

查询一个老师下的所有学生信息

  • 接口类

    public interface TeacherMapper {
        Teacher getTeacher(@Param("tid") int id);
    }
    
  • 实体类

    @Data
    public class Teacher {
        private int id;
        private String name;
        private List<Student> students;
    }
    

方式一:按照结果嵌套处理

<select id="getTeacher" resultMap="TeacherStudent">
    select s.id sid,s.name sname,t.id tid,t.name tname
    from student s,teacher t
    where s.tid = t.id and t.id = #{tid}
</select>
<resultMap id="TeacherStudent" type="Teacher">
    <result property="id" column="tid"/>
    <result property="name" column="tname"/>
    <!--JavaType 指定属性的类型
        ofType 集合中的泛型-->
    <collection property="students" ofType="Student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <result property="tid" column="tid"/>
    </collection>
</resultMap>

方式二:按照查询嵌套处理

<select id="getTeacher2" resultMap="TeacherStudent2">
    select * from teacher where id = #{tid}
</select>
<resultMap id="TeacherStudent2" type="Teacher">
    <collection property="students" javaType="ArrayList" ofType="Student" select="getStudentByTid" column="id"/>
</resultMap>
<select id="getStudentByTid" resultType="Student">
    select * from student where tid = #{tid}
</select>

关键点

  • 多对一,关联 - association

  • 一对多,集合 - collection

  • “ofType” 属性,用来将 JavaBean(或字段)属性的类型和集合存储的类型区分开来。

<collection property="posts" javaType="ArrayList" column="id" ofType="Post" select="selectPostsForBlog"/>

读作: “posts 是一个存储 Post 的 ArrayList 集合”

“javaType”属性,用来指定实体类中属性的类型。

``

方式一:按照结果嵌套处理

<select id="getTeacher" resultMap="TeacherStudent">
    select s.id sid,s.name sname,t.id tid,t.name tname
    from student s,teacher t
    where s.tid = t.id and t.id = #{tid}
</select>
<resultMap id="TeacherStudent" type="Teacher">
    <result property="id" column="tid"/>
    <result property="name" column="tname"/>
    <!--JavaType 指定属性的类型
        ofType 集合中的泛型-->
    <collection property="students" ofType="Student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <result property="tid" column="tid"/>
    </collection>
</resultMap>

方式二:按照查询嵌套处理

<select id="getTeacher2" resultMap="TeacherStudent2">
    select * from teacher where id = #{tid}
</select>
<resultMap id="TeacherStudent2" type="Teacher">
    <collection property="students" javaType="ArrayList" ofType="Student" select="getStudentByTid" column="id"/>
</resultMap>
<select id="getStudentByTid" resultType="Student">
    select * from student where tid = #{tid}
</select>

关键点

  • 多对一,关联 - association

  • 一对多,集合 - collection

  • “ofType” 属性,用来将 JavaBean(或字段)属性的类型和集合存储的类型区分开来。

<collection property="posts" javaType="ArrayList" column="id" ofType="Post" select="selectPostsForBlog"/>

读作: “posts 是一个存储 Post 的 ArrayList 集合”

“javaType”属性,用来指定实体类中属性的类型。

以上内容是学习MyBatis的一些总结笔记,后续会更新Spring、Spring MVC、Spring Boot等内容的学习笔记。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值