MyBatis框架

MyBatis

主流的ORM框架,之前叫做iBatis,后来更名为MyBatis,实现数据持久化的框架。
同时java,.NET,Ruby三种语言,MyBatis是一个对JDBC进行封装的框架。
Hibernate是一个全自动化ORM框架,MyBatis是一个半自动化的ORM框架。
全自动化:开发者只需要调用相关接口就可以完成操作,整个流程框架都已经进行了封装。Hibernate实现了POJO和数据库之间的映射,同时可以自动生成SQL语句并完成执行。
半自动化:框架只提供一部分功能,剩下的工作仍需要开发者手动完成,MyBatis没有提供POJO与数据库表的映射,只实现了POJO与SQL之间的映射关系,需要开发者自定义SQL语句,以及数据与POJO之间的装配关系。
虽然功能没有Hibernate更加方便,但是这种半自动化的方式提高了框架的灵活性,开发者可以根据具体的业务需求,完成定制化的持久层解决方案。
MyBatis对所有的JDBC进行了封装,包括参数设置、SQL执行、结果集解析等,通过XML配置/注解的方式完成POJO与数据的映射。

简单讲,使用MyBatis进行开发,主要完成两步操作:

  • 自己编写SQL
  • 自己完成数据库数据与POJO的映射

MyBatis

  • 极大简化了JDBC代码的开发
  • 简单好用、容易上手、具有更好的灵活性
  • 通过将SQL定义在XML中的方式降低程序的耦合度
  • 支持动态SQL,可以根据具体业务需要灵活实现功能

MyBatis

  • 相比于Hibernate,开发者需要完成更多的工作,比如定义SQL、设置POJO与数据的映射关系等
  • 要求开发人员具备一定的SQL编写能力,在一些特定场景下工作量比较大
  • 数据库移植性差,因为SQL依赖于底层数据库,如果要进行数据库迁移,部分SQL需要重新编写

MyBatis入门

创建Maven工程引入POM依赖

<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>5.1.46</version>
    </dependency>
</dependencies>

创建实体类

import lombok.Data;

@Data
public class People {
    private Integer id;
    private String name;
    private double money;
}

配置MyBatis环境,在resources路径下创建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>
    <!--配置MyBatis运行环境-->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"></transactionManager>
            <!--数据源-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://ip:端口/test?useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value=""/>
                <property name="password" value=""/>
            </dataSource>
        </environment>
    </environments>

</configuration>

MyBatis开发有两种方式

  • 使用原生接口
  • Mapper代理实现自定义接口

使用原生接口

创建Mapper文件PeopleMapper.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="org.example.mapper.PeopleMapper">
    <select id="findById" parameterType="java.lang.Integer" resultType="org.example.entity.People">
        select * from people where id = #{id}
    </select>

</mapper>

namespace通常设置为文件所在包名+文件名
parameterType是参数数据类型
resultType是返回值数据类型

在全局配置文件 config.xml中注册PeopleMapper.xml

    <mappers>
        <mapper resource="org/example/mapper/PeopleMapper.xml"></mapper>
    </mappers>

调用API完成操作


import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.example.entity.People;

import java.io.InputStream;

public class Test {
    public static void main(String[] args) {
        //加载MyBatis配置文件
        InputStream inputStream=Test.class.getClassLoader().getResourceAsStream("config.xml");
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder=new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory=sqlSessionFactoryBuilder.build(inputStream);
        //获取SqlSession
        SqlSession sqlSession=sqlSessionFactory.openSession();
        //调用MyBatis原生接口执行SQL语句
        String statement="org.example.mapper.PeopleMapper.findById";
        People people=sqlSession.selectOne(statement,1);
        System.out.println(people);
        sqlSession.close();
    }
}

IDEA中无法直接读取resources路径下的XML文件,需要进行设置在pom.xml中添加

    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>
    </build>

Mapper代理实现自定义接口

开发者只需要定义接口,并不需要实现接口,具体实现工作由Mapper代理结合配置文件完成。

自定义接口

import org.example.entity.People;

import java.util.List;

public interface PeopleRepository {
    public int save(People people);
    public int deleteById(Integer id);
    public int update(People people);
    public List<People> findAll();
}

