Mybatis

  • 持久层框架,方便填写sql语句

  • 方便,帮助将数据存入数据库

  • 传统的JDBC代码太复杂。简化、框架、自动化。

  • 优点

    • 简单易行
    • 灵活
    • sql和代码的分离,提高了可维护性
    • 。。。

持久化

数据持久化

  • 持久化就是将程序的数据在持久状态和顺势状态转化的过程
  • 内存:断电即失
  • 数据库(Jdbc),io文件持久化

持久层

Dao层,Service层,Controller层

  • 完成持久化工作的代码块
  • 层界限十分明显

1. Mybatis程序

1.1 搭建环境

  • 搭建数据库
create database `mybatics`;

use mybatics;


create table `user`(
    `id` int(20) not null,
    `name` varchar(30) default null,
    `pwd` varchar(30) default null,
    primary key(`id`)
)engine=InnoDB default charset=utf8;


insert into `user`(`id`,`name`,`pwd`) values
(1,'张三','123456'),
(2,'李四','123456'),
(3,'王五','123456')

新建项目

  1. 创建maven项目
  2. 更换自己的maven仓库
  3. 删除src目录
  4. 导入maven依赖
    <dependencies>
        <!-- mysql驱动 -->
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.16</version>
        </dependency>

        <!-- mybatis -->
        <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.6</version>
        </dependency>

        <!-- junit -->
        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
        </dependency>

    </dependencies>

1.2 创建模块

idea数据库连接

问题:

  1. mysql8.0 需要重新导入8.0的jdbc的jar包

  2. serverTimezone未配置

    • 打开mysql命令行
    // 显示时区信息
    show variables like’%time_zone’;
    // 若显示为system  -->  表示未设置时区
    //设置时区
    set global time_zone=’+8:00’;
  • 编写mybatis核心配置文件

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <!-- configuration核心配置文件 -->
    <configuration>
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://localhost:3306/mybatics?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
                    <property name="username" value="root"/>
                    <property name="password" value="888888"/>
                </dataSource>
            </environment>
        </environments>
        <mappers>
            <mapper resource="org/mybatis/example/BlogMapper.xml"/>
        </mappers>
    </configuration>
  • 编写mybatis工具类

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;

//sqlSessionFactory --> sqlSession
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();
        }
    }
    //从sqlSessionFactory获取sqlSession实例
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();

    }


}

1.3 编写代码

  • 实体类
public class User {

    private int id;
    private String name;
    private String pwd;

    public User(){

    }

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

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}
  • Dao接口
public interface UserDao {
    List<User> getUserList();
}
  • 接口实现类 : 由原来的Dap实现类重写方法的方式转为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接口 -->
<mapper namespace="com.Rickduck.dao.UserDao">

        <!--select查询语句-->
        <select id="getUserList" resultType="com.Rickduck.pojo.User">
                select * from mybatis.user
        </select>

</mapper>

1.4 测试

核心配置中配置mapper

junit单元测试

package com.Rickduck.dao;

import com.Rickduck.pojo.User;
import com.Rickduck.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;

import java.util.List;

public class MyTest {

    @Test
    public void test(){

        //第一步:获得SqlSession
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //执行Sql
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = userMapper.getUserList();
        for (User user : userList) {
            System.out.println(user);
        }

        sqlSession.close();

    }
}

需要注意的问题

  • 配置文件是否已有注册
  • 绑定接口是否有错
  • 方法名是否有错
  • 返回类型是否正确
  • Maven导出资源是否有问题
  • SqlSessionFactoryBuilder
    • 负责创建SqlSessionFactory,一旦创建了SqlSessionFactory,就不再需要用它
    • 方法作用域(局部方法变量)
  • SqlSessionFactory
    • 创建SqlSession,一旦被创建就应该在应用的运行期间一直存在
    • 应用作用域(单例模式或静态单例模式)
  • SqlSession
    • 每个线程应该都有自己的SqlSession实例
    • 线程不安全
    • 请求或方法作用域
    • 每收到HTTP请求,就可以打开SqlSession,返回一个响应,就关闭
    • 关闭操作放在finall块中!!!

另外关于资源配置的问题:

<!-- 在build中配置resources,来防止我们资源导出失败的问题 -->
<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>

2. CRUD

1.namespace

namespace中的包名跟Mapper接口的包名一致

2. select

选择、查询语句

  • id : 方法名
  • resultType : Sql语句执行的返回值
  • parameterType : 参数类型
    //第一步:获得SqlSession
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    //执行Sql
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    @Test
    public void select(){

        try{

            // 1. select *
            List<User> userList = userMapper.getUserList();
            for (User user : userList) {
                System.out.println(user);
            }

            //2. selecById
            User user = userMapper.getUserById(1);
            System.out.println(user);

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //关闭sqlSession
            sqlSession.close();
        }

    }

3. insert(增删改 需要提交事务)

    @Test
    public void insertTest(){

        //3. insert (增删改需要提交事务)
        int flag = userMapper.addUser(new User(4,"哈哈","123456"));

        //事务提交
        sqlSession.commit();
        //关闭sqlSession
        sqlSession.close();
    }

4. update

5. delete

6.Map

实体类或数据库中的表、字段或者参数过多,可以考虑使用Map!

3. 配置解析

1.核心配置文件

  • mybatis-config.xml

  • MyBatis的配置文件会深深影响Mybatis星为的设置和属性信息

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

