【java总结】框架之MyBatis

【java总结】框架之MyBatis

MyBatis基础

什么是MyBatis?

MyBatis 本是 apache 的一个开源项目 iBatis,Mybatis是一个半ORM(对象关系映射)框架,它内部封装了JDBC,开发时只需要关注SQL语句本身,不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。程序员直接编写原生态sql,可以严格控制sql执行性能,灵活度高。

Mybaits的优点?

(1)基于SQL语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL写在XML里,解除sql与程序代码的耦合,便于统一管理;提供XML标签,支持编写动态SQL语句,并可重用。

(2)与JDBC相比,减少了50%以上的代码量,消除了JDBC大量冗余的代码,不需要手动开关连接;

(3)很好的与各种数据库兼容(因为MyBatis使用JDBC来连接数据库,所以只要JDBC支持的数据库MyBatis都支持)。

(4)能够与Spring很好的集成;

(5)提供映射标签,支持对象与数据库的ORM字段关系映射;提供对象关系映射标签,支持对象关系组件维护。

缺点:

(1)SQL语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写SQL语句的功底有一定要求。

(2)SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。

MyBatis的缓存

mybatis提供查询缓存,用于减轻数据库压力,提高数据库性能

MyBatis的缓存分为一级缓存和二级缓存,分别如下:

  • 一级缓存放在session里面,默认就有。
  • 二级缓存放在它的命名空间里,默认是打开的。使用二级缓存属性类需要实现Serializable序列化接口(可用来保存对象的状态),可在它的映射文件中配置

在config.xml设置二级缓存开关 , 还要在具体的mapper.xml开启二级缓存

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

需要将映射的javapojo类实现序列化

<cache eviction="LRU" flushInterval="10000"/>

MyBatis使用

创建流程

1.创建mybatis-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核心配置-->
<configuration>
    <!--environments可以配置多个环境,default选择默认环境-->
    <environments default="development">
        <environment id="development">
            <!--事务管理-->
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8"/>
                <property name="username" value="guo"/>
                <property name="password" value="guo"/>
            </dataSource>
        </environment>
    </environments>
</configuration>

2.编辑mybatis工具类

public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
            //第一步!
            // /*使用mybatis获取sqlSessionFactory对象*/
            String resource = "mybatis-config.xml";
            /*获取配置文件resource*/
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**第二步!!
     * 从sqlSessionFactory中获取sqlsession
     * sqlsession完全包含了面向数据库执行sql命令所需的所有方法
     * */
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
}

3.创建mapper映射文件

<?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">
<!--接口实现类由原来的userdaoimpl转变为一个mapper配置文件-->
<mapper namespace="cn.jimu98.dao.UserDao">
    <select id="getUserList" resultType="cn.jimu98.pojo.User">
        select * from user
    </select>
</mapper>

4.测试

public class UserDaoTest {
    @Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        List<User> userList = userDao.getUserList();
        for (User user : userList) {
            System.out.println(user);
        }
        sqlSession.close();
    }
}

全局配置

引入外部配置文件

db.properties

db.username=root
db.password=123
db.driver=com.mysql.cj.jdbc.Driver
db.url=jdbc:mysql:///test01?serverTimezone=Asia/Shanghai

mybatis-config.xml

<configuration>
    <properties resource="db.properties"></properties>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${db.driver}"/>
                <property name="url" value="${db.url}"/>
                <property name="username" value="${db.username}"/>
                <property name="password" value="${db.password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <package name="cn.jimu98.mybatis.mapper"/>
    </mappers>
</configuration>

settings

