Mybatis Common Mapper常见问题解答:StackOverflow精选

Mybatis Common Mapper常见问题解答:StackOverflow精选

【免费下载链接】Mapper Mybatis Common Mapper - Easy to use 【免费下载链接】Mapper 项目地址: https://gitcode.com/gh_mirrors/ma/Mapper

引言

你是否在使用Mybatis Common Mapper时遇到过各种令人头疼的异常?是否在StackOverflow上苦苦搜索却找不到满意的答案?本文精选了Mybatis Common Mapper开发中最常见的10个问题,提供专业、详细的解决方案和代码示例,帮助你快速解决开发难题。

读完本文,你将能够:

  • 解决多@Id注解导致的MapperException异常
  • 正确配置@Table注解实现实体类与数据库表映射
  • 处理@Version乐观锁注解使用中的常见问题
  • 解决LogicDelete逻辑删除功能的实现问题
  • 掌握KeySql注解的正确使用方法
  • 解决mapperLocations配置路径问题
  • 解决MapperScannerConfigurer配置错误
  • 解决继承通用Mapper接口时的类型参数问题
  • 解决Example查询中的条件构造问题
  • 解决批量操作中的性能问题

1. 多@Id注解导致的MapperException异常

问题描述

在实体类中使用多个@Id注解时,调用deleteByIds或selectByIds方法会抛出MapperException异常:"继承 deleteByIds 方法的实体类[...]中必须只有一个带有 @Id 注解的字段"。

解决方案

Mybatis Common Mapper要求继承deleteByIds或selectByIds方法的实体类只能有一个@Id注解字段。如果需要使用联合主键,应该实现自定义的批量操作方法。

代码示例

错误示例:

public class UserLogin {
    @Id
    private Integer userId;
    
    @Id
    private String username;
    // getter和setter
}

正确示例(单主键):

public class User {
    @Id
    private Integer id;
    private String username;
    // getter和setter
}

联合主键解决方案:

// 1. 创建复合主键类
public class UserLoginKey implements Serializable {
    private Integer userId;
    private String username;
    // getter、setter和equals、hashCode方法
}

// 2. 在实体类中使用@IdClass注解
@IdClass(UserLoginKey.class)
public class UserLogin {
    @Id
    private Integer userId;
    
    @Id
    private String username;
    // 其他字段和getter、setter
}

// 3. 自定义批量操作方法
public interface UserLoginMapper extends Mapper<UserLogin> {
    // 自定义批量删除方法
    int deleteByIds(@Param("ids") List<UserLoginKey> ids);
}

2. @Table注解配置问题

问题描述

实体类使用@Table注解后,仍然无法正确映射到数据库表,导致SQL语句中表名错误。

解决方案

