java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > MyBatis之动态SQL和缓存

MyBatis之动态SQL和缓存使用及说明

作者:荔枝当大佬

这篇文章主要介绍了MyBatis之动态SQL和缓存使用及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

前言

在这篇文章中荔枝将会梳理有关MyBatis动态SQL和MyBatis缓存的相关知识,同时也稍微了解了有关MyBatis中借助MAVEN中的插件管理来实现逆向工程。

一、动态SQL

Mybatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能,它存在的意义是为了解决拼接SQL语句字符串时的问题。

在执行SQL查询时,只有属性值存在我们才能做相应的SQL语句的拼接,因此我们需要动态来拼装SQL语句。

在JDBC中我们根据不同的条件拼接SQL语句时往往需要注意一些预留处理,而MyBatis的动态SQL特性就极大地简化了这一处理过程。

1.1 if标签

根据if标签中的test属性所对应的表达式决定标签中的内容是否需要拼接到SQL中。

<?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.crj.mybatis.mapper.DynamicSQLMapper">
<!--    List<Emp> getEmpByCondition(Emp emp);-->
    <select id="getEmpByCondition" resultType="Emp">
        select * from t_emp where 1=1
        <if test="empName != null and empName != ''">
            and emp_name = #{empName}
        </if>
        <if test="age != null and age != ''">
            and age = #{age}
        </if>
        <if test="sex != null and sex != ''">
            and sex = #{sex}
        </if>
    </select>
</mapper>

这段实例demo中,我们需要在select语句中添加一个恒成立的条件1=1,这是为了防止SQL语句在某些属性不存在时出现的拼接错误。动态SQL的特性其实类似一种按需加载的过程,弹性拼接起SQL语句。if标签中的test属性其实就是if标签中的SQL语句段拼接的条件,满足这个条件才能拼接在原有的查询SQL语句中。

1.2 where标签

where标签可以辅助我们动态生成SQL语句中的where关键字,当where后面有内容时,where标签会帮助我们自动生成where关键字,同时会去掉内容前多余的and和or关键字,此时就无需我们手动添加where关键字和恒成立的条件了;当where后面没有内容时,此时不会生成where关键字。

<!--    List<Emp> getEmpByCondition(Emp emp);-->
    <select id="getEmpByCondition" resultType="Emp">
        select * from t_emp
        <where>
            <if test="empName != null and empName != ''">
                and emp_name = #{empName}
            </if>
            <if test="age != null and age != ''">
                and age = #{age}
            </if>
            <if test="sex != null and sex != ''">
                and sex = #{sex}
            </if>
        </where>
    </select>

1.3 trim标签

若标签中有内容时,属性功能正常;若标签没有内容时, trim不会有任何效果。

几个属性:

<!--    List<Emp> getEmpByCondition(Emp emp);-->
    <select id="getEmpByCondition" resultType="Emp">
        select * from t_emp
        <trim prefix="where" suffixOverrides="and|or">
            <if test="empName != null and empName != ''">
                 emp_name = #{empName} and
            </if>
            <if test="age != null and age != ''">
                age = #{age} and
            </if>
            <if test="sex != null and sex != ''">
               sex = #{sex}
            </if>
        </trim>
    </select>

1.4 choose、when、otherwise标签

choose和when标签组合起来相当于if...else if...else的结构,如果所有的when条件都不满足,则会执行otherwise中的条件。

<!--    List<Emp> getEmpByChoose(Emp emp);-->
    <select id="getEmpByChoose" resultType="Emp">
        select * from t_emp
        <where>
            <choose>
                <when test="empName != null and empName != ''">
                    emp_name = #{empName}
                </when>
                <when test="age != null and age != ''">
                    age = #{age}
                </when>
                <when test="sex != null and sex != ''">
                    sex = #{sex}
                </when>
                <otherwise>
                    did = 1
                </otherwise>
            </choose>
        </where>
    </select>

1.5 foreach标签

foreach标签简单来说就是一个循环,可以被用来执行批量操作,foreach标签有五种属性:

<!--    int deleteMoreByArray(Integer[] eids);-->
    <delete id="deleteMoreByArray">
        delete * from t_emp where eid in
        <foreach collection="eids" item="eid" separator="," open="(" close=")">
            #{eid}
        </foreach>
    </delete>

1.5 sql标签

sql标签又成为SQL片段,它可以用来记录常用的sql执行语句。通过include标签来引用SQL片段。

    <sql id="emColumns">eid,emp_name,age,sex,email</sql>
    <select id="getEmpByChoose" resultType="Emp">
        select <include refid="emColumns"></include> from t_emp      
    </select>

二、MyBatis的缓存

2.1 一级缓存

MyBatis的一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据就会从缓存中直接获取而不会从数据库中重新访问。一级缓存是默认开启的