创建PeopleMapper.xml,定义接口方法对应的SQL语句,statement标签根据SQL执行的业务可以选择select、insert、delete、update,MyBatis会自动根据规则创建PeopleRepository接口实现类代理对象。

规则如下

  • PeopleMapper.xml中的namespace为接口的全限定类名(带着包名的类名)
  • PeopleMapper.xml中statement的id为接口中对应的方法名
  • PeopleMapper.xml中的parameterType和接口中对应方法的参数类型一致
  • PeopleMapper.xml中的resultType和接口中方法返回值类型一致

配置PeopleRepository.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="org.example.repository.PeopleRepository">
    <insert id="save" parameterType="org.example.entity.People">
        insert into people(name,money) values(#{name},#{money})
    </insert>
    <delete id="deleteById" parameterType="java.lang.Integer">
        delete from people where id = #{id}
    </delete>
    <update id="update" parameterType="org.example.entity.People">
        update people set name = #{name},money=#{money} where id=#{id}
    </update>
    <select id="findById" parameterType="java.lang.Integer" resultType="org.example.entity.People">
        select * from people where id = #{id}
    </select>
    <select id="findAll" resultType="org.example.entity.People">
        select * from people
    </select>
</mapper>

完成注册,在config.xml中配置

<mappers>
    <mapper resource="org/example/repository/PeopleRepository.xml"></mapper>
</mappers>

配置接口

import org.example.entity.People;

import java.util.List;

public interface PeopleRepository {
    public int save(People people);
    public int deleteById(Integer id);
    public int update(People people);
    public People findById(Integer id);
    public List<People> findAll();
}

实现类

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

        PeopleRepository peopleRepository=sqlSession.getMapper(PeopleRepository.class);
       People people=new People();
        people.setName("小明");
        people.setMoney(Double.parseDouble("666"));
       peopleRepository.save(people);
        sqlSession.commit();
        List<People> people=peopleRepository.findAll();
        for(People people1:people)
        {
           System.out.println(people1);
        }
        sqlSession.close();
    }
}

Mapper.xml常用配置

MyBatis配置文件有两种:

  • 全局环境配置文件(数据源、事务管理、Mapper注册、打印SQL、惰性加载、二级缓存)
  • Mapper配置文件(定义自定义接口的具体实现方案:SQL、数据与POJO的映射)

多表关联查询包括一对一、一对多、多对多

单表查询

<select id="findById" parameterType="java.lang.Integer" resultType="org.example.entity.People">
        select * from people where id = #{id}
</select>

业务:通过id查询People对象
目标表:test/people
实体类: org.example.entity.People
Mapper.xml设置相关配置逻辑,由MyBatis自动完成查询,生成POJO
statement 标签主要属性有id、parameterType、ResultType
id对应接口的方法名
parameterType 定义参数的数据类型
resultType定义查询结果的数据类型(实体类的成员变量列表必须与目标表的字段列表一致)

parameterType

支持基本数据类型、包装类、String、多参数、POJO等

  1. 基本数据类型,通过id查询POJO

接口方法

 public People findById(int id);

xml

    <select id="findById" parameterType="int" resultType="org.example.entity.People">
        select * from people where id= #{id}
    </select>

2.包装类
接口方法

 public People findById(Integer id);

xml

    <select id="findById" parameterType="java.lang.Integer" resultType="org.example.entity.People">
        select * from people where id = #{id}
    </select>
  1. String类型
    public People findByName(String name);
    <select id="findByName" parameterType="java.lang.String" resultType="org.example.entity.People">
        select * from people where name=#{name}
    </select>
  1. 多参数
    public People findByIdAndName(Integer id,String name);
    <select id="findByIdAndName" resultType="org.example.entity.People">
        select * from people where id=#{param1} and name=#{param2}
    </select>

    </select>
    <select id="findByIdAndName" resultType="org.example.entity.People">
        select * from people where id=#{arg0} and name=#{arg1}
    </select>
  1. POJO
 public int update(People people);
    <update id="update" parameterType="org.example.entity.People">
        update people set name = #{name},money=#{money} where id=#{id}
    </update>

resultType

resultType与parameterType的使用基本一致

  1. 基本数据类型
    public int count();
    <select id="count" resultType="int">
        select count(*) from people
    </select>