2. 环境配置

可以配置多个环境,但每个sqlSessionFactory实例只能选择一个环境

默认事务管理器:JDBC

默认连接池:POOLED

3. 属性(properties)

可以通过properties属性实现引用配置文件(内部优先)

  • 属性可外部配置动态替换
    <!-- 引入外部配置文件 -->
    <properties resource="db.properties" >
        <property name="username" value=""/>
        <property name="password" value=""/>
    </properties>

4. 类型别名

  1. 实体类
  2. 包扫描
  3. 注解(实体类上添加@Alias("name") )
    <typeAliases>
        <!-- 实体类起别名 -->
        <typeAlias type="com.Rickduck.pojo.User" alias="User" />
        <!-- 包扫描起别名-->
        <package name="com.Rickduck.pojo"/>
    </typeAliases>

5. 设置

6. 映射器

MapperRegistry : 注册绑定我们的映射文件

方式一: xml配置

    <mappers>
        <mapper resource="com/Rickduck/dao/UserMapper.xml"/>
    </mappers>

方式二: class文件绑定注册

    <mappers>
       <mapper class="com.Rickduck.pojo.UserMapper" />
    </mappers>

注意点:

  • 接口和Mapper配置文件必须同名
  • 接口和Mapper配置文件必须在同一包下

方式三:使用包扫描

    <mappers>
       <package name="com.Rickduck.pojo"/>
    </mappers>

注意点:

  • 接口和Mapper配置文件必须同名
  • 接口和Mapper配置文件必须在同一包下

7. 生命周期和作用域

图片说明

SqlSessionFactoryBuilder

  • 一旦创建就不再需要
  • 最佳作用域:局部变量

SqlSessionFactory

  • 一旦创建旧应该一直存在(类似连接池)
  • 最佳作用域:应用作用域
  • 单例模式/静态单例模式

SqlSession

  • 连接到连接池的一个请求

  • SqlSession非线程安全,不能被共享

  • 最佳作用域:请求或方法作用

  • 用完后断开

4. 解决属性名和字段名不一致的问题

resultMap

结果集映射

<mapper namespace="com.Rickduck.dao.UserMapper">

    <!-- pojo类与数据库名字不一致可一一映射 -->
    <!-- 结果集映射 -->
    <resultMap id="UserMap" type="User">

        <result column="id",property="id" />
        <result column="name",property="name" />
        <result column="pwd",property="password" />
    </resultMap>

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

</mapper>
  • ResultMap设计思想:对于简单语句不需要配置显示映射,复杂语句只需要描述他们的关系即可

5. 日志

5.1 日志工厂

  • 出现异常、排错 需要日志!!
  • 曾经:sout、debug
  • 现在:日志工厂!

1609925677993

  • mybatis-config.xml 在properties中添加:
  • STDOUT_LOGGING : 标准日志输出
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

5.2 Log4J

  • log4J:可以控制日志信息的输出位置(控制台,组件,文件)
  • 可以控制输出格式
  • 可以定义日志的级别,更加细致控制日志的生成过程
  • 可通过一个配置文件配置而无需修改代码
  1. 导入log4j的包
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.14.0</version>
        </dependency>
  1. log4j.properties

  1. 配置log4j为日志实现
<settings>
    <setting name="logImpl" value="LOG4J" />
</settings>
  1. log4j的使用 测试运行

简单使用

  1. 在需要使用log4j的类中,导入包 import org.apache.log4j.logger

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

//日志对象
static Logger logger = Logger.getLogger(UserMapper.class);
public void testLog4j(){
    logger.info("info");
    logger.debug("debug");
    logger.error("error");
}
  1. 日志级别
logger.info("info");
logger.debug("debug");
logger.error("error");

6. 分页

6.1 使用Limit分页

  • 减少数据的处理量
  • 使用limit进行分页
-- 语法:select * from user limit startIndex,pageSize;
select * from user limit 0,2;

利用Mybatis实现分页,核心SQL

  1. 接口
List<User> getUserByLimit(Map<String,Integer> map);
  1. Mapper.xml
<select id="getUserByLimit" parameterType="map" resultType="User">
    select * from student.user limit #{startIndex},#{pageSize}
</select>
  1. 测试
@Test
public void getUserByLimit(){
    //第一步:获得SqlSession
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    //执行Sql
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    HashMap<String, Integer> map = new HashMap<>();
    map.put("startIndex",0);
    map.put("pageSize",2);
    List<User> userList = userMapper.getUserByLimit(map);
    for (User user : userList) {
        System.out.println(user);
    }

    sqlSession.close();
}

6.2 通过RowBound实现分页

  1. 接口
    List<User> getUserByRowBounds();
  2. mapper.xml
    <select id="getUserByRowBounds" resultMap="UserMap">
     select * from mybatis.user
    </select>

    6.3 分页插件

8. 使用注解开发

8.1 面向接口编程

  • 根本原因:解耦

三个面向区别

  • 面向对象 :以对象为单位,考虑其属性及方法
  • 面向过程 :以具体流程(事务过程)为单位,考虑其实现
  • 接口设计与非接口设计是针对复用技术而言,更多体现对系统的整体架构

8.2 使用注解开发

是可以使用Java注解来配置

public interface UserMapper{

    @Select("select * ftom student.user")
    List<User> getUsers();

}