Mybatis学习笔记,包含mybatis基本使用、关系映射、动态SQL、分页插件等等

创作不易,各位看官点赞收藏.

文章目录

  • MyBatis 学习笔记
    • 1、Mybatis Demo 程序
    • 2、Mybatis 核心配置文件
    • 3、Mybatis Mapper 传参映射
    • 4、Mybatis 查询结果
    • 5、Mybatis 关系映射处理
      • 5.1、多对一关系映射处理
      • 5.2、一对多关系映射处理
    • 6、Mybatis 动态 SQL
    • 7、Mybatis 缓存
    • 8、Mybatis 分页插件

MyBatis 学习笔记

简介:MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。简单来说,mybatis就是用来操作数据库的,可以使程序猿更加容易书写 dao 层。

1、Mybatis Demo 程序

搭建环境:导入依赖、创建数据库表user(id,name,address)


<dependency>
    <groupId>junitgroupId>
    <artifactId>junitartifactId>
    <version>4.11version>
dependency>

<dependency>
    <groupId>org.mybatisgroupId>
    <artifactId>mybatisartifactId>
    <version>3.4.6version>
dependency>

<dependency>
    <groupId>mysqlgroupId>
    <artifactId>mysql-connector-javaartifactId>
    <version>8.0.21version>
dependency>

<dependency>
    <groupId>log4jgroupId>
    <artifactId>log4jartifactId>
    <version>1.2.12version>
dependency>

编写配置文件:mybatis-config.xml,XML 配置文件中包含了对 MyBatis 系统的核心设置,包括获取数据库连接实例的数据源(DataSource)以及决定事务作用域和控制方式的事务管理器(TransactionManager)。


DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
    
    
    <environments default="mysql">
        
        <environment id="mysql">
            
            <transactionManager type="JDBC"/>
            
            
            <dataSource type="POOLED">
                
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///mybatis?characterEncoding=utf-8&serverTimezone=UTC"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            dataSource>
        environment>
    environments>
    
    <mappers>
        <mapper resource="mapper/UserMapper.xml"/>
    mappers>
configuration>

编写 Mapper 接口:

public interface UserMapper {
    // 查询所有的用户
    List<User> findAllUser();
}

编写 mapper.xml:


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.jx.app.mybatis.mapper.UserMapper">
    
    <select id="findAllUser" resultType="com.jx.app.mybatis.entity.User">
        select * from user
    select>
mapper>

编写 Mybatis 工具类:

public class MybatisUtils {
    // 成员变量
    private static SqlSessionFactory sqlSessionFactory;
    // 静态代码初始化
    static {
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    // 获取sqlSession
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
}

测试查询结果:

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

2、Mybatis 核心配置文件

environments:配置数据库连接配置环境。


<environments default="mysql">
    
    <environment id="mysql">
        
        <transactionManager type="JDBC"/>
        
        
        <dataSource type="POOLED">
            
            <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql:///mybatis?characterEncoding=utf-8&serverTimezone=UTC"/>
            <property name="username" value="root"/>
            <property name="password" value="123456"/>
        dataSource>
    environment>
environments>

propertes:可以引入 properties 文件,然后通过某种方式去访问文件中的值。

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql:///mybatis?characterEncoding=utf-8&serverTimezone=UTC
username=root
password=123456

<properties resource="jdbc.properties"/>

settings:Mybatis 的全局配置,还有很多配置,可以去官网上查看。

<settings>
    
    <setting name="mapUnderscoreToCamelCase" value="true"/>
    
    <setting name="logImpl" value="STDOUT_LOGGING"/>
settings>

typeAliases:取别名标签,给实体类取一个别名,在映射结果时就可以使用别名就不再使用全限定类名。

<typeAliases>
    
    <typeAlias type="com.jx.app.mybatis.entity.User" alias="User"/>
    
    
    <package name="com.jx.app.mybatis.entity"/>
typeAliases>

mappers:引入 mapper 映射文件。


<mappers>
    