2.包装类

    public Integer count();
    <select id="count" resultType="java.lang.Integer">
        select count(*) from people
    </select>
  1. String
  public String findNameById(Integer id);
    <select id="findNameById" parameterType="java.lang.Integer" resultType="java.lang.String">
        select name from people where id=#{id}
    </select>
  1. POJO
    public People findById(Integer id);
    <select id="findById" parameterType="java.lang.Integer" resultType="org.example.entity.People">
        select * from people where id = #{id}
    </select>

多表关联查询

实际开发中最常用的是:一对多和多对多

一对多

建表

CREATE TABLE t_classes(
id int(11) PRIMARY KEY auto_increment,
name VARCHAR(11) DEFAULT NULL);

CREATE TABLE t_student(
id INT PRIMARY KEY auto_increment,
name VARCHAR(11) DEFAULT NULL,
cid int(11) DEFAULT NULL,
CONSTRAINT t_student_ibfk_1 FOREIGN KEY (cid) REFERENCES t_classes(id)
);

内关联

SELECT s.id sid,s.`name` sname,c.id cid,c.`name` cname FROM test.t_student s,test.t_classes c WHERE s.id=1 AND s.cid=c.id

创建实体类

import lombok.Data;

@Data
public class Student {
    private Integer id;
    private String name;
    private Classes classes;
}
import lombok.Data;

@Data
public class Classes {
    private Integer id;
    private String name;
}

接口StudentRepository

import com.test.entity.Student;

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

StudentRepository.xml
resultType直接将结果集与实体类进行映射,结果集的字段名与实体类的成员变量名相等则映射。
resultMap可以对结果集进行二次封装,根据需求来完成结果集数据到实体类的映射。

<?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.test.Repository.StudentRepository">
    <resultMap id="studentMap" type="com.test.entity.Student">
        <id column="sid" property="id"/>
        <result column="sname" property="name"/>
        <association property="classes" javaType="com.test.entity.Classes">
            <id property="id" column="cid"/>
            <result property="name" column="cname"/>
        </association>
    </resultMap>
    <select id="findById" parameterType="java.lang.Integer" resultMap="studentMap">
        SELECT s.id sid,s.`name` sname,c.id cid,c.`name` cname FROM test.t_student s,test.t_classes c WHERE s.id=1 AND s.cid=c.id
    </select>
</mapper>

调用

import com.test.Repository.StudentRepository;
import com.test.entity.Student;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.InputStream;

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

        StudentRepository studentRepository=sqlSession.getMapper(StudentRepository.class);
        Student student=studentRepository.findById(1);
        System.out.println(student);

    }
}

查询

SELECT c.id cid,c.name cname,s.id sid,s.name sname FROM test.t_classes c,test.t_student s WHERE c.id=1 AND c.id=c.cid

接口

import com.test.entity.Classes;

public interface ClassesRepository {
    public Classes findById(Integer id);
}

ClassRepository.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.test.Repository.ClassesRepository">
    <resultMap id="classesMap" type="com.test.entity.Classes">
        <id property="id" column="cid"/>
        <result property="name" column="cname"/>
        <collection property="students" ofType="com.test.entity.Student">
            <id property="id" column="sid"/>
            <result property="name" column="sname"/>
        </collection>
    </resultMap>
<select id="findById" parameterType="java.lang.Integer" resultMap="classesMap">
    SELECT c.id cid,c.name cname,s.id sid,s.name sname FROM test.t_classes c,test.t_student s WHERE c.id=1 AND c.id=s.id
</select>
</mapper>

conllection和association的区别

conllection是将结果集封装成一个集合对象(多个目标对象)
association是将结果集封装成一个实体类的对象(一个目标对象)
collection是通过ofType设置数据类型,association是通过javaType设置数据类型。

多对多

多对多是双向的一对多关系

建表