Setting(设置)Description(描述)Valid Values(验证值组)Default(默认值)
cacheEnabled在全局范围内启用或禁用缓存配置任何映射器在此配置下true or falseTRUE
lazyLoadingEnabled在全局范围内启用或禁用延迟加载。禁用时,所有查询将热加载true or falseTRUE
aggressiveLazyLoading启用时,有延迟加载属性的对象将被完全加载后调用懒惰的任何属性。否则,每一个属性是按需加载。true or falseTRUE
multipleResultSetsEnabled允许或不允许从一个单独的语句(需要兼容的驱动程序)要返回多个结果集。true or falseTRUE
useColumnLabel使用列标签,而不是列名。在这方面,不同的驱动有不同的行为。参考驱动文档或测试两种方法来决定你的驱动程序的行为如何。true or falseTRUE
useGeneratedKeys允许 JDBC 支持生成的密钥。兼容的驱动程序是必需的。此设置强制生成的键被使用,如果设置为 true,一些驱动会不兼容性,但仍然可以工作。true or falseFALSE
autoMappingBehavior指定 MyBatis 应如何自动映射列到字段/属性。NONE自动映射。 PARTIAL 只会自动映射结果没有嵌套结果映射定义里面。 FULL 会自动映射的结果映射任何复杂的(包含嵌套或其他)。NONE, PARTIAL, FULLPARTIAL
defaultExecutorType配置默认执行人。SIMPLE执行人确实没有什么特别的。 REUSE执行器重用准备好的语句。 BATCH执行器重用语句和批处理更新。SIMPLE REUSE BATCHSIMPLE
defaultStatementTimeout设置驱动程序等待一个数据库响应的秒数。Any positive integerNot Set (null)
safeRowBoundsEnabled允许使用嵌套的语句RowBounds。true or falseFALSE
mapUnderscoreToCamelCase从经典的数据库列名 A_COLUMN 启用自动映射到骆驼标识的经典的 Java 属性名 aColumn。true or falseFALSE
localCacheScopeMyBatis的使用本地缓存,以防止循环引用,并加快反复嵌套查询。默认情况下(SESSION)会话期间执行的所有查询缓存。如果 localCacheScope=STATMENT 本地会话将被用于语句的执行,只是没有将数据共享之间的两个不同的调用相同的 SqlSession。SESSION or STATEMENTSESSION
dbcTypeForNull指定为空值时,没有特定的JDBC类型的参数的 JDBC 类型。有些驱动需要指定列的 JDBC 类型,但其他像 NULL,VARCHAR 或 OTHER 的工作与通用值。JdbcType enumeration. Most common are: NULL, VARCHAR and OTHEROTHER
lazyLoadTriggerMethods指定触发延迟加载的对象的方法。A method name list separated by commasequals,clone,hashCode,toString
defaultScriptingLanguage指定所使用的语言默认为动态SQL生成。A type alias or fully qualified class name.org.apache.ibatis.scripting.xmltags.XMLDynamicLanguageDriver
callSettersOnNulls指定如果setter方法或地图的put方法时,将调用检索到的值是null。它是有用的,当你依靠Map.keySet()或null初始化。注意原语(如整型,布尔等)不会被设置为null。true or falseFALSE
logPrefix指定的前缀字串,MyBatis将会增加记录器的名称。Any StringNot set
logImpl指定MyBatis的日志实现使用。如果此设置是不存在的记录的实施将自动查找。SLF4J or LOG4J or LOG4J2 or JDK_LOGGING or COMMONS_LOGGING or STDOUT_LOGGING or NO_LOGGINGNot set
proxyFactory指定代理工具,MyBatis将会使用创建懒加载能力的对象。CGLIBJAVASSIST

typeAliases

这个是 MyBatis 中定义的别名,分两种,一种是 MyBatis 自带的别名,另一种是我们自定义的别名。

本来,我们在 Mapper 中定义数据类型时,需要写全路径,如下:

<select id="getUserCount" resultType="java.lang.Integer">
    select count(*) from user ;
</select>

但是,每次写全路径比较麻烦。这种时候,我们可以用类型的别名来代替,例如用 int 做 Integer 的别名:

<select id="getUserCount" resultType="int">
    select count(*) from user ;
</select>
自定义别名

