清茶书香

一杯清茶,一本书籍,一个下午。


  • 首页

  • 归档

  • 分类

  • 关于

  • 搜索
Redis JPA Solr SpringData SpringMVC localRepository local Mapper 事务 Mybatis JDBC AOP DI IOC 常用函数 触发器 存储过程 Promise Gateway SpringCloud vue-cli axios es6 webpack npm vue 个性化 zsh 终端 caffeine jvm缓存 guava cache validation Mapping MapStruct comment 小程序 建站 WeHalo config logback plugins database idea maven spring https http nginx password RabbitMQ 秒杀系统 Windows MySQL 数据备份 halo SpringBoot shell Linux ip Optional Stream Lambda k8s Docker 列编辑 vim MacOS 图片合成 Java 远程联调 nps 内网穿透

MyBatis详解(二)

发表于 2019-06-28 | 分类于 Mybatis | 0 | 阅读次数 293

通过上一章我们学习了通过mybatis框架实现增删改查的操作,这一章我们主要学习mybatis的进阶级语法,包括动态SQL、缓存、关联查询,以及通过工具生成一个数据库表在Java对应的实体类、mapper接口、mapper配置文件和Spring Mybatis的整合等。

动态SQL

if标签

通过if标签来判断传的参数是否为空,然后拼接到SQL语句上,示例:

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG WHERE state = 'ACTIVE'
  <if test="title != null">
    AND title like #{title}
  </if>
  <if test="author != null and author.name != null">
    AND author_name like #{author.name}
  </if>
</select>

如果我们的state字段也是动态拼接的,那这里就有问题了,比如我三个条件都没有时,拼出来的sql语句就是SELECT * FROM BLOG WHERE显然是无法执行的,这就要用到我们的where标签

choose...when...otherwise标签

有时我们不想应用到所有的条件语句,而只想从中择其一项。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。

使用示例:

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG WHERE state = ‘ACTIVE’
  <choose>
    <when test="title != null">
      AND title like #{title}
    </when>
    <when test="author != null and author.name != null">
      AND author_name like #{author.name}
    </when>
    <otherwise>
      AND featured = 1
    </otherwise>
  </choose>
</select>

tirm,where,set标签

<where>标签

当我们拼接动态SQL时,如果一个查询条件都没有,那我们就不需要where子句,而如果有至少一个条件我们就需要where子句。这样,我们就需要做个判断,而mybatis里的标签就省去了我们自己做这个判断。 使用示例:

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG
  <where>
    <if test="state != null">
         state = #{state}
    </if>
    <if test="title != null">
        AND title like #{title}
    </if>
    <if test="author != null and author.name != null">
        AND author_name like #{author.name}
    </if>
  </where>
</select>

当一个查询条件都没有拼接时, mybatis会自动将where关键字和拼接多个条件之间的诸如AND、OR这些多余的关键字去掉

<set>标签

set 元素会动态前置 SET 关键字,同时也会删掉无关的逗号(如:语句最后的逗号)
使用示例:

<update id="updateAuthorIfNecessary">
  update Author
    <set>
      <if test="username != null">username=#{username},</if>
      <if test="password != null">password=#{password},</if>
      <if test="email != null">email=#{email},</if>
      <if test="bio != null">bio=#{bio}</if>
    </set>
  where id=#{id}
</update>

<trim>标签

trim标签可以
常用属性有:

  • prefix: 添加指定前缀
  • prefixOverrides: 删除指定前缀
  • suffixOverrides: 删除指定后缀
    示例一:用标签实现标签功能
<trim prefix="WHERE" prefixOverrides="AND |OR ">
  ...
</trim>

prefixOverrides的作用是移除字符串开头的内容中所有指定在 prefixOverrides 属性中的内容,并且插入 prefix 属性中指定的内容。

示例二: 用标签实现标签功能

<!-- 以下内容实现了动态的拼接更新的SQL操作 -->    
<update id="updateById" parameterType="BookType">
	update booktype
	<trim prefix="set" suffixOverrides=",">
        <if test="id != null">
            id = #{id},
        </if>
        <if test="tname != null">
            tname = #{tname},
        </if>
	</trim>
	where id = #{id}
</update>

注意这里我们删去的是后缀值,同时添加了前缀值。

foreach标签