CREATE TABLE t_account(
id int(11) NOT NULL PRIMARY KEY auto_increment,
name VARCHAR(11) default null
);
create table t_course(
id int(11) NOT NULL PRIMARY KEY auto_increment,
name varchar(11) DEFAULT null
);
CREATE TABLE account_course(
id int(11) NOT NULL PRIMARY KEY auto_increment,
aid int(11) DEFAULT null,
cid int(11) DEFAULT null,
CONSTRAINT account_course_ibfk_1 FOREIGN KEY (aid) REFERENCES t_account(id),
CONSTRAINT account_course_ibfk_2 FOREIGN KEY (cid) REFERENCES t_course(id)
);

实体类

import lombok.Data;

import java.util.List;

@Data
public class Account {
    private Integer id;
    private String name;
    private List<Course> courses;
}
import lombok.Data;

import java.util.List;

@Data
public class Course {
    private Integer id;
    private String name;
    private List<Account> accounts;
}

AccountRepository

import org.example.entity.Account;

public interface AccountRepository {
    public Account findById(Integer id);
}

AccountRepository.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="org.example.repository.AccountRepository">

    <resultMap id="accountMap" type="org.example.entity.Account">
        <id column="aid" property="id"/>
        <result column="aname" property="name"/>
        <collection property="courses" ofType="org.example.entity.Course">
            <id column="cid" property="id"/>
            <result column="cname" property="name"/>
        </collection>
    </resultMap>

    <select id="findById" parameterType="java.lang.Integer" resultMap="accountMap">
        SELECT a.id aid,a.name aname,c.id cid,c.name cname FROM t_account a,account_course ac,t_course c WHERE a.id=1 AND a.id=ac.aid AND c.id=ac.cid;
    </select>
</mapper>

config.xml

<mappers>
 <mapper resource="org/example/repository/AccountRepository.xml"></mapper>
</mappers>

调用

    public static void main(String[] args) {
        InputStream inputStream=Test2.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.close();
    }

CourseRepository

import org.example.entity.Course;

public interface CourseRepository {
    public Course findById(Integer id);
}

CourseRepository.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="org.example.repository.CourseRepository">
    <resultMap id="CourseMap" type="org.example.entity.Course">
        <id column="cid" property="id"/>
        <result column="cname" property="name"/>
        <collection property="accounts" ofType="org.example.entity.Account">
            <id column="aid" property="id"/>
            <result column="aname" property="name"/>
        </collection>
    </resultMap>

    <select id="findById" parameterType="java.lang.Integer" resultMap="CourseMap">
        SELECT a.id aid,a.name aname,c.id cid,c.name cname FROM t_account a,account_course ac,t_course c WHERE c.id=#{id} AND a.id=ac.aid AND c.id=ac.cid;
    </select>
</mapper>

MyBatis逆向工程

MyBatis是半自动化的ORM框架,SQL需要开发者自定义,SQL需要单独定义在Mapper.xml中,与Mapper接口对应,使用MyBatis进行开发的基本配置:

  • 实体类
  • Mapper接口
  • Mapper.xml

这种方法的缺陷是如果参与业务的表太多,每张表的业务都需要自定义SQL、创建实体类、Mapper接口,工作量较大。

MyBatis框架可以自动根据数据表帮助开发者生成实体类、Mapper接口及Mapper.xml,这就是逆向工程。

逆向工程概念

逆向工程是MyBatis提供的一种自动化配置方案,针对数据表自动生成MyBatis所需要的各种资源(实体类、Mapper接口、Mapper.xml),但是逆向工程只针对于单表,如果数据表之间有级联关系逆向工程无法自动生成级联关系。

使用逆向工程

MyBatis逆向工程组件是MyBatis Generator,简称MBG,是专为MyBatis框架制定代码自动生成解决方案,MBG可以根据数据表结构快速生成对应的实体类、Mapper接口、Mapper.xml,并且支持基本的CRUD操作,但是业务逻辑相对复杂的操作就需要开发者手动完成。

创建Maven工程,pom.xml添加相关依赖

<dependencies>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.6</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.46</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis.generator</groupId>
        <artifactId>mybatis-generator-core</artifactId>
        <version>1.4.1</version>
    </dependency>
</dependencies>

创建目标表

CREATE TABLE t_account(
id INT(11) NOT NULL PRIMARY KEY auto_increment,
name varchar(11),
password VARCHAR(11),
age int(11));

