Mybatis MyBatis-Generator Interceptor PageHelper

2021/07/29

mybatis MyBatis-Generator Interceptor PageHelper

参考资料

一、MyBatis基础

1.1 ORM介绍

  • ORM: 对象关系映射(英语:Object Relational Mapping ), 在关系型数据库和业务实体对象之间作一个映射
    Hibernate的轻量级 ORM 模型逐步确立了在 JAVA ORM 架构中领导地位
    linqToSql:微软为SQLSERVER数据库提供的,是.NET FRAMEWORK 3.5 版的一个组件,提供了用于将关系数据作为对象管理的运行时基础结构 
  • ORM框架: 就是用于实现ORM技术的程序, 当前ORM框架主要有四种:
    • Hibernate(Nhibernate)
    • iBATIS
    • mybatis
    • EclipseLink

1.2 mybatis配置、使用

核心概念:

  • mybatis-config.xml:配置数据源、事务等核心配置
  • SqlSessionFactoryBuilder:主要作用就是读mybatis-config.xml中配置,创建一个SqlSessionFactory
  • SqlSessionFactory:sql会话工厂,用于创建SqlSession
  • SqlSession:定义了数据库的增删改查以及事务管理的常用方法,还提供了查找Mapper接口的有关方法,每次收到的 HTTP 请求,就可以打开一个 SqlSession,返回一个响应,就关闭它。
  • Mapper:由SqlSession创建, 用于将Java对象和实际的SQL语句映射

使用示例:

问题总结:

  • logback中把mapper包的日志改为debug,可以看到查询sql
  • ${}区别#{}:
    • $方式无法防止Sql注入,#{}方式能够很大程度防止sql注入
    • 动态传入列名时,是非预编译的话,最好使用${}而不是#{}
  • 传参方式
1.一个参数直接传

2.多参数,占位符顺序遍历参数:
Public User selectUser(String name,String password);
select * from t_user where name = #{0} and password=#{1}

3.Map传多参数
Public User selectUser(Map paramMap);
select * from t_user where name = #{paramMap.name} and password = #{paramMap.password}

4.@param传多参数
Public User selectUser(@param(“name”)String name, @param(“password”)String password);
select * from t_user where name = #{name} and password = #{password}

5.pojo传多参数
public List<User> getUserByParam(User user);
<select id="getUserByParam" resultType="com.wds.demo.entity.User" parameterType="com.wds.demo.entity.User" >
    select * from t_user t
    <where>
       <if test="{name} != null">
            t.name like CONCAT('%',#{name},'%')
       </if>
       <if test="{password} != null">
           and t.password like CONCAT('%',#{password},'%')
       </if>
    </where> 
</select> 

二、MyBatis-Generator

SpringBoot整合Mybatis(三)集成Mybatis Generator进行代码自动生成

Mybatis Generator最完整配置详解

三、Interceptor拦截器

mybatis Interceptor拦截器实现机制,使用的是JDK的InvocationHandler.
会在程序执行指定sql前后,对请求参数和返回值进行处理的插件.
MyBatis 允许使用插件来拦截的方法调用包括:

// 执行器
Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
// 请求参数处理
ParameterHandler (getParameterObject, setParameters)
// 返回结果集处理
ResultSetHandler (handleResultSets, handleOutputParameters)
// SQL语句构建
StatementHandler (prepare, parameterize, batch, update, query)

如果需要实现自定义的拦截器,需要实现 org.apache.ibatis.plugin.Interceptor 接口,该接口有三个方法:

  • Object intercept(Invocation invocation) throws Throwable;
  • Object plugin(Object target);
  • void setProperties(Properties properties);

应用场景示例

  • mybatis拦截器实现数据库字段加密解密: 需要在保存数据前和查询返回结果后对相应数据进行加解密处理,需要针对 Parameter 和 ResultSet这两种类型进行处理
  • 统一拦截update语句,更新修改时间update_time字段
@Slf4j
@Intercepts({ @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }) })
public class CommonFieldInterceptor implements Interceptor { 
	// 公共字段值设置
	public void setCommonFieldValues(Object bean) {
		if(bean == null) {
			return;
		}
		try {
			// 创建时间,在为空时写入当前时间
			if (BeanUtil.containsProp(bean, "updateTime") && BeanUtil.getPropValue(bean, "updateTime") == null) {
				BeanUtil.setPropValue(bean, "updateTime", new Date());
			}
			// 修改时间,始终写入当前时间
			if (BeanUtil.containsProp(bean, "updateTime")) { 
				BeanUtil.setPropValue(bean, "updateTime", new Date());
			}
		} catch (Exception e) {
			logger.error("设置{}对象公共字段时出错!", new Object[] { bean.getClass().getName() }, e);
		}
	}

	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		// MappedStatement mappedStatement = (MappedStatement)
		// invocation.getArgs()[0];
		// String sqlId = mappedStatement.getId();
		// String namespace = sqlId.substring(0, sqlId.lastIndexOf('.'));
		// Executor exe = (Executor) invocation.getTarget();
		String methodName = invocation.getMethod().getName();
		if (methodName.equals("update")) {
			// 对pojo对象设置公共字段
			Object bean = invocation.getArgs()[1];
			setCommonFieldValues(bean);
		}
		return invocation.proceed();
	}

	@Override
	public Object plugin(Object target) {  //Object target 被代理的目标对象
		return Plugin.wrap(target, this);  //wrap把拦截器对象封装成Plugin代理对象.
	}

	@Override
	public void setProperties(Properties properties) {

	}
}

