MyBatis简易教程

1、什么是MyBatis

MyBatis本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。MyBatis是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAO)MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis使用简单的XML或注解用于配置和原始映射,将接口和Java的POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
简单来说,MyBatis是一个用来帮你管理数据增删改查的框架。

2、搭建MyBatis环境

2.1 新建maven工程

配置文件pom.xml写上

<build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <!--修改Language level-->
                    <!--这里写你的jdk版本,如果是8则写1.8-->
                    <source>11</source>
                    <!--修改Java Compiler-->
                    <target>11</target>
                </configuration>
            </plugin>
        </plugins>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
           <!-- 由于maven只能识别resources里的xml配置文件.因此放在mapper类中的配置文件需要设置<include>才能被获取   -->
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>
    </build>


    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.20</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.6</version>
            <scope>provided</scope>
        </dependency>


    </dependencies>

2.2 新建数据表

新建mybatis数据库,并且在mybatis中新建一个空表t_account。

use mybatis;
create table t_account(
	id int primary key auto_increment;
	username varchar(11);
	password varchar(11);
	age int
)

2.3 新建数据表对应的实体类Account

package com.southwind.entity;

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

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Account {
    //成员变量要和数据库字段相同
    private long id;
    private String username;
    private String password;
    private int age;
}

2.4 创建MyBatis的配置文件config.xml

config.xml位于resources文件下, 需要自己新建。

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

<configuration>

    <!--    配置mybatis运行环境-->
    <environments default="development">
        <environment id="development">
            <!--      配置JDBC事务管理-->
            <transactionManager type="JDBC"></transactionManager>
            <!--  POOLED配置JDBC数据源连接池 -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<!--          value="jdbc:mysql://      serverTimezone=GMT%2B8&amp;-->
                <property name="url"
                          value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=GMT%2B8&amp;useUnicode=true&amp;characterEncoding=UTF-8"></property>
                <property name="username" value="root"/>
                <property name="password" value="1234"/>
            </dataSource>
        </environment>
    </environments>

</configuration>

2.5 使用MyBatis

2.5.1 使用原生接口