创建MBG配置文件generatorConfig.xml

  • jdbcConnection配置数据库连接信息
  • javaModelGenerator配置JavaBean的生成策略
  • sqlMapGenerator配置SQL映射文件生成策略
  • javaClientGenerator配置Mapper接口的生成策略
  • table配置要逆向解析的数据表(tableName:表名,domainObjectName:实体类名)

generatorConfig.xml

<?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">
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://ip:3306/test?"
                        userId="username"
                        password="password">
        </jdbcConnection>

        <javaModelGenerator targetPackage="org.example.entity" targetProject="./src/main/java"></javaModelGenerator>
        <sqlMapGenerator targetPackage="org.example.repository" targetProject="./src/main/java"></sqlMapGenerator>
        <javaClientGenerator type="XMLMAPPER" targetPackage="org.example.repository" targetProject="./src/main/java"></javaClientGenerator>
        <table tableName="t_account" domainObjectName="Account"></table>
    </context>
</generatorConfiguration>

创建GeneratorMain类,执行自动生成资源的代码

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

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class GeneratorMain {
    public static void main(String[] args) {
        List<String> warnings=new ArrayList<String>();
        boolean overwrite=true;
        String genCig="/generatorConfig.xml";
        File configFile=new File(GeneratorMain.class.getResource(genCig).getFile());
        ConfigurationParser configurationParser=new ConfigurationParser(warnings);
        Configuration configuration=null;
        try{
            configuration=configurationParser.parseConfiguration(configFile);
        }
        catch (Exception e){e.printStackTrace();}
        DefaultShellCallback callback=new DefaultShellCallback(overwrite);
        MyBatisGenerator myBatisGenerator=null;
        try{
            myBatisGenerator=new MyBatisGenerator(configuration,callback,warnings);
        }catch (Exception e){e.printStackTrace();}
        try{
            myBatisGenerator.generate(null);
        }catch (Exception e){e.printStackTrace();}
    }
}

MyBatis延迟加载

在中添加

    <settings>
        <!--打印SQL-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        <!--延迟加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
    </settings>

可以显示执行的SQL语句,并延迟加载

建表

表orders

CREATE TABLE orders (
id INTEGER PRIMARY KEY auto_increment,
name VARCHAR(11),
cid INTEGER);

表customer

CREATE TABLE customer(
id INTEGER PRIMARY KEY auto_increment,
name VARCHAR(11)
);

创建实体类

Customer

import lombok.Data;

import java.util.List;

@Data
public class Customer {
    private Integer id;
    private String name;
    List<Order> orders;
}

Order

import lombok.Data;

@Data
public class Order {
    private Integer id;
    private String name;
    private Customer customer;
}

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>
    <settings>
        <!--打印SQL-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        <!--延迟加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
    </settings>

    <!--配置MyBatis运行环境-->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"></transactionManager>
            <!--数据源-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://ip/test?useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="username"/>
                <property name="password" value="password"/>
            </dataSource>
        </environment>
    </environments>
<mappers>
    <mapper resource="com/example/repository/OrderRepository.xml"/>
    <mapper resource="com/example/repository/CustomerRepository.xml"/>
</mappers>
</configuration>

CustomerRepository接口

import com.example.entity.Customer;

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

OrderRepository接口

import com.example.entity.Order;

public interface OrderRepository {
    public Order findById(Integer 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.example.repository.CustomerRepository">
    <select id="findById" parameterType="java.lang.Integer" resultType="com.example.entity.Customer">
        select * from customer where id = #{id}
    </select>
</mapper>

OrderRepository.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.example.repository.OrderRepository">

    <resultMap id="orderMap" type="com.example.entity.Order">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <association property="customer"
                     javaType="com.example.entity.Customer"
                     select="com.example.repository.CustomerRepository.findById"
                     column="cid"
        ></association>
    </resultMap>

    <select id="findById" parameterType="java.lang.Integer" resultMap="orderMap">
        select * from orders where id = #{id}
    </select>
</mapper>

运行

import com.example.entity.Order;
import com.example.repository.OrderRepository;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.InputStream;

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

        OrderRepository orderRepository=sqlSession.getMapper(OrderRepository.class);
        Order order= orderRepository.findById(1);
        System.out.println(order.getName());
        sqlSession.close();
    }
}

