Mybatis大杂烩

SpringBoot版本:2.5.4

Mybatis版本:2.2.0

Mysql版本:8.0

1.@mapper和@mapperscan。二者的作用是一样的,mapper用在单个mapper接口上,mapperscan用在程序入口类上,如果不想在每个mapper上加@mapper,就直接在程序的入口类上加@mapperscan,如下:

2.mybatis自动生成的mapper.xml文件需要在application.properties里配置一下,才能正确加载:

mybatis.mapper-locations=classpath:/mapper/*.xml(写在application.properties里面)

否则会报错:Invalid bound statement (not found)

3.mybatis有个对应的库叫mybatis-generate,它是一个自动根据数据库生成mapper的工具,它同时也会生成一个叫example的东西,这个是自动生成sql条件语句用的,这样就可以减少sql语句的编写,比较冷门。

4.mybatis如何支持json类型,如果你的实体类里面有个字段是类对象,你希望在进行数据库存储的时候,把该实体类转化为json类型存放到数据库,那么你需要提供一个typehandler:

@MappedJdbcTypes(JdbcType.JAVA_OBJECT)
public class ObjectJsonHandler extends BaseTypeHandler<DataEntity> {
    Gson gson=new Gson();
    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, 
int i, DataEntity 
dataEntity, JdbcType jdbcType) throws SQLException {
        //写入数据库时,转为json
        preparedStatement.setObject(i,gson.toJson(dataEntity));
    }

    @Override
    public DataEntity getNullableResult(ResultSet resultSet, String s) 
throws SQLException {
        //查询数据时,转为对象
        String ret=resultSet.getString(s);
        if (ret==null) return null;
        return gson.fromJson(ret,DataEntity.class);
    }

    @Override
    public DataEntity getNullableResult(ResultSet resultSet, int i) 
throws SQLException {
        return null;
    }

    @Override
    public DataEntity getNullableResult(CallableStatement callableStatement, int i) 
throws SQLException {
        return null;
    }
}

这里的jdbcType是JAVA_OBJECT,这个类型我看官方的文档并没有,估计是后来新增的。同时我用的mysql数据库是8.0版本的,早期的版本并不支持json,较新的版本是支持的。

写好typehandler之后,xml的resultMap要这么配置:

// 其他的配置这里省略    
<resultMap id="BaseResultMap" type="com.camjy.datacloud.entity.DeviceDataEntity">
        <result column="data" property="data" jdbcType="JAVA_OBJECT" 
javaType="java.lang.Object" typeHandler="com.test.ObjectJsonHandler"/>
</resultMap>

sql语句这么写:

<insert id="insertData" parameterType="com.camjy.datacloud.entity.DeviceDataEntity">
    insert into data_table(data)
    VALUES (#{data,typeHandler=com.test.ObjectJsonHandler});
</insert>

5.mybatis-generate里面example类型强制转换的问题,这个比较冷门,不推荐用。这里有些字段的类型比较特殊,比如id经常用uuid,这个时候生成的sql语句要加上::uuid才行(postgresql语法),但是example不直接支持增加类型强制转换,这里我想到的解决办法是修改mybatis自动生成的源代码,方法如下:

a)首先要在example文件里面找到Criterion这个类,在里面加上一个属性property,这个是用来标识你的属性名的,根据你的属性名来判断哪些地方需要加上强制转换。

private String property;

public String getProperty() {
    return property;
}

public void setProperty(String property) {
    this.property = property;
}

b)然后修改特殊类型字段条件方法,比如我用的数据库是postgresql,而我的id是uuid类型的。最初mybatis生成的方法是这样的

public Criteria andIdNotEqualTo(String value) {
    addCriterion("id <>", value, "id");
    return (Criteria) this;
}

这个方法是给sql加上id不等于某个值的条件,因为我传进去的是字符串,如果不加::uuid转换,数据库会报错。既然我们已经把属性名id传进去了,所以我们修改一下addCriterion这个方法,它原本是这样的

protected void addCriterion(String condition, Object value, String property) {
    if (value == null) {
        throw new RuntimeException("Value for " + property + " cannot be null");
    }
    Criterion criterion=new Criterion(condition, value);
    criteria.add(criterion);
}

我们加一句: criterion.setProperty(property);让它变成这样

protected void addCriterion(String condition, Object value, String property) {
    if (value == null) {
        throw new RuntimeException("Value for " + property + " cannot be null");
    }
    Criterion criterion=new Criterion(condition, value);
    criterion.setProperty(property);
    criteria.add(criterion);
}

c)这个时候,传给mapper.xml的Criterion 就带有属性名了,然后把mapper.xml里面的Example_Where_Clause,或者其他用到example的语句改一下,改成这样

<when test="criterion.singleValue and criterion.property=='id'">
  and ${criterion.condition} #{criterion.value}::uuid
</when>
<when test="criterion.singleValue and criterion.property!='id'">
  and ${criterion.condition} #{criterion.value}
</when>

你会注意到我这里面加了一个判断:and criterion.property=='id',也就是说当属性是id的时候,我要给语句sql上加一个::uuid的转换。其他的则不加。这样,就解决了example特殊类型转换的问题了。当然,更复杂的逻辑,可能xml里面的条件判断要复杂一些。然后你再使用example的时候还像原来那样正常使用就可以了:

UserExample example = new UserExample();
example.createCriteria().andIdNotEqualTo(user.getId());
int count = userMapper.countByExample(example);

6.restful风格的接口允许传null值进来的问题。这个问题的解决方式是用map接收body,而不再是实体类。如果你用实体类接收,那么你就无法区分是用户传给了你null,还是因为用户没有传导致的null值了。用map接收则没有这个问题,你可以判断map中是否包含这个key,如果包含就表示用户要修改,如果不包含,就表示用户不打算修改,至于所传的值是不是null,你则不需要关心。这样的话,mybatis的mapper应该像下面这么写:

<update id="updateTest" parameterType="Map">
  update public.status
  <set>
    <if test="_parameter.containsKey('name')">
      name = #{name,jdbcType=VARCHAR},
    </if>
    <if test="_parameter.containsKey('remarks')">
      remarks = #{remarks,jdbcType=VARCHAR},
    </if>
  </set>
  where id = #{id,jdbcType=VARCHAR}
</update>

判断是否包含该键,如果包含则更新。

7.一个xml配置里面同时执行多条语句,这个需要在application.properties里面进行配置,在数据库连接字符串上增加allowMultiQueries=true:

spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test?allowMultiQueries=true

然后,你xml的sql语句里面用逗号隔开不同的语句就行了,如下:

<insert id="test" parameterType="com.test.TestEntity">
    update test_table set time=#{time} where id=#{id};
    insert into test_table(time) VALUES(#{time});
</insert>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值