我们自己的对象,在 Mapper 中定义的时候,也是需要写全路径:

<select id="getAllUser" resultType="cn.jimu98.mybatis.model.User">
    select * from user;
</select>

这种情况下,写全路径也比较麻烦,我们可以给我们自己的 User 对象取一个别名,在 mybatis-config.xml 中添加 typeAliases 节点:

<configuration>
    <properties resource="db.properties"></properties>
    <typeAliases>
        <typeAlias type="cn.jimu98.mybatis.model.User" alias="java"/>
    </typeAliases>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${db.driver}"/>
                <property name="url" value="${db.url}"/>
                <property name="username" value="${db.username}"/>
                <property name="password" value="${db.password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <package name="cn.jimu98.mybatis.mapper"/>
    </mappers>
</configuration>

这里,我们给 User 对象取了一个别名叫 jimu98,然后,我们就可以在 Mapper 中直接使用 jimu98来代替 User 对象了:

<select id="getAllUser" resultType="jimu98">
    select * from user;
</select>

但是,这种一个一个去枚举对象的过程非常麻烦,我们还可以批量给对象定义别名,批量定义主要是利用包扫描来做,批量定义默认的类的别名,是类名首字母小写,例如如下配置:

<typeAliases>
    <package name="cn.jimu98.mybatis.model"/>
</typeAliases>

这个配置就表示给 cn.jimu98.mybatis.model 包下的所有类取别名,默认的别名就是类名首字母小写。这个时候,我们在 Mapper 中,就可以利用 user 代替 User 全路径了:

<select id="getAllUser" resultType="user">
    select * from user;
</select>

在最新版中,批量定义的别名,类名首字母也可以不用小写,在实际开发中,我们一般使用第二种方式(批量定义的方式)

Mapper 映射文件

parameterType

这个表示输入的参数类型。

在 MyBatis 中,我们在 mapper 引用变量时,默认使用的是 #,像下面这样:

<select id="getUserById" resultType="cn.jimu98.mybatis.model.User">
    select * from user where id=#{id};
</select>

除了使用 # 之外,我们也可以使用 $ 来引用一个变量:

<select id="getUserById" resultType="cn.jimu98.mybatis.model.User">
    select * from user where id=${id};
</select>

$ 相当于是参数拼接的方式,而 # 则相当于是占位符的方式。

对象参数

例如添加一个用户:

Integer addUser(User user);

对应的 mapper 文件如下:

