MybatisPlus支持SqlServer数据库空间数据类型的增改查

本文介绍了如何在MybatisPlus中优化对SqlServer空间数据类型的支持,通过GeoInterceptor拦截器修改插入和更新SQL,避免直接使用`STAsText()`函数。尽管有局限性,但这个方法可供学习参考。
摘要由CSDN通过智能技术生成

前言

MybatisPlus通过内置的一些方法使我们可以不需要编写sql代码即可执行sql语句,而对于空间类型却不太支持,所以本文章是对MybatisPlus支持空间数据类型的一种优化

注:本文章仅针对SqlServer的空间数据进行优化,因其语句执行比较友好。专业的空间数据库没学过,在此不讨论。虽然也可以支持MySQL,但比较麻烦,所以就没写了

环境

springboot:2.7.10

mybatis-plus:3.5.5

系统:Windows 11

java:1.8.351

Maven:3.9.2

实验

1、准备一张表

CREATE TABLE [geo](
    [id] bigint PRIMARY KEY,
    [location] geography
);

2、编写实体类

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;

@Data
public class Geo {
    @TableId
    private Long id;
    @TableField(value = "location.STAsText()")
    private String location;
}

这里直接通过@TableField注解注入调用函数的sql,在使用IService的方法时会自动带上location作为别名,以能正确映射到该属性上

3、Mapper和Service

省略,以平常一致

4、通过拦截器修改sql

第2步只是确保了查询时能够转为wkt,但插入和更新会自动使用@TableField注解里的名字,这将导致错误,接下来,就是要修复该错误了。

import org.apache.ibatis.executor.statement.BaseStatementHandler;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.util.Properties;

@Component
// Intercepts注解用于声明拦截器,此处将会拦截StatementHandler类的prepare(Coonection,Integer)方法
@Intercepts({
        @Signature(
                type = StatementHandler.class,
                method = "prepare",
                args ={Connection.class, Integer.class}
        )
})
public class GeoInterceptor implements Interceptor {
    @Lazy
    @Autowired
    private SqlSessionFactory sqlSessionFactory;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 获取拦截的对象
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        // 获取该方法所对应的sql命令类型
        MetaObject metaObject = MetaObject.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY, SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory());
        MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
        // 如果是插入和更新命令,则进行处理
        if (mappedStatement.getSqlCommandType() == SqlCommandType.INSERT || mappedStatement.getSqlCommandType() == SqlCommandType.UPDATE) {
            // 获取sql
            BoundSql boundSql = statementHandler.getBoundSql();
            String sql = boundSql.getSql();
            // 移除后面的函数
            sql = sql.replaceAll("\\.STAsText\\(\\)", "");
            // 将新的sql放回去
            Field delegate = RoutingStatementHandler.class.getDeclaredField("delegate");
            delegate.setAccessible(true);
            Object o = delegate.get(statementHandler);
            delegate.setAccessible(false);
            Field field = BaseStatementHandler.class.getDeclaredField("boundSql");
            field.setAccessible(true);
            field.set(o, new BoundSql(sqlSessionFactory.getConfiguration(), sql, boundSql.getParameterMappings(), boundSql.getParameterObject()));
            field.setAccessible(false);
        }
        // 后续执行
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return Interceptor.super.plugin(target);
    }

    @Override
    public void setProperties(Properties properties) {
        Interceptor.super.setProperties(properties);
    }
}

至此,大功告成

结语

该拦截器是Mybatis的功能,所以也会对Mapper里面自己手写sql的方法也会生效,若要避免这种情况,需要进行额外处理。

本功能将SqlServer的空间数据类型转为字符串进行传输(插入更新时SqlServer会对字符串自动进行转换,MySQL则必须使用函数转为空间数据才可进行插入更新),后续通过类型处理器可将其转为几何类来方便计算。

总之呢,个人感觉用处不大,本文章仅为学习时的记录。毕竟要用空间数据类型的话,大多数时候都是需要使用空间函数的,所以,倒不如手写SQL还来的快速方便

  • 10
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值