SpringBoot之集成Mybatis踩的各种坑
0.概述
使用SpringBoot集成Mybatis曾经踩了各种坑,也花费了很久找解决方案才把坑填上.只是时间久了,很容易健忘,导致过一段时间就会出现,遇到同样的问题还是不得不花费时间去找解决方案.所以索性就一次把错误犯个遍,写一遍文章记录一下.
1.项目构建
使用SpringBoot搭建项目,由于是测试mybatis出现的错误,因此引入可以不引入web依赖.
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>demo</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.20</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
application.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: root
password: 123456
# 使用druid数据源
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
#mybatis:
mapper-locations: classpath:/mapper/*Mapper.xml
mysql数据库
这是转出的sql文件内容
/*
Navicat Premium Data Transfer
Source Server : test
Source Server Type : MySQL
Source Server Version : 80027
Source Host : localhost:3306
Source Schema : test
Target Server Type : MySQL
Target Server Version : 80027
File Encoding : 65001
Date: 14/03/2022 09:30:54
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(0) NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`pwd` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, '李四', '123456');
INSERT INTO `user` VALUES (2, '朱六', '123zhuliu');
SET FOREIGN_KEY_CHECKS = 1;
实体类
package com.example.demo.entity;
import lombok.Data;
@Data
public class User {
private Integer id;
private String name;
private String pwd;
}
Mapper
package com.example.demo.mapper;
import com.example.demo.entity.User;
public interface UserMapper {
public User getUserById(Integer id);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">
<select id="getUserById" resultType="com.example.demo.entity.User">
select * from user where id=#{id}
</select>
</mapper>
Service
接口:
package com.example.demo.service;
import com.example.demo.entity.User;
public interface UserService {
public User queryUserById(Integer id);
}
接口实现类:
package com.example.demo.service.impl;
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public User queryUserById(Integer id) {
return userMapper.getUserById(id);
}
}
测试类
package com.example.demo;
import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class Test {
@Autowired
private UserService userService;
@org.junit.jupiter.api.Test
public void testById(){
System.out.println("开始测试");
User user = userService.queryUserById(1);
System.out.println(user.toString());
}
}
2.踩坑
2.1 pom.xml文件踩坑
第一个坑就是pom.xml文件没配置资源插件,导致target目录下只有UserMapper.java,没有UaerMapper.xml
此时会出现什么呢?
注释调pom.xml中相关代码:
清理项目后重新编译运行,得到结果:
target下没有UserMapper文件,自然发现不了.
2.2 application.yml踩坑(此处无坑,是我学艺不精搞错了)
将注释去掉,配置好资源插件,接着踩application.yml的坑.
先清理再运行.
结果运行之后没有坑,好尴尬.
2.3 SpringBoot启动类未添加注解@MapperScan
运行结果:
2.4 ServiceImpl忘记加@Service注解
说起来这是一个低级错误,但是经常出现光顾着敲Service实现类的代码,忘记最后加上@Service注解;
将@Service注释:
运行结果:
报错信息为:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘com.example.demo.Test’: Unsatisfied dependency expressed through field ‘userService’; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type ‘com.example.demo.service.UserService’ available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
2.5 xxxxMapper.xml文件的内部错误
1.namespace对应的路径写错
详细报错信息:
org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. The XML location is 'com/example/demo/mapper/UserMapper.xml'. Cause: org.apache.ibatis.builder.BuilderException: Wrong namespace. Expected 'com.example.demo.mapper.UserMapper' but found 'com.example.mapper.UserMapper'.
提示信息很详细,相对容易排查.
2. 对应的映射结果类写错
报错信息:
org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. The XML location is 'com/example/demo/mapper/UserMapper.xml'. Cause: org.apache.ibatis.builder.BuilderException: Error resolving class. Cause: org.apache.ibatis.type.TypeException: Could not resolve type alias 'com.example.demo.entity.Users'. Cause: java.lang.ClassNotFoundException: Cannot find class: com.example.demo.entity.Users
3.sql标签中的id值与xxxMapper.java中的方法名对不上
4. sql语句有语法错误
报错信息:
org.springframework.jdbc.BadSqlGrammarException:
### Error querying database. Cause: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'id=1' at line 1
### The error may exist in com/example/demo/mapper/UserMapper.xml
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: select * from user wher id=?
### Cause: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'id=1' at line 1
; bad SQL grammar []; nested exception is java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'id=1' at line 1
5.可能犯得错误
6.使用Oracle可能出现错误
java.sql.SQLException: 不支持的字符集 (在类路径中添加 orai18n.jar): ZHS16GBK
在pom文件添加依赖:
<!-- 用于解决: uncategorized SQLException; SQL state [99999]; error code [17056]; 不支持的字符集 (在类路径中添加 orai18n.jar): ZHS16GBK; nested exception is java.sql.SQLException: 不支持的字符集 (在类路径中添加 orai18n.jar): ZHS16GBK] with root cause
java.sql.SQLException: 不支持的字符集 (在类路径中添加 orai18n.jar): ZHS16GBK -->
<!-- https://mvnrepository.com/artifact/com.oracle/orai18n -->
<dependency>
<groupId>com.oracle</groupId>
<artifactId>orai18n</artifactId>
<version>11.2.0.3</version>
</dependency>
参考CSDN博主「是夏天呀!」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_40555277/article/details/103139648
3.一些建议
使用Mybatis正确的步骤为:
-
在pom.xml配置资源插件,确保能够将xxxMapper.xml文件复制到target目录下
-
SpringBoot启动类一定要加@MapperScan注解
-
Service实现类不要忘记添加@Service注解
-
注意XXXMapper.xml文件的编写,不要写错namspace,映射的类名,注意resultMap,resultType,注意sql语句的id与方法名是否对应,注意sql与语法是否正确等等.
-
注意Oracle数据库出现java.sql.SQLException: 不支持的字符集 (在类路径中添加 orai18n.jar): ZHS16GBK,记得在pom文件中添加相关依赖,参考文章:https://blog.csdn.net/qq_40555277/article/details/103139648
-
建议安装mybatis插件,能够在一定程度上减少XXXMapper.xml文件的错误:
4.结语
以上内容是我遇到的SpringBoot整合Mybaits可能出现的问题,但不可能将所有的问题都罗列在内,以后根据需要再进行修改补充.最后想说一句编程中刚接触自己不会的技术,肯定会出现各种各样的问题,不要怕,勇敢试错,做好总结,最终总能掌握.