正确配置@Table注解的name属性,确保与数据库表名一致。如果表名包含特殊字符或关键字,需要使用反引号`包裹。

代码示例

正确示例1:基本用法

@Table(name = "user_info")
public class UserInfo {
    @Id
    private Integer id;
    private String username;
    // getter和setter
}

正确示例2:包含特殊字符的表名

@Table(name = "`user`") // 当表名为关键字时使用反引号
public class User {
    @Id
    private Integer id;
    private String username;
    // getter和setter
}

正确示例3:schema和catalog配置

@Table(name = "user", schema = "public", catalog = "testdb")
public class User {
    @Id
    private Integer id;
    private String username;
    // getter和setter
}

3. @Version乐观锁注解使用问题

问题描述

使用@Version注解实现乐观锁时,抛出"中包含多个带有 @Version 注解的字段,一个类中只能存在一个带有 @Version 注解的字段!"异常,或更新操作未触发版本检查。

解决方案

确保实体类中只有一个@Version注解字段,并且该字段的类型正确。同时,在更新操作中必须包含版本字段。

代码示例

正确示例:

public class User {
    @Id
    private Integer id;
    private String username;
    
    @Version
    private Integer version; // 版本号字段,支持Integer、Long、Timestamp等类型
    
    // getter和setter
}

// 使用示例
public void updateUser(UserMapper userMapper, User user) {
    try {
        int rows = userMapper.updateByPrimaryKeySelective(user);
        if (rows == 0) {
            throw new OptimisticLockException("更新失败,数据已被其他用户修改");
        }
    } catch (Exception e) {
        // 异常处理
    }
}

4. LogicDelete逻辑删除功能问题

问题描述

实现逻辑删除功能后,调用delete方法并未更新逻辑删除字段,而是执行了物理删除。

解决方案

使用@LogicDelete注解标记逻辑删除字段,并确保实体类对应的Mapper接口继承了正确的通用Mapper。

代码示例

实体类示例:

@Table(name = "tb_user")
public class TbUserLogicDelete {
    @Id
    private Long id;
    private String username;
    private String password;
    
    @LogicDelete(value = "1", delval = "0")
    private Integer isValid; // 逻辑删除字段,1表示有效,0表示删除
    
    // getter和setter
}

Mapper接口示例:

public interface TbUserLogicDeleteMapper extends Mapper<TbUserLogicDelete> {
    // 继承通用Mapper接口
}

使用示例:

public void testLogicDelete() {
    SqlSession sqlSession = getSqlSession();
    try {
        TbUserLogicDeleteMapper logicDeleteMapper = sqlSession.getMapper(TbUserLogicDeleteMapper.class);
        TbUserLogicDelete tbUserLogicDelete = new TbUserLogicDelete();
        tbUserLogicDelete.setUsername("test");
        
        // 执行逻辑删除,实际上会执行UPDATE语句更新isValid字段
        Assert.assertEquals(1, logicDeleteMapper.delete(tbUserLogicDelete));
    } finally {
        sqlSession.close();
    }
}

5. KeySql注解使用问题

问题描述

使用@KeySql注解生成主键时,出现主键值未正确生成或生成策略不符合预期的问题。

解决方案

根据数据库类型和主键生成策略,正确配置@KeySql注解的属性。

代码示例

示例1:使用数据库自增主键

public class UserAutoIncrement {
    @Id
    @KeySql(useGeneratedKeys = true) // 使用数据库自增主键
    private Integer id;
    private String username;
    // getter和setter
}

示例2:使用特定数据库的IDENTITY生成器

public class UserAutoIncrementIdentity {
    @Id
    @KeySql(dialect = IdentityDialect.MYSQL) // 指定数据库方言
    private Integer id;
    private String username;
    // getter和setter
}

示例3:使用SQL语句生成主键

public class UserSqlBefore {
    @Id
    @KeySql(sql = "select 12345", order = ORDER.BEFORE) // 插入前执行SQL获取主键
    private Integer id;
    private String username;
    // getter和setter
}

public class UserSqlAfter {
    @Id
    @KeySql(sql = "SELECT LAST_INSERT_ID()", order = ORDER.AFTER) // 插入后执行SQL获取主键
    private Integer id;
    private String username;
    // getter和setter
}

示例4:使用自定义主键生成器

public class Country {
    @Id
    @KeySql(genId = SimpleGenId.class) // 使用自定义主键生成器
    private String id;
    private String name;
    // getter和setter
}

// 自定义主键生成器
public class SimpleGenId implements GenId<String> {
    @Override
    public String genId(String table, String column) {
        return UUID.randomUUID().toString().replace("-", "");
    }
}

6. mapperLocations配置路径问题

问题描述

在Spring或Spring Boot配置中,设置mapperLocations属性后,Mybatis无法找到映射文件,导致绑定异常。

解决方案

正确配置mapperLocations路径,确保能匹配到所有的Mapper XML文件。注意路径中的通配符使用和资源文件的实际位置。

代码示例

Spring Boot配置示例:

mybatis:
  mapper-locations: classpath*:tk/mybatis/mapper/xml/**/*.xml

Spring配置示例:

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="mapperLocations" value="classpath*:tk/mybatis/mapper/xml/**/*.xml" />
</bean>

正确的资源文件目录结构:

src/main/resources/
  tk/
    mybatis/
      mapper/
        xml/
          CountryMapper.xml
          UserMapper.xml

7. MapperScannerConfigurer配置错误

问题描述

配置MapperScannerConfigurer后,Spring无法扫描到Mapper接口,导致@Autowired注入失败。

解决方案

正确配置MapperScannerConfigurer的basePackage属性,确保覆盖所有Mapper接口所在的包。同时注意使用tk.mybatis.spring.mapper.MapperScannerConfigurer而非MyBatis原生的类。

代码示例

Spring配置示例:

<bean class="tk.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="tk.mybatis.mapper" />
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
    <property name="markerInterface" value="tk.mybatis.mapper.common.Mapper" />
</bean>

Spring Boot注解配置示例:

@SpringBootApplication
@MapperScan(basePackages = "tk.mybatis.mapper", markerInterface = Mapper.class)
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

8. 继承通用Mapper接口时的类型参数问题

问题描述

创建Mapper接口继承通用Mapper时,如果类型参数指定错误,会导致编译错误或运行时异常。

解决方案

确保Mapper接口正确指定了泛型参数,即实体类类型。

代码示例

正确示例:

public interface CountryMapper extends Mapper<Country> {
    // 继承通用Mapper接口,指定实体类类型
}

public interface UserMapper extends Mapper<User>, MySqlMapper<User> {
    // 同时继承多个通用接口
}

错误示例:

public interface CountryMapper extends Mapper {
    // 错误:未指定泛型参数
}

public interface UserMapper extends Mapper<Long> {
    // 错误:泛型参数应为实体类类型,而非基本类型
}

9. Example查询中的条件构造问题

问题描述

使用Example进行复杂条件查询时,出现查询条件不正确或无法构造复杂SQL的问题。

解决方案

正确使用Example和Criteria构造查询条件,注意不同条件方法的正确调用顺序和组合方式。

代码示例

基本查询示例:

public List<Country> selectByExample() {
    Example example = new Example(Country.class);
    example.createCriteria()
           .andEqualTo("continent", "Asia")
           .andLike("name", "%China%");
           
    // 添加排序条件
    example.orderBy("population").desc();
    
    return countryMapper.selectByExample(example);
}

复杂OR条件示例:

public List<Country> selectWithOrCondition() {
    Example example = new Example(Country.class);
    Example.Criteria criteria1 = example.createCriteria()
                                       .andEqualTo("continent", "Asia")
                                       .andGreaterThan("population", 100000000);
                                       
    Example.Criteria criteria2 = example.createCriteria()
                                       .andEqualTo("continent", "Europe")
                                       .andLike("name", "%United%");
                                       
    example.or(criteria2); // 使用OR组合两个条件
    
    return countryMapper.selectByExample(example);
}

Between条件示例:

public List<Country> selectWithBetween() {
    Example example = new Example(Country.class);
    example.createCriteria()
           .andBetween("population", 10000000, 100000000);
           
    return countryMapper.selectByExample(example);
}

10. 批量操作中的性能问题

问题描述

使用通用Mapper的批量操作方法时,遇到性能问题或内存溢出。

解决方案

对于大量数据的批量操作,应该使用分批处理的方式,避免一次性加载过多数据到内存。同时可以考虑使用Mybatis的BatchExecutor提高性能。

代码示例

分批插入示例:

public void batchInsertUsers(List<User> userList, int batchSize) {
    SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    
    try {
        for (int i = 0; i < userList.size(); i++) {
            userMapper.insert(userList.get(i));
            
            if ((i + 1) % batchSize == 0) {
                sqlSession.flushStatements();
                sqlSession.clearCache();
            }
        }
        sqlSession.commit();
    } catch (Exception e) {
        sqlSession.rollback();
        throw e;
    } finally {
        sqlSession.close();
    }
}

使用InsertListMapper批量插入:

public interface UserMapper extends Mapper<User>, InsertListMapper<User> {
    // 继承InsertListMapper接口获得批量插入能力
}

public void batchInsertUsingInsertList(List<User> userList) {
    // InsertListMapper提供的insertList方法
    userMapper.insertList(userList);
}

总结

本文详细介绍了Mybatis Common Mapper开发中10个常见问题的解决方案,涵盖了注解使用、配置问题、查询构造和性能优化等方面。掌握这些解决方案可以帮助你快速解决开发中的大部分问题,提高开发效率。

Mybatis Common Mapper作为一个功能强大的MyBatis增强工具,还有很多高级特性值得探索。建议深入阅读官方文档,了解更多最佳实践和性能优化技巧。

附录:常见异常及其解决方案对照表

异常信息解决方案
"继承 deleteByIds 方法的实体类[...]中必须只有一个带有 @Id 注解的字段"确保实体类中只有一个@Id注解字段,联合主键场景需自定义批量操作方法
"类 [...] 不包含属性 [...],或该属性被@Transient注释!"检查Example查询中使用的属性名是否与实体类一致,确保没有被@Transient注解
"中包含多个带有 @Version 注解的字段"确保实体类中只有一个@Version注解字段
"not found for parameter: entity"检查Mapper接口方法参数是否正确,确保使用@Param注解指定参数名
"Could not find value method on SQL annotation. Cause: java.lang.reflect.InvocationTargetException"检查@SelectProvider等注解的方法是否正确实现

希望本文能帮助你解决Mybatis Common Mapper使用中的常见问题。如果有其他问题或解决方案,欢迎在评论区分享交流!

【免费下载链接】Mapper Mybatis Common Mapper - Easy to use 【免费下载链接】Mapper 项目地址: https://gitcode.com/gh_mirrors/ma/Mapper

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值