MyBatis延迟加载机制,是实际开发中使用频率较高的一个功能,正确的使用延迟加载,可以有效减少Java Application和数据库的交互次数,从而提高整个系统的运行效率,延迟加载是为了提高程序运行效率的一种手段,一般应用于多表关联查询的业务场景。

MyBatis缓存

使用缓存的作用也是为了减少Java Application与数据库的交互次数,从而提升程序的运行效率。

MyBatis有两种缓存:一级缓存和二级缓存

一级缓存

MyBatis自带一级缓存,并且是无法关闭的,一直存在,一级缓存的数据存储在SqlSession中。

即使用同一个SqlSession进行查询操作的时候,一级缓存存在,如果使用多个SqlSession进行查询操作,一级缓存不存在,缓存只针对于查询,但是如果SqlSession执行了增、删、改操作,MyBatis会自动清空SqlSession缓存中的数据,以此来保证数据的一致性。
一级缓存不需要进行任何配置,直接使用即可。

二级缓存

MyBatis二级缓存是比一级缓存作用域更大的缓存机制,它是Mapper级别的,只要是同一个Mapper无论使用多少个SqlSession,数据都是共享的。

MyBatis二级缓存默认是关闭的,需要使用时可以通过配置手动开启

实体类

import lombok.Data;

@Data
public class MyClass {
    private Integer id;
    private String name;
}

Mapper接口

import com.example.entity.MyClass;

public interface MyClassRepository {
    public MyClass findById(Integer id);
}

Mapper.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.example.repository.MyClassRepository">
    <select id="findById" parameterType="java.lang.Integer" resultType="com.example.entity.MyClass">
        select * from t_classes where id = #{id}
    </select>
</mapper>

测试

import com.example.entity.MyClass;
import com.example.repository.MyClassRepository;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.InputStream;

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


        MyClassRepository myClassRepository=sqlSession.getMapper(MyClassRepository.class);
        MyClass myClass=myClassRepository.findById(1);
        System.out.println(myClass);
        MyClass myClass2=myClassRepository.findById(1);
        System.out.println(myClass2);
        sqlSession.close();
    }
}

触发一级缓存,只查询一次数据库。

MyBatis可以使用自带的二级缓存,也可以使用第三方ehcache二级缓存

自带二级缓存
config.xml中配置开启二级缓存

<settings>
        <!--开启二级缓存-->
        <setting name="cacheEnabled" value="true"/>
</settings>

在Mapper.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.example.repository.MyClassRepository">
    <cache></cache>
    <select id="findById" parameterType="java.lang.Integer" resultType="com.example.entity.MyClass">
        select * from t_classes where id = #{id}
    </select>
</mapper>

实体类实现Serializable接口

import lombok.Data;

import java.io.Serializable;

@Data
public class MyClass implements Serializable {
    private Integer id;
    private String name;
}

调用

import com.example.entity.MyClass;

import com.example.repository.MyClassRepository;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.InputStream;

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

        MyClassRepository myClassRepository=sqlSession.getMapper(MyClassRepository.class);
        MyClass myClass=myClassRepository.findById(1);
        System.out.println(myClass);

        sqlSession=sqlSessionFactory.openSession();
        myClassRepository=sqlSession.getMapper(MyClassRepository.class);
        MyClass myClass3=myClassRepository.findById(1);
        System.out.println(myClass3);
        sqlSession.close();
    }

第三方ehcache二级缓存

pom.xml

    <!--ehcache-->
    <dependency>
        <groupId>net.sf.ehcache</groupId>
        <artifactId>ehcache-core</artifactId>
        <version>2.4.3</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-ehcache</artifactId>
        <version>1.0.0</version>
    </dependency>

resources路径下创建ehcache.xml

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
    <diskStore/>
    <defaultCache
        maxElementsInMemory="1000"
        maxElementsOnDisk="10000000"
        eternal="false"
        overflowToDisk="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        diskExpiryThreadIntervalSeconds="120"
        memoryStoreEvictionPolicy="LRU"></defaultCache>
</ehcache>

config.xml中配置二级缓存

        <!--开启二级缓存-->
        <setting name="cacheEnabled" value="true"/>