<insert id="addUser" parameterType="cn.jimu98.mybatis.model.User">
    insert into user (username,address,favorites) values (#{username},#{address},#{favorites,typeHandler=cn.jimu98.mybatis.typehandler.List2VarcharHandler});
</insert>

我们在引用的时候,直接使用属性名就能够定位到对象了。如果对象存在多个,我们也需要给对象添加 @Param 注解,如果给对象添加了 @Param 注解,那么对象属性的引用,会有一些变化。如下:

Integer addUser(@Param("user") User user);

如果对象参数添加了 @Param 注解,Mapper 中的写法就会发生变化:

<insert id="addUser" parameterType="cn.jimu98.mybatis.model.User">
    insert into user (username,address,favorites) values (#{user.username},#{user.address},#{user.favorites,typeHandler=cn.jimu98.mybatis.typehandler.List2VarcharHandler});
</insert>

注意多了一个前缀,这个前缀不是变量名,而是 @Param 注解中定义名称。

Map 参数

如果想要使用 Map 传递参数,技术上来说,肯定是没有问题的。

Integer updateUsernameById(HashMap<String,Object> map);

XML 文件写法如下:

<update id="updateUsernameById">
    update user set username = #{username} where id=#{id};
</update>

引用的变量名,就是 map 中的 key。基本上和实体类是一样的,如果给 map 取了别名,那么在引用的时候,也要将别名作为前缀加上,这一点和实体类也是一样的。

resultType

resultType 是返回类型,在实际开发中,如果返回的数据类型比较复杂,一般我们使用 resultMap,但是,对于一些简单的返回,使用 resultType 就够用了。

resultType 返回的类型可以是简单类型,可以是对象,可以是集合,也可以是一个 hashmap,如果是 hashmap,map 中的 key 就是字段名,value 就是字段的值。

resultMap

先来看一个基本用法:

首先在 mapper.xml 中定义一个 resultMap:

<resultMap id="MyResultMap" type="org.javaboy.mybatis.model.User">
    <id column="id" property="id"/>
    <result column="username" property="username"/>
    <result column="address" property="address"/>
</resultMap>

在这个 resultMap 中,id 用来描述主键,column 是数据库查询出来的列名,property 则是对象中的属性名。

然后在查询结果中,定义返回值时使用这个 ResultMap:

<select id="getUserById" resultMap="MyResultMap">
    select * from user where id=#{id};
</select>

动态 SQL

动态 SQL 是 MyBatis 中非常强大的一个功能。例如一些常见的查询场景:

  • 查询条件不确定
  • 批量插入

image-20200809003512530
if

使用动态 SQL 最常见情景是根据条件包含 where 子句的一部分。比如:

<select id="findActiveBlogWithTitleLike"
     resultType="Blog">
  SELECT * FROM BLOG
  WHERE state = ‘ACTIVE’
  <if test="title != null">
    AND title like #{title}
  </if>
</select>

这条语句提供了可选的查找文本功能。如果不传入 “title”,那么所有处于 “ACTIVE” 状态的 BLOG 都会返回;如果传入了 “title” 参数,那么就会对 “title” 一列进行模糊查找并返回对应的 BLOG 结果(细心的读者可能会发现,“title” 的参数值需要包含查找掩码或通配符字符)。

如果希望通过 “title” 和 “author” 两个参数进行可选搜索该怎么办呢?首先,我想先将语句名称修改成更名副其实的名称;接下来,只需要加入另一个条件即可。

<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>
choose、when、otherwise

有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。

还是上面的例子,但是策略变为:传入了 “title” 就按 “title” 查找,传入了 “author” 就按 “author” 查找的情形。若两者都没有传入,就返回标记为 featured 的 BLOG(这可能是管理员认为,与其返回大量的无意义随机 Blog,还不如返回一些由管理员挑选的 Blog)。

<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>
trim、where、set

前面几个例子已经合宜地解决了一个臭名昭著的动态 SQL 问题。现在回到之前的 “if” 示例,这次我们将 “state = ‘ACTIVE’” 设置成动态条件,看看会发生什么。

<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>
</select>

如果没有匹配的条件会怎么样?最终这条 SQL 会变成这样:

SELECT * FROM BLOG
WHERE

这会导致查询失败。如果匹配的只是第二个条件又会怎样?这条 SQL 会是这样:

SELECT * FROM BLOG
WHERE
AND title like ‘someTitle’

这个查询也会失败。这个问题不能简单地用条件元素来解决。这个问题是如此的难以解决,以至于解决过的人不会再想碰到这种问题。

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>

where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。

如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:

<trim prefix="WHERE" prefixOverrides="AND |OR ">
  ...
</trim>

prefixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。

用于动态更新语句的类似解决方案叫做 setset 元素可以用于动态包含需要更新的列,忽略其它不更新的列。比如:

<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>

这个例子中,set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。

来看看与 set 元素等价的自定义 trim 元素吧:

<trim prefix="SET" suffixOverrides=",">
  ...
</trim>

注意,我们覆盖了后缀值设置,并且自定义了前缀值。

foreach

动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。比如:

<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>

foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符,看它多智能!

提示 你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。

至此,我们已经完成了与 XML 配置及映射文件相关的讨论。下一章将详细探讨 Java API,以便你能充分利用已经创建的映射配置。

script

要在带注解的映射器接口类中使用动态 SQL,可以使用 script 元素。比如:

@Update({"<script>",
  "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}",
  "</script>"})
void updateAuthorValues(Author author);
bind

bind 元素允许你在 OGNL 表达式以外创建一个变量,并将其绑定到当前的上下文。比如:

<select id="selectBlogsLike" resultType="Blog">
  <bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
  SELECT * FROM BLOG
  WHERE title LIKE #{pattern}
</select>
模糊查询like的三种方式:

1、直接在参数上拼接%

2、使用concat()函数做字符串拼接

select * from orders where number like concat(concat(‘%’, #{number}),’%’)

3、bind标签

select * from orders where number like #{ll}

当实体类中的属性名和表中的字段名不一样 ,怎么办 ?

  • 写sql语句时起别名

  • 在MyBatis的全局配置文件中开启驼峰命名规则

    <configuration>
        <settings>
            <!-- 开启驼峰命名规则,可以将数据库中的下划线映射为驼峰命名 -->
            <!-- 例如:dept_id 可以映射为deptId -->
            <setting name="mapUndercoreToCamelCase" value="true" /></setting>
        </settings>
    </configuration>
    1234567
  • 在Mapper映射文件中使用resultMap来自定义映射规则

<select id="getOrder" parameterType="int" resultMap="orderresultmap">
	select * from orders where order_id=#{id}
</select>
<resultMap type=”me.gacl.domain.order” id=”orderresultmap”>
	<!–用id属性来映射主键字段–>
	<id property=”id” column=”order_id”>
	<!–用result属性来映射非主键字段,property为实体类属性名,column为数据表中的属性–>
		<result property = “orderno” column =”order_no”/>
		<result property=”price” column=”order_price” />
</reslutMap>

#{}和${}的区别是什么?

#{}是预编译处理,${}是字符串替换。

Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;

Mybatis在处理${}时,就是把${}替换成变量的值。

使用#{}可以有效的防止SQL注入,提高系统安全性。

MyBatis其他问题

MyBatis与Hibernate有哪些不同?

(1)Mybatis和hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句。

(2)Mybatis直接编写原生态sql,可以严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,因为这类软件需求变化频繁,一但需求变化要求迅速输出成果。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件,则需要自定义多套sql映射文件,工作量大。

(3)Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件,如果用hibernate开发可以节省很多代码,提高效率。

什么是MyBatis的接口绑定,有什么好处

答:接口映射就是在IBatis中任意定义接口,然后把接口里面的方法和SQL语句绑定,我们直接调用接口方法就可以,这样比起原来了SqlSession提供的方法我们可以有更加灵活的选择和设置。

接口绑定有几种实现方式,分别是怎么实现的?

答:接口绑定有两种实现方式:

  • 一种是通过注解绑定,就是在接口的方法上面加上@Select@Update等注解里面包含Sql语句来绑定。
  • 另外一种就是通过xml里面写SQL来绑定,在这种情况下,要指定xml映射文件里面的namespace必须为接口的全路径名。

什么情况下用注解绑定,什么情况下用xml绑定

当Sql语句比较简单时候,用注解绑定。
当SQL语句比较复杂时候,用xml绑定,一般用xml绑定的比较多。

Mybatis是如何进行分页的?分页插件的原理是什么?

答:Mybatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页,而非物理分页,可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。

分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数。

举例:select * from student,拦截sql后重写为:select t.* from (select * from student)t limit 0,10

简述Mybatis的插件运行原理,以及如何编写一个插件。

答:Mybatis仅可以编写针对ParameterHandler、ResultSetHandler、StatementHandler、Executor这4种接口的插件,Mybatis使用JDK的动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这4种接口对象的方法时,就会进入拦截方法,具体就是InvocationHandler的invoke()方法,当然,只会拦截那些你指定需要拦截的方法。

实现Mybatis的Interceptor接口并复写intercept()方法,然后在给插件编写注解,指定要拦截哪一个接口的哪些方法即可,记住,别忘了在配置文件中配置你编写的插件。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值