四、分页插件PageHelper

无需你自己去封装以及关心sql分页等问题,使用很方便,前端取数据也很方便

  • PageHelper
    • 1) 对国产数据库支持不足
    • 2) 扩展不方便
    • 3) 配置复杂
    • 4) 性能底下 (不要喷我, 因为它不是用的占位符?,发挥不了PrepareSatement的优势)
    • 5) 只支持MyBatis
  • Sqlhelper
    • 支持MyBatis, JFinal,Ebean,Mango
    • 支持 90+ 种数据库, 支持列表参见 here. 包含了几乎所有的国产数据库:
    • 同一个应用中支持多种数据库
    • 不需要配置dialect,可以自动的获取。
    • 比 Mybatis-PageHelper性能更高, 原因是limit , offset等参数使用 PrepareStatement placeholder ‘?’ , Mybatis是硬编码拼接的
    • 通过Java SPI的方式支持了插件
    • 支持 spring boot 1.x , 2.x
    • 支持 mybatis 3.x
    • 支持 JDK6+

PageHelper集成使用

五、使用总结

一对多:MyBatis中的collection两种使用方法

MyBatis实现一对多 多层Collection集合嵌套关系实现

//示例:三表级联,两层嵌套
<resultMap id="PerquisiteResultMap" type="com.wds.entity.model.Organization">
    <id column="id" property="id" jdbcType="INTEGER"/>
    <result column="name" property="name" jdbcType="VARCHAR"/>

    <collection property="perquisites" ofType="com.wds.entity.model.Perquisite">
        <id column="per_id" jdbcType="INTEGER" property="id"/>
        <result column="org_id" jdbcType="INTEGER" property="orgId"/>
        <result column="per_name" jdbcType="VARCHAR" property="name"/>

        <collection property="perquisiteSpans" ofType="com.wds.entity.model.PerquisiteSpan">
            <id column="span_id" jdbcType="INTEGER" property="id"/>
            <result column="perquisite_id" jdbcType="INTEGER" property="perquisiteId"/>
        </collection>
    </collection>
</resultMap>

<select id="selectOrgWithPerquisite" resultMap="PerquisiteResultMap">
    select org.id as id, org.name as name, 
        per.id as per_id, per.name as per_name,
	    span.id span_id, span.perquisite_id
    from organization org 
    left join perquisite per on per.org_id = org.id
	left join perquisite_span span on span.perquisite_id = per.id
    where org.delete_tate = 'A' and per.delete_state = 'A'  and span.delete_state = 'A'
</select>

Post Directory

扫码关注公众号:暂无公众号
发送 290992
即可立即永久解锁本站全部文章