Mapper.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.example.repository.MyClassRepository">
    <cache type="org.mybatis.caches.ehcache.EhcacheCache">
        <!--缓存创建后,最后一次访问缓存的时间至失效的时间间隔-->
        <property name="timeToIdleSeconds" value="3600"/>
        <!--缓存自创建时间起至失效的时间间隔-->
        <property name="timeToLiveSeconds" value="3600"/>
        <!--缓存回收策略,LRU移除近期最少使用的对象-->
        <property name="memoryStoreEvictionPolicy" value="LRU"/>
    </cache>
    <select id="findById" parameterType="java.lang.Integer" resultType="com.example.entity.MyClass">
        select * from t_classes where id = #{id}
    </select>
</mapper>

实体类不需要实现序列化接口

MyBatis动态SQL

实体类

public class User{
    private Integer id;
    private String username;
    private String password;
    private Integer age;
}
  • 通过id和username查询User
  • 通过username和password查询User
  • 通过password和age查询User

UserRepository.xml

<select id="findByUser1" parameterType="User" resultType="User">
    select * from t_user where id =#{id} and username=#{username}
</select>
<select id="findByUser2" parameterType="User" resultType="User">
    select * from t_user where username=#{username} and password=#{password}
</select>
<select id="findByUser3" parameterType="User" resultType="User">
    select * from t_user where password=#{password} and age=#{age}
</select>

MyBatis动态SQL,SQL不是固定的,可以根据不同的参数信息来动态拼接不同的SQL,以适应不同的需求。

实体类

import lombok.Data;

@Data
public class User {
    private Integer id;
    private String username;
    private String password;
    private Integer age;
}

Mapper.java

import com.example.entity.User;

public interface UserRepository {
    public User findByUser(User user);
}
  • if
  • where
  • choose、when

Mapper.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.example.repository.UserRepository">
    <select id="findByUser" parameterType="com.example.entity.User" resultType="com.example.entity.User">
        select * from t_user
        <where>
            <if test="id!=null">
                id=#{id}
            </if>
            <if test="username!=null">
                and username = #{username}
            </if>
            <if test="password!=null">
                and password = #{password}
            </if>
            <if test="age!=null">
                and age = #{age}
            </if>
        </where>
    </select>
</mapper>

用choose、when

<?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.example.repository.UserRepository">
    <select id="findByUser" parameterType="com.example.entity.User" resultType="com.example.entity.User">
        select * from t_user
        <where>
            <choose>
                <when test="id!=null">
                    id=#{id}
                </when>
                <when test="username!=null">
                    and username = #{username}
                </when>
                <when test="password!=null">
                    and password = #{password}
                </when>
                <when test="age!=null">
                    and age = #{age}
                </when>
            </choose>
        </where>
    </select>
</mapper>
  • trim

通过设置prefix和suffix参数来完成使用的

<?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.example.repository.UserRepository">
    <select id="findByUser" parameterType="com.example.entity.User" resultType="com.example.entity.User">
        select * from t_user
        <trim prefix="where" prefixOverrides="and">
            <if test="id!=null">
                id=#{id}
            </if>
            <if test="username!=null">
                and username = #{username}
            </if>
            <if test="password!=null">
                and password = #{password}
            </if>
            <if test="age!=null">
                and age = #{age}
            </if>
        </trim>
    </select>
</mapper>

  • set

set标签用于Update操作,会自动根据参数生成SQL语句

Mapper.java

import com.example.entity.User;

public interface UserRepository {
    public int update(User users);
}

Mapper.xml

    <update id="update" parameterType="com.example.entity.User">
        update t_user
        <set>
            <if test="username!=null">
                username = #{username},
            </if>
            <if test="password!=null">
                password = #{password},
            </if>
            <if test="age!=null">
                age = #{age}
            </if>
        </set>
            where id = #{id}
    </update>

调用

import com.example.entity.User;

import com.example.repository.UserRepository;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.InputStream;

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

        UserRepository userRepository=sqlSession.getMapper(UserRepository.class);
        User user=new User();
        user.setId(1);
        user.setUsername("tom");
        user.setAge(3);
        userRepository.update(user);
        sqlSession.commit();
        sqlSession.close();
    }
}

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码

)">
< <上一篇
下一篇>>