友情提醒,阅读本文前,可以先阅读​​Mybatis系列总结1​​。

There is no getter for property named ‘ids’ in ‘class java.lang.String’

比较具体的报错信息为:

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'ids' in 'class java.lang.String'

@Options

insert后获取主键

首先,想要获取的注解,名字随意,可能不叫​​id​​​,但是必须要确保设置为​​auto_increment​​​。
代码层:
​​​int num = dashboardCategoryMapper.insert(dashboardCategory);​

<insert id="insert" parameterType="com.xy.cloudiview.common.model.DashboardCategory"
useGeneratedKeys="true" keyProperty="categoryId" keyColumn="category_id">
insert into category (category_name, user_id,
type, update_user_name, parent_id)
values (#{categoryName,jdbcType=VARCHAR}, #{userId,jdbcType=VARCHAR},
#{type,jdbcType=INTEGER}, #{updateUserName,jdbcType=VARCHAR}, #{parentId,jdbcType=BIGINT})
</insert>

然后在代码层:​​dashboardCategory.getCategoryId()​​获取主键,而不是num,num永远都是1,表示影响的记录数。

​#{}​​​和​​${}​​的区别

  1. ​#{}​​​相当于对数据加上双引号,​​${}​​相当于直接显示数据;
  2. ​#{}​​​能够很大程度上防止SQL注入,而​​${}​​则不能;
  3. ​${}​​方式一般应用于传入数据库对象,如表名;
  4. 一般能用​​#{}​​​的地方不要使用​​${}​​;
  5. 动态排序时,​​order by column​​​,只能使用​​${}​​​;如果使用​​#{}​​​,拼接得到的SQL会加上引号,如​​order by 'dataset_id'​​,执行会报错:
  6. Mybatis系列总结2_sql

Mapper method attempted to return null from a method with a primitive return type (int).

报错查询语句如下:

int checkLastViewTime(Long widgetId);
<select id="checkLastViewTime" resultType="java.lang.Integer">
SELECT datediff(now(), last_view_time)
FROM widget
WHERE isactive = 1
AND widget_id = #{widgetId}
</select>

原因很容易定位到

Mybatis系列总结2_sql_02


一开始如下更改:

Mybatis系列总结2_sql_03


结果还是报同样的错误信息。参考:​​解决方案​​,将Dao接口类里面的方法改成包装类型即可,ifnull完全没有效果:

Mybatis系列总结2_mybatis_04

@SelectKey

先看源码,mybatis-3.4.6:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SelectKey {
String[] statement();

// selectKey 语句结果应该被设置的目标属性。
String keyProperty();

String keyColumn() default "";

// true:首先选择主键,设置 keyProperty 然后执行插入语句;
// false:先执行插入语句,然后是 selectKey 元素-这和 Oracle 数据库相似,可以在插入语句中嵌入序列调用。
boolean before();

// 结果的类型。MyBatis 通常可以算出来,但是写上也没有问题。MyBatis 允许任何简单类型用作主键的类型,包括字符串。
Class<?> resultType();

// MyBatis 支持 STATEMENT ,PREPARED 和CALLABLE 语句的映射类型,分别代表 PreparedStatement 和CallableStatement 类型。
StatementType statementType() default StatementType.PREPARED;
}

StatementType枚举类:

public enum StatementType {
STATEMENT, PREPARED, CALLABLE
}

SelectKey在Mybatis中是为了解决Insert数据时不支持主键自动生成的问题,可以很随意的设置生成主键的方式。SelectKey需要注意order属性,像MySQL一类支持自动增长类型的数据库中,order需要设置为after才会取到正确的值。像Oracle这样取序列的情况,需要设置为before,否则会报错。
有用于mapper.xml 以及mapper接口中两种形式。
例子:

<insert id="insert" parameterType="map">
insert into table1 (name) values (#{name})
<selectKey resultType="java.lang.Integer" keyProperty="id">
CALL IDENTITY()
</selectKey>
</insert>

xml的传入参数是map,selectKey会将结果放到入参数map中。用POJO的情况一样,keyProperty对应的字段在POJO中必须有相应的setter方法,setter的参数类型还要一致,否则会报错。

@Insert("insert into table2 (name) values(#{name})")
@SelectKey(statement="call identity()", keyProperty="nameId", before=false, resultType=int.class)
int insertTable2(Name name);

MyBatis-PageHelper

官网:https://github.com/pagehelper/Mybatis-PageHelper
通用的分页插件,使用时 Mybatis 最低版本不能低于3.3。
原理:通过 AOP 在截获执行 SQL 时把相关的数据再执行一次。使用时,maven dependency需要添加的依赖包括:pagehelper、mybatis-paginator、jsqlparser。同时在spring配置文件添加:

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations" value="classpath*:mappers/*Mapper.xml"></property>
<!-- 分页插件 -->
<property name="plugins">
<array>
<bean class="com.github.pagehelper.PageHelper">
<property name="properties">
<value>
<!-- 数据库方言 -->
dialect=mysql
</value>
</property>
</bean>
</array>
</property>
</bean>

Mybatis配置多个分页插件

<plugins>
<plugin interceptor="org.mybatis.pagination.PaginationInterceptor">
<property name="dbms" value="mysql"/>
<property name="sqlRegex" value=".*Paging.*"/>
</plugin>
<plugin interceptor="com.github.pagehelper.PageHelper">
<!--配置数据库方言 -->
<property name="dialect" value="mysql"/>
<!--<property name="offsetAsPageNum" value="false"/>-->
<!--<property name="rowBoundsWithCount" value="false"/>-->
<!--<property name="pageSizeZero" value="true"/>-->
<!--<property name="reasonable" value="false"/>-->
<!--<property name="supportMethodsArguments" value="false"/>-->
<!--<property name="returnPageInfo" value="none"/>-->
</plugin>
</plugins>

Mybatis IDEA 插件

作为应用最广泛的两个ORM框架之一,Mybatis有其成功之处,不过也有麻烦的时候,此时配上IDEA的mybatis插件,能够大大提升开发效率。

MyBatisCodeHelper

IDEA下代码自动生成插件,支持生成Mybatis的dao接口,mapper xml和建表SQL,支持直接从接口方法名直接生成SQL。关于插件的使用,​​这里​​有很详细的介绍,支持的特性包括但不限于:

  • 根据数据库对象一键生成 Dao接口,Service,Xml,数据库建表SQL文件提供dao与xml的跳转;
  • 根据dao中的方法名生成对应的mapper SQL并进行方法补全;
  • Mybatis接口方法名重构支持;

安装:
idea常规的插件安装方式,会发现找不到该插件。倒是可以搜索到MyBatisCodeHelperPro,意思很明显,是升级版,需要付费或者破解之后才可以使用。看来并不是完全开源的。故而可以转向使用下面的插件,功能差不多都是类似的,足够日常开发;付费的高级功能如果要用到时可以尝试破解或者掏钱。

MyBatis plugin

很重的插件,最新版13.7M;
官网https://www.codesmagic.com/,有很多强大的功能,暂时还没有试用。

Free MyBatis plugin

MyBatisX

对应的框架是MyBatis-plus,有待试用。

参考

​Mybatis的@Options注解​​​​Mybatis 示例之 SelectKey​​​​Mybatis中的@SelectKey注解​​​​MyBatisCodeHelper​​​​mybatis-how-to-get-the-auto-generated-key-of-an-insert-mysql​