一级缓存失效的四种情况:

手动清空缓存:

sqlSession.clearCache();

2.2 二级缓存

二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSessioni查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取。

二级缓存开启的条件:

  1. 在核心配置文件中,设置全局配置属性cacheEnabled="true",默认为true,不需要设置
  2. 在映射文件中设置标签<cache />
  3. 二级缓存必须在SqlSession关闭或提交之后有效 sqlSession.close() | sqlSession.commit()
  4. 查询的数据所转换的实体类类型必须实现序列化的接口

实体类实现序列化接口

public class Emp implements Serializable 

二级缓存失效的情况:

两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效。

二级缓存的相关配置

在二级缓存的开启条件中,我们发现<cache />标签是可以配置一些属性的,具体如下

eviction属性:缓存回收策略

默认的是LRU。

flushlnterval属性:刷新间隔,单位毫秒

默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用增删改语句时刷新

size属性:引用数目,正整数

代表缓存最多可以存储多少个对象,太大容易导致内存溢出

readOnly属性:只读,true/false

2.3 MyBatis缓存查询顺序

首先先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用。

如果二级缓存没有命中,再查询一级缓存;如果一级缓存也没有命中,则查询数据库。

注意在sqlSession关闭之后,一级缓存中的数据会写入二级缓存

三、MyBatis的逆向工程(MBG)

正向工程:先创建ava实体类,由框架负责根据实体类生成数据库表。Hibernate是支持正向工程的。

逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成如下资源:

在使用逆向工程之前首先应该配置好项目依赖

pom.xml

<?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.crj</groupId>
    <artifactId>MyBatis_MBG</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <!--依赖MyBatis核心包-->
    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version>
        </dependency>
        <!--junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.3</version>
        </dependency>
        <!--log4j日志-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>
    <!--控制Maven在构建过程中相关配置-->
    <build>
        <!--构建过程用到的插件-->
        <plugins>
            <!--具体插件-->
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.0</version>
                <!--插件的依赖-->
                <dependencies>
                    <!--逆向工程的核心依赖-->
                    <dependency>
                        <groupId>org.mybatis.generator</groupId>
                        <artifactId>mybatis-generator-core</artifactId>
                        <version>1.3.2</version>
                    </dependency>
                    <!--数据库连接池c3p0-->
                    <dependency>
                        <groupId>com.mchange</groupId>
                        <artifactId>c3p0</artifactId>
                        <version>0.9.2</version>
                    </dependency>
                    <!--mysql驱动-->
                    <dependency>
                        <groupId>mysql</groupId>
                        <artifactId>mysql-connector-java</artifactId>
                        <version>5.1.8</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>
</project>

逆向工程配置文件:

<?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>
    <!--
        targetRuntime:执行生成的逆向工程的版本
            MyBatis3Simple:生成基本的CRUD
            MyBatis:生成带条件的CRUD
    -->
    <!-- 是否去除自动生成的注释 true:是 : false:否 -->
    <context id="DB2Tables" targetRuntime="MyBatis3Simple">
        <!-- 数据库连接 -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/mybatis"
                        userId="root"
                        password="123456">
        </jdbcConnection>
        <!--
            javaBean的生成策略
            生成model模型,对应的包路径,以及文件存放路径(targetProject),targetProject可以指定具体的路径
            也可以使用“MAVEN”来自动生成,这样生成的代码会在target/generatord-source目录下
        -->
        <javaModelGenerator targetPackage="com.crj.mybatis.pojo" targetProject=".\src\main\java">
            <!--是否能够使用子包-->
            <property name="enableSubPackages" value="true" />
            <!-- 从数据库返回的值被清理前后的空格  -->
            <property name="trimStrings" value="true" />
        </javaModelGenerator>
        <!--
            SQL映射文件的生成策略
            对应的mapper.xml文件
        -->
        <sqlMapGenerator targetPackage="com.crj.mybatis.mapper" targetProject=".\src\main\resources">
            <property name="enableSubPackages" value="true" />
        </sqlMapGenerator>
        <!-- 对应的Mapper接口类文件的生成策略 -->
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.crj.mybatis.mapper" targetProject=".\src\main\java">
            <property name="enableSubPackages" value="true" />
        </javaClientGenerator>
        <!-- 逆向分析的表 -->
        <table tableName="t_emp" domainObjectName="Emp"/>
        <table tableName="t_dept" domainObjectName="Dept"/>
    </context>
</generatorConfiguration>

测试类中我们这样来进行条件查询:

EmpExample example = new EmpExample();
//这里可以借助example.createCriteria().and开头的方法来设置查询条件
example.createCriteria().andEmpNameEqualTo("荔枝");
mapper.selectByExample(example);

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文