原理图:
在这里插入图片描述
1、创建Mapper类对应的Mapper.xml,定义管理该对象的SQL。(实际开发中,会给每个实体类创建对应的想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设置为xml所在的包+文件名-->
<mapper namespace="com.southwind.mapper.AccountMapper">
    <!-- 根据对象传参数-->
<!--    insert标签代表插入数据,还有delete,update和select;
        根据id的值来调用方法执行sql语句;
        parameterType是指调用对应方法时参数的数据类型;
        -->
    <insert id="save" parameterType="com.southwind.entity.Account">
        insert into t_account(username,password,age) values (#{username},#{password},#{age})
    </insert>

</mapper>

2、在全局配置文件config.xml中注册AccountMapper.xml

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

<configuration>

    <!--    配置mybatis运行环境-->
    <environments default="development">
        <environment id="development">
            <!--      配置JDBC事务管理-->
            <transactionManager type="JDBC"></transactionManager>
            <!--  POOLED配置JDBC数据源连接池 -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<!--          value="jdbc:mysql://      serverTimezone=GMT%2B8&amp;-->
                <property name="url"
                          value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=GMT%2B8&amp;useUnicode=true&amp;characterEncoding=UTF-8"></property>
                <property name="username" value="root"/>
                <property name="password" value="1234"/>
            </dataSource>
        </environment>
    </environments>

    <!--  注册AccountMapper.xml  -->
    <mappers>
        <mapper resource="com\southwind\mapper\AccountMapper.xml"></mapper>
    </mappers>
    
</configuration>

3、调用MyBatis的原生接口执行添加操作

package com.southwind.test;

import com.southwind.entity.Account;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Test {
    public static void main(String[] args) {
        //忽视由于jdk版本过高导致的Illegal reflective access by org.apache.ibatis.reflection.Reflector警告
        disableAccessWarnings();
        //输入流文件  读取config配置
        InputStream inputStream = Test.class.getClassLoader().getResourceAsStream("config.xml");
        //获取实现接口
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //选择mapper里的
        String statement = "com.southwind.mapper.AccountMapper.save";
        Account account = new Account(1L,"张三","123",22);
        sqlSession.insert(statement,account);
        sqlSession.commit();

    }


    @SuppressWarnings("unchecked")
    public static void disableAccessWarnings(){
        try {
            Class unsafeClass = Class.forName("sun.misc.Unsafe");
            Field field = unsafeClass.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            Object unsafe = field.get(null);

            Method putObjectVolatile = unsafeClass.getDeclaredMethod("putObjectVolatile", Object.class, long.class, Object.class);
            Method staticFieldOffset = unsafeClass.getDeclaredMethod("staticFieldOffset", Field.class);

            Class loggerClass = Class.forName("jdk.internal.module.IllegalAccessLogger");
            Field loggerField = loggerClass.getDeclaredField("logger");
            Long offset = (Long) staticFieldOffset.invoke(unsafe, loggerField);
            putObjectVolatile.invoke(unsafe, loggerClass, offset, null);
        } catch (Exception ignored) {
        }
    }

}

4、结果
由于我们的AccountMapper类对应的Mapper.xml只有一个insert方法,并且inset的对象是Account(1L,“张三”,“123”,22),因此执行完后会在数据库中插入一行数据。
在这里插入图片描述

2.5.2 Mapper代理实现自定义接口

流程: 1、自定义接口,定义相关也二五方法
2、编写与方法对应的Mapper.xml

1、自定义接口

package com.southwind.repostory;

import com.southwind.entity.Account;

import java.util.List;

public interface AccountRepostory {
    public int save(Account account);
    public int update(Account account);
    public int deleteById(long id);
    public List<Account> findAll();
    public Account findById(long id);

}

2、创建接口对应的mapper.xml,定义接口方法的sql语句。
mapper.xml中statement标签可根据sql执行的业务选择insert、update、delete和select
MyBatis框架会根据规则自动创建接口实现类的代理对象:
遵循的规则

  • mapper.xml中namespace为接口的全类名
  • mapper.xml中statement的id为接口中对应的方法名
  • mapper.xml中statement的parameterType要和接口中对应的方法参数一致
  • mapper.xml中statement的resultType和接口对应的方法的返回值一致
<?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.southwind.repostory.AccountRepostory">
<!--    插数据-->
    <insert id="save" parameterType="com.southwind.entity.Account">
        insert into t_account(username,password,age) values (#{username},#{password},#{age});
    </insert>
<!--更新数据-->
    <update id="update" parameterType="com.southwind.entity.Account">
        update t_account set username = #{username},password = #{password},age = #{age} where id = #{id}
    </update>
<!--    根据id删除-->
    <delete id="deleteById" parameterType="long">
        delete from t_account where id = #{id}
    </delete>
<!--    根据id查找-->
    <select id="findById" parameterType="long" resultType="com.southwind.entity.Account">
        select * from t_account where id = #{id}
    </select>
<!--    查找所有-->
    <select id="findAll" resultType="com.southwind.entity.Account">
        select * from t_account
    </select>

</mapper>

3、在config.xml中注册AccountRepository.xml

    <!--  注册AccountMapper.xml  -->
    <mappers>
        <mapper resource="com\southwind\mapper\AccountMapper.xml"></mapper>

        <mapper resource="com\southwind\repostory\AccountRepository.xml"></mapper>
    </mappers>

4、调用接口的代理对象完成业务操作

package com.southwind.test;

import com.southwind.entity.Account;
import com.southwind.repostory.AccountRepostory;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

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

public class Test2 {

    public static void main(String[] args) {
        InputStream inputStream = Test.class.getClassLoader().getResourceAsStream("config.xml");
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //获取实现接口的代理对象
        AccountRepostory accountRepostory = sqlSession.getMapper(AccountRepostory.class);

        //增加
//        Account account = new Account(2L,"李四","726",25);
//        accountRepostory.save(account);



        //查找全部
//        List<Account> list = accountRepostory.findAll();
//        for(Account ac:list){
//            System.out.println(ac);
//        }

        //修改
//        Account account = accountRepostory.findById(2);
//        account.setUsername("二狗");
//        account.setAge(90);
//        account.setPassword("111111");
//        System.out.println(accountRepostory.update(account));

		//删除
        System.out.println(accountRepostory.deleteById(3));

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

3、Mapper.xml配置

Mapper.xml和config.xml是使用MyBatis框架的两大核心,所有操作都要通过这两个配置文件来配合完成。

  • statement标签:select、update、insert、delete分别对应查询、更新、插入和删除操作。
  • parameterType:参数数据类型

1、基本数据类型

	<select id="findById" parameterType="long" resultType="com.southwind.entity.Account">
        select * from t_account where id = #{id}
    </select>

2、String类型

	<select id="findByName" parameterType="java.lang.String" resultType="com.southwind.entity.Account">
         select * from t_account where username = #{username}
    </select>

3、包装类

	<select id="findById2" parameterType="java.lang.Long" resultType="com.southwind.entity.Account">
        select * from t_account where id = #{id}
    </select>

4、多个参数

    <select id="findByNameAndAge" resultType="com.southwind.entity.Account">
        select * from t_account where username = #{param1} and age =#{param2}
    </select>

5、java Bean

    <insert id="save" parameterType="com.southwind.entity.Account">
        insert into t_account(username,password,age) values (#{username},#{password},#{age});
    </insert>
  • resultType:结果类型
    1、基本数据类型
    <select id="count" resultType="int">
        select count(id) from t_account
    </select>

2、String类型

    <select id="findById" resultType="java.lang.String">
        select username from t_account where id = #{id}
    </select>

3、包装类

    <select id="count2" resultType="java.lang.Integer">
        select count(id) from t_account
    </select>

4、java Bean

    <insert id="save" parameterType="com.southwind.entity.Account">
        insert into t_account(username,password,age) values (#{username},#{password},#{age});
    </insert>

4 级联查询

4.1 一对多

例子:
student表和classes表:在这里插入图片描述
表结构:主键:Classes的id,外键:student的cid
在这里插入图片描述

实体类:
Student类:

package com.southwind.entity;

import lombok.Data;

@Data
public class Student {
    private int id;
    private String name;
    private Classes classes;
}

Classes类:

package com.southwind.entity;

import lombok.Data;

import java.util.List;

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

}

StudentRepository接口:

package com.southwind.repostory;

import com.southwind.entity.Student;

public interface StudentRepository {
    public Student findById(int id);
}

StudentRepository.xml配置文件
实现一对多级联操作不用resultType,应该设置一个resultMap ,建立起Student和Classes的映射,然后传入select 中

<?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.southwind.repostory.StudentRepository">

    <resultMap id="studentMap" type="com.southwind.entity.Student">
        <!--        student映射-->
        <id column="id" property="id"></id>
        <result column="name" property="name"/>
        <!--        建立连接关系-->
        <association property="classes" javaType="com.southwind.entity.Classes">
            <id column="cid" property="id"></id>
            <result column="cname" property="name"></result>
        </association>
    </resultMap>


    <select id="findById" parameterType="int" resultMap="studentMap">
        select s.id,s.name,c.id as cid,c.name as cname from student s , classes c where s.id = #{id};
    </select>

</mapper>

ClassesRepository.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.southwind.repostory.ClassesRepository">

    <resultMap id="classesMap" type="com.southwind.entity.Classes">
        <!--        student映射-->
        <id column="cid" property="id"></id>
        <result column="cname" property="name"/>
        <!--        建立连接关系
            property是classes的成员变量
            ofType是泛型
        -->
        <collection property="students" ofType="com.southwind.entity.Student">
            <id column="id" property="id"/>
            <result column="name" property="name" />
        </collection>
    </resultMap>


    <select id="findById" parameterType="int" resultMap="classesMap">
        select s.id,s.name,c.id as cid,c.name as cname from student s , classes c where c.id = #{id};
    </select>

</mapper>

注意:resultmap需要根据两表的映射关系以及所需要查询的结果来设计

4.2 多对多

数据表:
三张,一张顾客表customer,一张商品表goods,一张映射表customer_goods,映射顾客与商品之间的对应关系。

在这里插入图片描述
Customer类:

package com.southwind.entity;


import lombok.Data;

import java.util.List;

@Data
public class Customer {
    private int id;
    private String name;
    private List<Goods> goods;
}

Goods类

package com.southwind.entity;


import lombok.Data;

import java.util.List;

@Data
public class Goods {
    private int id;
    private String name;
    private List<Customer> customers;
}

CustomerRepository接口

package com.southwind.repository;

import com.southwind.entity.Customer;

public interface CustomerRepository {
    public Customer findById(int id);
}

CustomerRepository.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.southwind.repository.CustomerRepository">

    <resultMap id="customerMap" type="com.southwind.entity.Customer">
        <!--        student映射-->
        <id column="cid" property="id"></id>
        <result column="cname" property="name"/>
        <!--        建立连接关系-->
        <collection property="goods" ofType="com.southwind.entity.Goods">
            <id column="gid" property="id"></id>
            <result column="gname" property="name"></result>
        </collection>
    </resultMap>


    <select id="findById" parameterType="int" resultMap="customerMap">
        select c.id cid,c.name cname,g.id gid,g.name gname from customer c,goods g,customer_goods cg where c.id = #{id} and cg.cid = c.id and cg.gid = g.id;
    </select>

</mapper>

GoodsRepository接口

package com.southwind.repository;

import com.southwind.entity.Customer;
import com.southwind.entity.Goods;

public interface GoodsRepository {
    public Goods findById(int id);
}

GoodsRepository.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.southwind.repository.GoodsRepository">

    <resultMap id="goodsMap" type="com.southwind.entity.Goods">
        <!--        student映射-->
        <id column="gid" property="id"></id>
        <result column="gname" property="name"/>
        <!--        建立连接关系-->
        <collection property="customers" ofType="com.southwind.entity.Customer">
            <id column="cid" property="id"></id>
            <result column="cname" property="name"></result>
        </collection>
    </resultMap>


    <select id="findById" parameterType="int" resultMap="goodsMap">
        select c.id cid,c.name cname,g.id gid,g.name gname from customer c,goods g,customer_goods cg where g.id = #{id} and cg.cid = c.id and cg.gid = g.id;
    </select>

</mapper>

目的:1、在查询顾客时根据映射表查出他购买的商品 2、在查询商品时根据映射表查出商品对应的买家
原理:在顾客类和商品类中都有一个集合,顾客类中是泛型为商品的集合,商品类则是泛型为顾客
因此在xml中要使用collection标签,并且根据他们的映射关系以及sql语句配置好xml文件

流程:1、确定sql语句 2、确定映射关系 3、写配置文件xml
查询结果:(以查询商品为例)

控制台输出:
Goods(id=3, name=洗衣机, customers=[Customer(id=1, name=张三, goods=null), Customer(id=3, name=小明, goods=null)])

5 逆向工程

MyBatis框架需要实体类、自定义Mapper接口,Mapper.xml
传统开发中以上三个都需要开发者手动创建,逆向工程可以实现自动创建。

使用:
通过MyBatis Generator(简称MBG,是一个代码生成器)
1、新建maven工程
创建依赖

<?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.southwind</groupId>
    <artifactId>aimbg</artifactId>
    <version>1.0-SNAPSHOT</version>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <!--修改Language level-->
                    <!--这里写你的jdk版本,如果是8则写1.8-->
                    <source>11</source>
                    <!--修改Java Compiler-->
                    <target>11</target>
                </configuration>
            </plugin>
        </plugins>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <!-- 由于maven只能识别resources里的xml配置文件.因此放在mapper类中的配置文件需要设置<include>才能被获取   -->
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>
    </build>


    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.4</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.20</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.4.0</version>
        </dependency>

    </dependencies>

</project>

2、创建MBG配置文件generatorConfig.xml
位于resource文件下

  1. jdbcConnection 配置数据库连接信息
  2. javaModelGenerator 配置javaBean生成策略
  3. sqlMapGenerator 配置SQL映射文件生成策略
  4. javaClientGenerator 配置Mapper接口的生成策略
  5. table配置目标数据表(tableName表名,domainObjectName:java Bean类名)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <context id="testTables" targetRuntime="MyBatis3">
<!--        jdbc连接-->
        <jdbcConnection
                driverClass="com.mysql.cj.jdbc.Driver"
                connectionURL="jdbc:mysql://localhost:3306/mybatis?serverTimezone=GMT%2B8&amp;useUnicode=true&amp;characterEncoding=UTF-8"
                userId="root" password="1234"
        ></jdbcConnection>
<!--        实体类生成-->
        <javaModelGenerator targetPackage="com.southwind.entity" targetProject="./src/main/java"></javaModelGenerator>

<!--        sql语句-->
        <sqlMapGenerator targetPackage="com.southwind.repository" targetProject="./src/main/java"></sqlMapGenerator>

<!--        map接口-->
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.southwind.repository" targetProject="./src/main/java"></javaClientGenerator>
        
        
        <table tableName="t_account" domainObjectName="Account"></table>
    </context>
</generatorConfiguration>

3、创建Generator执行类

package com.southwind.test;

import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.exception.InvalidConfigurationException;
import org.mybatis.generator.exception.XMLParserException;
import org.mybatis.generator.internal.DefaultShellCallback;



import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String> warings = new ArrayList<String>();
        boolean overwrite = true;
        String genCig = "/generatorConfig.xml";
        File configFile = new File(Main.class.getResource(genCig).getFile());
        ConfigurationParser configurationParser = new ConfigurationParser(warings);
        Configuration configuration = null;

        try {
            configuration = configurationParser.parseConfiguration(configFile);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (XMLParserException e) {
            e.printStackTrace();
        }

        DefaultShellCallback callback = new DefaultShellCallback(overwrite);
        MyBatisGenerator myBatisGenerator = null;
        try {
            myBatisGenerator = new MyBatisGenerator(configuration,callback,warings);
        } catch (InvalidConfigurationException e) {
            e.printStackTrace();
        }
        try {
            myBatisGenerator.generate(null);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

执行后会自动创建实体类、Mapper接口以及Mapper配置文件。

6、延迟加载

延迟加载是指对数据持久层的操作,对于多个sql的查询,采取延迟加载的方式来减少与数据库的交互。

在访问学生表和班级表时,假如只需要获取学生表的信息,不需要获取学生对应的班级时就可以不执行查询班级表的SQL语句。

  1. 在config.xml中开启延迟加载
    <settings>
<!--        打印sql-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
<!--        开启延迟加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
    </settings>
    
  1. 将多表关联查询拆分成多个单表查询

StudentRepository

public Student findByIdLazy(int id);

StudentRepository.xml

    <resultMap id="studentMapLazy" type="com.southwind.entity.Student">
        <id column="id" property="id"></id>
        <result column="name" property="name"/>
        <association property="classes" javaType="com.southwind.entity.Classes"
                    select="com.southwind.repository.ClassesRepository.findByIdLazy"
                     column="cid">
        </association>
    </resultMap>

    <select id="findByIdLazy" parameterType="int" resultMap="studentMapLazy">
        select * from student where id = #{id};
    </select>

ClassesRepository

public Classes findByIdLazy(int id);

ClassesRepository.xml

    <select id="findByIdLazy" parameterType="int" resultType="com.southwind.entity.Classes">
        select * from classes where id = #{id}
    </select>

7、MyBatis缓存

使用缓存减少java应用与数据库的交互次数,从而提高程序的运行效率。会将之前查找的对象存放在缓存中,下次查找相同对象就可以直接访问,而不需要再与数据库交互。

MyBatis缓存分类

7.1 一级缓存:SqlSession级别,默认开启,且不能关闭

创建SqlSession对象,对象中有HashMap用于存储缓存数据。不同的SqlSession之间的缓存数据互不影响。

一级缓存的作用域是SqlSession范围的,在同一个SqlSession中执行两次相同的sql语句,第一次执行完会把结果保存到缓存中,第二次查询直接从缓存中调取。
注意:如果SqlSession执行了DML操作(insert、update、delete),那么需要清空缓存以保证数据的准确性

7.2 二级缓存:Mapper级别,默认关闭,可以开启

对于使用同一个Mapper的多个SqlSession,会使用同一个缓存区,同样也是使用HashMap进行数据存储。与一级缓存比较,二级缓存范围更大。

二级缓存的作用域是Mapper的同一个namespace,不同的SqlSession执行相同的namespace下的sql语句时可以根据二级缓存获得已查询过的信息。

(1)MyBatis自带二级缓存

  • config.xml配置开启二级缓存
    <settings>
<!--        打印sql-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
<!--        开启延迟加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
<!--        开启二级缓存-->
        <setting name="cacheEnabled" value="true"/>
    </settings>
  • Mapper.xml中配置二级缓存
    在mapper标签中
 <cache></cache>
  • 实体类实现序列化接口

implements Serializable

package com.southwind.entity;

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

import java.io.Serializable;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Account implements Serializable {
    //成员变量要和数据库字段相同
    private long id;
    private String username;
    private String password;
    private int age;
}

  • 执行类
 package com.southwind.test;

import com.southwind.entity.Account;
import com.southwind.repository.AccountRepository;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.InputStream;

public class Test4 {
    public static void main(String[] args) {
        InputStream inputStream = Test.class.getClassLoader().getResourceAsStream("config.xml");
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();

        AccountRepository accountRepository = sqlSession.getMapper(AccountRepository.class);
        Account account = accountRepository.findById(1);
        System.out.println(account);
        //关闭sqlSession 模拟两个sqlSession进行同个查询,观察执行了多少次sql语句
        //一级缓存会执行两次,二级缓存只会执行一次
        sqlSession.close();
        sqlSession = sqlSessionFactory.openSession();
        accountRepository = sqlSession.getMapper(AccountRepository.class);
        Account account1 = accountRepository.findById(1);
        System.out.println(account1);
    }
}
  • 输出:
    由图能看出,查询结果有两个,并且只执行了一次sql语句。
    在这里插入图片描述

(2)ehcache

  1. pom.xml添加依赖
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-ehcache</artifactId>
            <version>1.0.0</version>
        </dependency>

        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache-core</artifactId>
            <version>2.4.3</version>
        </dependency>

  1. 在resource下添加ehcache.xml
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
    <diskStore/>
    <defaultCache
            maxElementsInMemory="1000"
            maxElementsOnDisk="10000000"
            eternal="false"
            overflowToDisk="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
    </defaultCache>
</ehcache>
  1. config.xml配置开启二级缓存
    <settings>
<!--        打印sql-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
<!--        开启延迟加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
<!--        开启二级缓存-->
        <setting name="cacheEnabled" value="true"/>
    </settings>
  1. Mapper.xml中配置二级缓存
    <cache type="org.mybatis.caches.ehcache.EhcacheCache">
<!--    缓存创建后,最后一次访问缓存的时间到缓存失效的时间间隔-->
        <property name="timeToIdleSeconds" value="3600"/>
<!--        缓存自创建时间起到失效的时间间隔-->
        <property name="timeToLiveSeconds" value="3600"/>
<!--        缓存回收策略,LRU表示移除近期使用最少的对象-->
        <property name="memoryStoreEvictionPolicy" value="LRU'"/>
    </cache>

  1. 实体类不需要实现序列化接口
package com.southwind.entity;

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

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Account  {
    //成员变量要和数据库字段相同
    private long id;
    private String username;
    private String password;
    private int age;
}

8、动态sql

8.1 where与if标签

where标签一般和if搭配使用,where标签可以自动判断是否要删除多余的and关键字,如果检测到where直接和and拼接,则自动删除and。

    <select id="findByAccount" parameterType="com.southwind.entity.Account" resultType="com.southwind.entity.Account">
        select * from t_account
        <where>
            <if test="id!=0">
                id = #{id}
            </if>
            <if test="username!=null">
                and username = #{username}
            </if>
            <if test="password!=null">
                and password = #{password}
            </if>
            <if test="age!=0">
                and age = #{age}
            </if>
        </where>
    </select>

8.2 choose与when标签

<select id="findByAccount" parameterType="com.southwind.entity.Account" resultType="com.southwind.entity.Account">
        select * from t_account
        <where>
            <choose>
                <when test="id!=0">
                    id = #{id}
                </when>
                <when test="username!=null">
                    username = #{username}
                </when>
                <when test="password!=null">
                    password = #{password}
                </when>
                <when test="age!=0">
                    age = #{age}
                </when>
            </choose>
        </where>
    </select>

8.3 trim标签

trim标签中的prefix和suffix属性会被用于生成实际的sql语句,会和标签内部的语句进行拼接,如果语句前后出现了prefixOverrides或者suffixOverrides属性中指定的值,MyBatis框架会自动将其删除。

prefix:在trim标签内sql语句加上前缀
suffix:在trim标签内sql语句加上后缀
suffixOverrides:指定去除多余的后缀内容
比如:suffixOverrides=”,”,去除trim标签内sql语句多余的后缀”,”
prefixOverrides:指定去除多余的前缀内容

 <select id="findByAccount" parameterType="com.southwind.entity.Account" resultType="com.southwind.entity.Account">
        select * from t_account
        <trim prefix="where" prefixOverrides="and">
            <if test="id!=0">
                id = #{id}
            </if>
            <if test="username!=null">
                and username = #{username}
            </if>
            <if test="password!=null">
                and password = #{password}
            </if>
            <if test="age!=0">
                and age = #{age}
            </if>
        </trim>
    </select>

8.4 set标签

set标签用于update操作,会自动根据参数选择生成sql语句。

 <update id="update" parameterType="com.southwind.entity.Account">
        update t_account
        <set>
            <if test="username!=null">
                username = #{username},
            </if>
            <if test="password!=null">
                password = #{password},
            </if>
            <if test="age!=0">
                age = #{age},
            </if>
        </set>
        where id = #{id}
    </update>

8.5 foreach标签

foreach标签迭代生成一系列值,这标签主要用于sql的in语句。

<select id="findByIds" parameterType="com.southwind.entity.Account" resultType="com.southwind.entity.Account">
--         select * from t_account where id in (2,4);
        select * from t_account
        <where>
            <foreach collection="ids" open="id in (" close=")" item="id" separator=",">
                #{id}
            </foreach>
        </where>
    </select>
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值