foreach标签用于通过循环的方式动态拼接SQL,该标签的属性有collection,item,index,这三个下面重点介绍,而open属性是在循环开始时添加我们要加的字符串,separator属性则是循环中间添加字符串,close属性是循环结束时添加字符串。使用方法如下:

<select id="selectPostIn" resultType="domain.blog.Post">
  SELECT *
  FROM POST P
  WHERE ID in
  <foreach item="item" index="index" collection="list"
      open="(" separator="," close=")">
        #{item}
  </foreach>
</select>
  • item: 指定在循环中可以用的item属性名称。当循环的对象是List、Set、数组时item是当前迭代的对象的元素值;而当循环对象是Map时,item是key对应的值
  • index: 指定在循环中可以用的index属性名称。当循环的对象是List、Set、数组时index是当前迭代的次数;而当循环对象是Map时,index是key

迭代集合类型参数

java代码:

int batchInsertByNormal(List<Teacher> teacherList);

xml中迭代

<insert id="batchInsertByNormal" parameterType="Teacher">
    insert into teacher (tname, age) values
    <!-- 迭代list类型参数时,collection的值写list, 这时index就是迭代次数,item是迭代的元素 -->        
    <foreach collection="list" index="idx" item="teacher" separator="," close=";">
             (#{teacher.tname}, #{teacher.age})
    </foreach>
</insert>

迭代数组类型参数(和迭代集合类型类似)

java代码:

int batchInsertByNormal(List<Teacher> teacherList);

xml代码:

<insert id="batchInsertByNormal" parameterType="Teacher">
    insert into teacher (tname, age) values
    <!-- 迭代数组类型参数时,collection的值写array, 这时index就是迭代次数,item是迭代的元素 -->        
    <foreach collection="array" index="idx" item="teacher" separator="," close=";">
             (#{teacher.tname}, #{teacher.age})
    </foreach>
</insert>

迭代Map类型参数

java代码:

void testForeachMap(@Param("data") Map<String, Integer> data);

xml代码:

<select id="testForeachMap" parameterType="hashmap">
    insert into teacher (tname, age) values
    <!-- 迭代map类型参数时,collection写接口中通过@Param注解指定的map参数名称,这时index就是map的key,item就是map的value -->
    <foreach collection="data" index="key" item="value" separator=",">
            (#{key}, #{value})
    </foreach>
</select>

缓存

一级缓存(本地缓存)

配置方法:

<setting name="localCacheScope" value="SESSION"/>

取值有两个:SESSION和STATEMENT分别对应缓存应用session会话范围和一次statement范围

  • MyBatis一级缓存的生命周期和SqlSession一致。
  • MyBatis一级缓存内部设计简单,只是一个没有容量限定的HashMap,在缓存的功能上有所欠缺。
  • MyBatis的一级缓存最大范围是SqlSession内部,有多个SqlSession或者分布式的环境下,数据库写操作会引起脏数据,建议设定缓存级别为Statement。

二级缓存

开启二级缓存的方法

第一步,打开全局二级缓存开关

<setting name="cacheEnabled" value="true"/>

在具体的Mapper中开启二级缓存

<cache/> 

可配置参数:

  • type:cache使用的类型,默认是
  • PerpetualCache,这在一级缓存中提到过。
  • eviction: 定义回收的策略,常见的有FIFO,LRU。
  • flushInterval: 配置一定时间自动刷新缓存,单位是毫秒。
  • size: 最多缓存对象的个数。
  • readOnly: 是否只读,若配置可读写,则需要对应的实体类能够序列化。
  • blocking: 若缓存中找不到对应的key,是否会一直blocking,直到有对应的数据进入缓存。

二级缓存可以跨越不同的SqlSession之间,可以达到namespace级别(但必须是同一个SqlSessionFactory)

缓存查找顺序

二级缓存 --> 一级缓存 --> 查数据库

关联查询

一对一关联

一对一的关联需要在xml配置中的<resultMap>标签中使用<association>标签,示例:

<resultMap id="book" type="Book">
        <id column="b_id" property="id"/>
        <result column="bname" property="bname"/>
        <result column="author" property="author"/>
        <result column="author_gender" property="authorGender"/>
        <result column="price" property="price"/>
        <result column="description" property="description"/>
    	<!-- bookType属性是引用类型:BookType,一本书对应一种图书类型 -->
        <association property="bookType" javaType="BookType">
            <id column="bt_id" property="id"/>
            <result column="tname" property="tname"/>
        </association>
    </resultMap>

多对多关联

多对多的关联需要使用xml配置中的<collection>标签,示例:

    <resultMap id="stu" type="Student">
        <result property="id" column="id" />
        <result property="sname" column="sname" />
        <result property="age" column="age" />
        <result property="gender" column="gender" />
        <result property="nickName" column="nick_name" />
        <!-- book属性同样是引用类型Book,一个学生对应多本书 -->
        <collection property="book" ofType="Book">
            <id column="b_id" property="id"/>
            <result column="bname" property="bname"/>
            <result column="author" property="author"/>
            <result column="author_gender" property="authorGender"/>
            <result column="price" property="price"/>
            <result column="description" property="description"/>
            <!-- bookType属性是引用类型:BookType,一本书对应一种图书类型 -->
            <association property="bookType" javaType="BookType">
                <id column="bt_id" property="id"/>
                <result column="tname" property="tname"/>
            </association>
        </collection>
    </resultMap>

官方代码生成工具-Generator

命令行方式使用

命令行方式就需要mybatis-generator-core-1.3.7.jar包,以及一个xml配置文件,下面给出配置文件demo

<?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>
    
	<!-- 引入第三方依赖包 -->
	<classPathEntry location="D:\m2\maven repository\mysql\mysql-connector-java\5.1.47\mysql-connector-java-5.1.47.jar" />
	
	<!--
     targetRuntime常用值:
        MyBatis3Simple(只生成基本的CRUD和少量的动态SQL)
        MyBatis3(生成完整的CRUD,包含CriteriaAPI方法Example后缀的方法)
     -->
    <context id="localhost_mysql" targetRuntime="MyBatis3Simple">

        <!-- 不生成注解 -->
        <commentGenerator>
            <property name="suppressAllComments" value="true" />
        </commentGenerator>

        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/books?characterEncoding=utf8"
                        userId="root"
                        password="root">
        </jdbcConnection>

        <javaTypeResolver >
            <property name="forceBigDecimals" value="false" />
        </javaTypeResolver>

		<!-- 生成实体类 -->
        <javaModelGenerator targetPackage="com.spring.bean" targetProject="src/main/java">
            <property name="enableSubPackages" value="false" />
            <property name="trimStrings" value="true" />
        </javaModelGenerator>

		<!-- 生成XML Mapper -->
        <sqlMapGenerator targetPackage="src/main/resources/mapper" targetProject=".">
            <property name="enableSubPackages" value="false" />
        </sqlMapGenerator>

		<!-- 生成Mapper接口 -->
        <!-- 生成的Mapper类型:ANNOTATEDMAPPER(注解)、MIXEDMAPPER(混合)、XMLMAPPER(XML) -->
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.spring.mapper"  targetProject="src/main/java">
            <!-- 是否将数据库中的schema作为包名的一部分,默认就是false -->
            <property name="enableSubPackages" value="false" />
        </javaClientGenerator>
        
        <table schema="books" tableName="book" domainObjectName="BookDO"
               enableCountByExample="false">
            <!-- 是否用数据库中的字段名作为POJO属性名(不自动转小驼峰),默认值是false -->

            <!--
            <property name="useActualColumnNames" value="true"/>
            -->
            <!-- 生成代码时支持获取插入数据后自增的ID, 需要通过sqlStatement配置数据库类型。 -->

            <generatedKey column="id" sqlStatement="mysql" identity="true" />

            <!-- 此标签用于在生成代码时忽略数据库中的某个字段 -->
            <!--
            <ignoreColumn column="FRED" />
            -->
            <!-- 通过此标签重写mybatis从数据库读到的元信息,自定义列相关配置,包括(名称、类型) -->
            <!--
            <columnOverride column="aa" property="sname" />
            -->
        </table>
    </context>
</generatorConfiguration>

然后就可以使用下面的命令来生成代码了(配置文件名为:generatorConfig.xml)

java -jar mybatis-generator-core-1.3.7.jar -configfile generatorConfig.xml -overwrite

echo "SUCCESS"

注:如果不存在src\main\java这三个文件夹,那么就不会生成bean实体类,因此如果设置了生成的代码放置的文件夹,那么就需要创建它们。

为了避免这种情况,我们可以在运行jar包之前先通过命令创建需要的文件夹

mkdir src\main\java

java -jar mybatis-generator-core-1.3.7.jar -configfile generatorConfig.xml -overwrite

echo "SUCCESS"

我们可以通过将上面的命令先写在txt中,然后存储为.bat格式,这种格式可以在windows平台直接运行,这样就不需要每次都有输入上面的命令。如果在Linux系统则可以存储为.sh格式,且创建文件夹的命令要加一个-p参数,如:mkdir -p src\main\java

maven方式使用

首先要在pom.xml文件中添加一个插件

    <build>
        <plugins>
            <!-- 引用插件 -->
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
            </plugin>
        </plugins>

        <pluginManagement>
            <plugins>
                <!-- 生成实体类、mapper等代码的插件 -->
                <plugin>
                    <groupId>org.mybatis.generator</groupId>
                    <artifactId>mybatis-generator-maven-plugin</artifactId>
                    <version>1.3.7</version>
                    <executions>
                        <execution>
                            <id>Generate MyBatis Artifacts</id>
                            <goals>
                                <goal>generate</goal>
                            </goals>
                        </execution>
                    </executions>
                    <configuration>
                        <!-- 指定自定义配置文件(代码生成工具)路径,配置文件默认会在resources文件夹下找generatorConfig.xml,如果换了地方(名字)需要在下面标签中指定 -->
                        <!-- <configurationFile>${basedir}/src/main/resources/mybatis/generatorConfig.xml</configurationFile> -->
                        <includeCompileDependencies>true</includeCompileDependencies>
                        <overwrite>true</overwrite>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>

将插件引入项目中后,还需要在resources文件夹下添加一个名为generatorConfig.xml的配置文件,这个配置文件与命令行方式的配置文件基本一致,只是不再需要引用jar包,因为我们已经在pom.xml文件中对插件授权了共享项目中引入的依赖,因此不引用jar包的前提是项目中已经添加了数据库驱动的依赖。

Spring MyBatis整合

概述

MyBatis-Spring 会帮助你将 MyBatis 代码无缝地整合到 Spring 中。它将允许 MyBatis 参与到 Spring 的事务管理之中,创建映射器 mapper 和 SqlSession 并注入到 bean 中,以及将 Mybatis 的异常转换为 Spring 的 DataAccessException。最终,可以做到应用代码不依赖于 MyBatis,Spring 或 MyBatis-Spring。

使用示例

  1. 添加依赖包
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
</dependency>
  1. 配置数据源
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="url" value="${jdbc.url}"/>
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="username" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
  1. 配置Spring、Mybatis整个的管理Bean
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <!-- 指定XML Mapper文件的路径 -->
    	<property name="mapperLocations" value="classpath:/mapper/*"/>
    </bean>
  1. 通过mybatis scheme来自动扫描所有的Mapper接口
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mybatis="http://mybatis.org/schema/mybatis-spring"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
        http://mybatis.org/schema/mybatis-spring
        http://mybatis.org/schema/mybatis-spring.xsd">
    
    <!-- 自动扫描所有Mapper接口 -->
    <mybatis:scan base-package="com.lanou3g.spring.mapper" />
</beans>
  1. 使用

经过上面的几步配置后, 我们就可以直接从Spring的IOC容器中获取Mapper操作接口了

public class AppTest {
    
    /**
     * 测试mybatis-spring
     */
    @Test
    public void testMyBatisAndSpring(){
        // 1. 初始化IOC容器
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 2. 从容器中获取Service对象(Mapper对象已经自动注入到Service中了)
        MessageServiceImpl messageService = ctx.getBean(MessageServiceImpl.class);
        // 3. 执行查询所有方法
        List<Message> messageList = messageService.queryAll();
        log.info("" + messageList);
    }
}
Bennett wechat
欢迎收藏我的微信小程序,方便查看更新的文章。
  • 本文作者: Bennett
  • 本文链接: https://hibennett.cn/archives/mybatis-2
  • 版权声明: 本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处!
# Mybatis # Mapper
Mybatis详解(一)
了解SpringMVC(一)
  • 文章目录
  • 站点概览
Bennett

Bennett

60 日志
28 分类
74 标签
RSS
Github E-mail Gitee QQ
Creative Commons
Links
  • MacWk
  • 知了
0%
© 2020 — 2023 hibennett.cn版权所有
由 Halo 强力驱动
|
主题 - NexT.Pisces v5.1.4

浙公网安备 33010802011246号

    |    浙ICP备2020040857号-1