    <mapper resource="mapper/UserMapper.xml"/>

    
    <package name="com.jx.app.mybatis.mapper"/>
mappers>

3、Mybatis Mapper 传参映射

​ 在 mapper 映射文件获取接口的参数有两种方式,${}#{}

  • ${}: 本质是字符串拼接,将参数与 SQL 语句进行简单拼接,这种方式可能存在 SQL 注入问题,使用这种方式需要注意字符串的单引号拼接。
  • #{}:本质是占位符方式来拼接 SQL,自动给参数加上单引号,这种方式防止 SQL 注入问题。

单个字面量参数:

// 参数 name 是单个字面量
User getUserByName(String name);
<select id="getUserByName" resultType="com.jx.app.mybatis.entity.User">
    SELECT *
    FROM user u
    WHERE u.user_name = #{name} 
    
select>

多个字面量参数:

// 存在多个参数
User getUser(String id, String name);

<select id="getUser" resultType="com.jx.app.mybatis.entity.User">
    SELECT *
    FROM user u
    
    WHERE u.id = #{param1} AND u.user_name = #{param2}
select>

map 传参:

// 参数是一个map
User getUserByMap(Map<String,String> map);

<select id="getUserByMap" resultType="com.jx.app.mybatis.entity.User">
    SELECT *
    FROM user u
    WHERE u.id = #{id} AND u.user_name = #{username}
select>

实体类传参:

// 参数是一个是实体类
int insert(User user);

<insert id="insert">
    INSERT INTO user values(null,#{userName},#{password},#{money})
insert>

@param 注解:可以命名参数,标识参数后依然后把参数放入 map 中,可以通过命名参数的 key 来获取参数值。

// @Param 将参数进行取别名命名
User getUser(@Param("id") String id, @Param("name") String name);

<select id="getUser" resultType="com.jx.app.mybatis.entity.User">
    SELECT *
    FROM user u
    WHERE u.id = #{id} AND u.user_name = #{name}
select>

4、Mybatis 查询结果

查询结果为实体对象:

// 接口返回值为实体对象
User getUserByName(String name);

<select id="getUserByName" resultType="com.jx.app.mybatis.entity.User">
    SELECT *
    FROM user u
    WHERE u.user_name = #{name}
select>

注意:返回值是一个实体类对象时,返回结果只能是一条数据或者 null,如果查询出来是多条数据就会报错。

查询结果为集合:

// 接口返回值为集合类型,并指定对应泛型
List<User> getUserByName(@Param("name") String name);
<!-- resultType:需要指定集合中泛型对应类的全限定类名或者别名-->
<select id="getUserByName" resultType="com.jx.app.mybatis.entity.User">
    SELECT * FROM user u
</select>

注意:如果查询出来一条或多条结果就会封装到集合中,如果没有结果就会返回空集合但是不会返回 null。

查询结果为 map 集合:

// 接口返回值是map类型
Map<String,Object> getUserToMap();

<select id="getUserToMap" resultType="java.util.Map">
    SELECT * FROM user u
select>

注意:查询结果为 map 只能查询一条数据,查询出多条就会报错,而且如果某个字段是 null,这个字段不会封装到 map 中。

多条结果封装成 map:

/**
 * 如果查询多条数据也想封装成 map,@MapKey 可以指定查询出来那个字段可以作为 key,
 * 然后这一条数据又会封装成一个 map 作为 value 存储进去
*/
@MapKey("id")
Map<String, Map<String,Object>> getUserToMap();

获取自增主键:在插入数据时,可以获取插入数据后对应的自动递增的 id。

// 插入元素
int insert(User user);

<insert id="insert" useGeneratedKeys="true" keyProperty="id">
    INSERT INTO user values(null,#{userName},#{password},#{money})
insert>

resultMap 字段关系映射:查询出来的结果与实体类上的字段名称不一致,我们就需要通过 resultMap 属性去自定义映射关系。

方式一:字段起别名,可以在 SQL 语句中把字段名通过起别名方式与属性名一一对应。

方式二:使用 resultMap 映射,将查询出来字段名与对象属性名进行一个自定义映射。


<select id="getUserList" resultMap="UserListMap">
    SELECT * FROM user u
select>



<resultMap id="UserListMap" type="com.jx.app.mybatis.entity.User">
    <id column="id" property="id"/>
    <result column="user_name" property="userName"/>
    <result column="password" property="password"/>
    <result column="money" property="money"/>
resultMap>

注意:如果查询出来字段名与属性名对应不上,不会报错,只是他们对应属性值都是对象默认值。

5、Mybatis 关系映射处理

两个实体:Student 和 Teacher,一个学生有一个老师,一个老师有多个学生。

@Data
public class Student {
    private String id;
    private String studentName;
    private Teacher teacher;
}
@Data
public class Teacher {
    private String id;
    private String teacherName;
    private List<Student> students;
}

5.1、多对一关系映射处理

方式一:使用连接查询查询对学生对应的老师信息,然后使用级联属性映射。


<select id="getStudentById" resultMap="StudentMap">
    SELECT * FROM student s
    LEFT JOIN teacher t ON s.t_id = t.id
    WHERE s.id = #{id}
select>


<resultMap id="StudentMap" type="com.jx.app.mybatis.entity.Student">
    <id column="id" property="id"/>
    <result column="student_name" property="studentName"/>
    <result column="t_id" property="teacher.id"/>
    <result column="teacher_name" property="teacher.teacherName"/>
resultMap>

方式二:使用连接查询查询对学生对应的老师信息,然后通过 resultMap 进行关系映射。


<select id="getStudentById" resultMap="StudentMap">
    SELECT * FROM student s
    LEFT JOIN teacher t ON s.t_id = t.id
    WHERE s.id = #{id}
select>


<resultMap id="StudentMap" type="com.jx.app.mybatis.entity.Student">
    <id column="id" property="id"/>
    <result column="student_name" property="studentName"/>
    
    <association property="teacher" javaType="com.jx.app.mybatis.entity.Teacher">
        <id column="t_id" property="id"/>
        <result column="teacher_name" property="teacherName"/>
    association>
resultMap>

方式三:通过子查询去查询老师信息,然后通过 resultMap 进行关系映射。


<select id="getStudentById" resultMap="StudentMap">
    SELECT * from student WHERE id = #{id}
select>

<resultMap id="StudentMap" type="com.jx.app.mybatis.entity.Student">
    <id property="id" column="id"/>
    <result property="studentName" column="student_name"/>
    
    <association property="teacher" select="com.jx.app.mybatis.mapper.UserMapper.getTeacher" column="t_id"/>
resultMap>


<select id="getTeacher" resultType="com.jx.app.mybatis.entity.Teacher">
    SELECT * from teacher where id = #{t_id}
select>

注意:子查询有一个好处就是可以设置关联对象的延迟加载,只有在使用到延迟对象时才会去执行对应的子查询 SQL 语句然后返回结果。

  • 需要开启 mybatis 的全局懒加载设置,
  • association 有一个 fetchType 属性手动控制懒加载,值有 lazy(懒加载)、eager(立即加载),如果不设置这个属性默认是懒加载。

5.2、一对多关系映射处理

方式一:通过连接查询出老师对应的所有学生信息,然后通过 resultMap 进行关系映射。


<select id="getTeacherById" resultMap="TeacherMap">
    SELECT * FROM teacher t
    LEFT JOIN student s ON t.id = s.t_id
    WHERE t.id = #{id}
select>

<resultMap id="TeacherMap" type="com.jx.app.mybatis.entity.Teacher">
    <id property="id" column="id"/>
    <result property="teacherName" column="teacher_name"/>
     
    <collection property="students" ofType="com.jx.app.mybatis.entity.Student">
        <id property="id" column="s_id"/>
        <result property="studentName" column="student_name"/>
    collection>
resultMap>

方式二:分步查询老师信息和学生信息,然后通过 resultMap 映射关联。

<select id="getTeacherById" resultMap="TeacherMap">
    SELECT * FROM teacher t
    WHERE t.id = #{id}
select>

<resultMap id="TeacherMap" type="com.jx.app.mybatis.entity.Teacher">
    <id property="id" column="id"/>
    <result property="teacherName" column="teacher_name"/>
    
    <collection property="students" ofType="com.jx.app.mybatis.entity.Student"
            select="com.jx.app.mybatis.mapper.UserMapper.getStudent"
            column="id">
    collection>
resultMap>

<select id="getStudent" resultType="com.jx.app.mybatis.entity.Student">
    select * from student where t_id = #{tid}
select> 

6、Mybatis 动态 SQL

​ 根根据特定的条件动态拼接 SQL 语句的功能,它就是解决在拼接 SQL 时字符串问题。

if 标签:会根据标签的 test 属性对应表达式返回 true 或者 false 决定是否拼接到 SQL 语句中。

// 使用 if 进行多条件查询
List<User> DynamicSQL(User user);
<select id="DynamicSQL" resultType="com.jx.app.mybatis.entity.User">
    select * from user 
    where 1=1
    
    <if test="userName != null and userName != ''">
        and user_name = #{userName}
    if>
    <if test="money != null and money != ''">
        and money = #{money}
    if>
select>

where 标签:动态生成 where 条件语句,根据拼接 SQL 在前面添加或去掉 and、or 关键字,如果没有条件就不会有 where 关键字。

<select id="DynamicSQL" resultType="com.jx.app.mybatis.entity.User">
    select * from user
    
    <where>
        
        <if test="userName != null and userName != ''">
            and user_name = #{userName}
        if>
        <if test="money != null and money != ''">
            or money = #{money}
        if>
    where>
select>

trim 标签:如果拼接 SQL 字符串有内容可以在内容前后添加内容,如果没有内容也没有任何效果。

<select id="DynamicSQL" resultType="com.jx.app.mybatis.entity.User">
    select * from user
    
    <trim prefix="where" suffix="" prefixOverrides="and|or" suffixOverrides="">
            <if test="userName != null and userName != ''">
                and user_name = #{userName}
            if>
            <if test="money != null and money != ''">
                or money = #{money}
            if>
    trim>
select>

chose…when…otherwise 标签:相当于 if…eles if…else,指定条件选择一个进行执行,其它内容不执行。

<select id="DynamicSQL" resultType="com.jx.app.mybatis.entity.User">
    select * from user
    <where>
        
        <choose>
            <when test="userName != null and userName != ''">
                user_name = #{userName}
            when>
            <when test="money != null and money != ''">
                money = #{money}
            when>
            <otherwise>
                id = #{id}
            otherwise>
        choose>
    where>
select>

注意:这个条件选择执行只会满足一个,要么是 when 中的一个要么就是 otherwise。

foreach 标签:如果参数是集合类型,可以通过标签遍历集合中内容,例如进行批量删除、增加等操作。

// 批量删除
int deleteBatch(@Param("ids") List<String> ids);
<delete id="deleteBatch">
    delete from user
    <where>
        id in
        
        <foreach collection="ids" item="id" close=")" open="(" separator="," index="i">
            #{id}
        foreach>
    where>
delete>

sql 标签:对常用的 SQL 语句进行一个抽取,如果在其它地方使用直接引用。


<sql id="CommonSQL">
    id,user_name,password,money
sql>


<select id="selectAll" resultType="com.jx.app.mybatis.entity.User">
    select <include refid="CommonSQL"/> from user
select>

7、Mybatis 缓存

一级缓存:这个级别缓存是 SqlSession 级别的缓存,通过同一个 SqlSession 对象去查询数据,那么在第二次查询就会去缓存中获取而不会去查询数据库,这种缓存是默认开启的。

@Test
public void test4(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    UserMapper userMapper1 = sqlSession.getMapper(UserMapper.class);
    List<User> allUser1 = userMapper1.findAllUser();
    System.out.println(allUser1);

    // 即使是不同 mapper 对象,但是是同一个 sqlSession,那么第二次就会去缓存中取数据
    UserMapper userMapper2 = sqlSession.getMapper(UserMapper.class);
    List<User> allUser2 = userMapper2.findAllUser();
    System.out.println(allUser2);
}

一级缓存失效:

  • 使用不同的 SqlSession 进行查询数据。
  • 同一个 SqlSession 但是查询条件不同。
  • 同一个 SqlSession 的两次查询之间执行了其它的增、删、改等操作。
  • 同一个 SqlSession 的两次查询之间手动清空了缓存。
// 手动清空缓存
sqlSession.clearCache();

二级缓存:二级缓存是 SqlSessionFactory 级别的缓存,通过同一个 SqlSessionFactory 创建的 SqlSession 去查询结果会被缓存,那么第二次去执行相同查询就会去缓存中查询,二级缓存需要手动开启。

  • 需要在 mybatis 核心配置文件中开启缓存。
<settings>
    
    <setting name="cacheEnabled" value="true"/>
settings>
  • 在 mapper 映射文件中开启缓存。

<cache />
@Test
public void test5(){
    SqlSession sqlSession1 = MybatisUtils.getSqlSession();
    SqlSession sqlSession2 = MybatisUtils.getSqlSession();

    UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
    List<User> users1 = mapper1.selectAll();
    System.out.println(users1);
    sqlSession1.commit();

    // 同一个 SqlSessionFactory 获取的不同 SqlSession 查询结果会被缓存
    UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
    List<User> users2 = mapper2.selectAll();
    System.out.println(users2);
}

注意事项:

  • 必须是同一个 SqlSessionFactory 的 SqlSession 的二级缓存才会生效。
  • 只有每一个将 SqlSession 查询后提交或者关闭,数据才会被缓存。
  • 查询的结果对象必须实现序列化,不然使用缓存会报错。
  • 两次相同查询之间,执行了增、删、改操作,一级缓存、二级缓存都会失效。

Mybatis学习笔记,包含mybatis基本使用、关系映射、动态SQL、分页插件等等_第1张图片

二级缓存相关设置:在 mapper 映射文件中的 cache 标签可以设置以下属性。


<cache eviction="LRU" flushInterval="1000" size="10" readOnly="false"/>

Mybatis 缓存查询顺序:

  • 先查询二级缓存,二级缓存的范围比一级缓存大一些。
  • 如果二级缓存没有命中就回去查询一级缓存。
  • 如果一级缓存也没有命中,就会去查询数据库。
  • SqlSession 关闭后,会将一级缓存的数据写入二级缓存。

第三方缓存工具 EHCache:

  • 导入依赖:

<dependency>
    <groupId>org.mybatis.cachesgroupId>
    <artifactId>mybatis-ehcacheartifactId>
    <version>1.2.1version>
dependency>
  • 编写 ehcache 配置文件:

<ehcache
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
        updateCheck="false">
    
    <diskStore path="E:\ehcache"/>
    <defaultCache
            eternal="false"
            maxElementsInMemory="10000"
            overflowToDisk="true"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="259200"
            memoryStoreEvictionPolicy="LRU"/>
    <cache
            name="cloud_user"
            eternal="false"
            maxElementsInMemory="5000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="1800"
            memoryStoreEvictionPolicy="LRU"/>
    
ehcache>
  • 使用三方缓存工具:在 mapper 映射文件中修改。

<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

8、Mybatis 分页插件

导入依赖:

<dependency>
    <groupId>com.github.pagehelpergroupId>
    <artifactId>pagehelperartifactId>
    <version>5.3.3version>
dependency>

设置 mybatis 插件:

<plugins>
    
    <plugin interceptor="com.github.pagehelper.PageInterceptor"/>
plugins>

使用方式:

@Test
public void test6(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);

    // 开启分页,在下一个查询语句会进行分页拦截,参数一:页码,参数二:一页数量
    PageHelper.startPage(1,5);

    List<User> users2 = mapper.selectAll();
    
    // 参数是查询后的 list 结果
    PageInfo<User> pageInfo = new PageInfo<>(users2);

    System.out.println(pageInfo.getList());
}

你可能感兴趣的:(mybatis,学习,笔记)