spring boot整合mybatis jpa异常情况汇总及解决办法

mybatis整合后,不需要写业务接口的实现类,

1、application.yml配置文件:

type-aliases-package作用

在Mybatis的mapper.xml文件中resultType的type或者paramterType会返回自定义entity,此时可以用全类名名来指定这些实体。可以使用type-aliases-package中指定entity扫描包类让mybatis自定扫描到自定义的entity。这样就不用全名指定了,只用类型即可。

  • 配置多个别用只需要用逗号“,”隔开就行,当然上面是以 XML 为例,YML 或 Properties 文件配置同理可得~

mybatis配置打印sql语句

resources/mapper/*Mapper.xml配置文件通用头部

2、repository/UserRepository.java接口

3、resources/mapper/UserRepositoryMapper.xml动态代理实现类需要此文件

4、cotroller/UserController.java 控制类,注入UserRepository接口@Autowired

5、启动类application上加入@MapperScan("com.example.demo.repository")

controller类和及方法上的@RequestMapping("")不能省略,需要写上路由路径。

使用接口操作即可。总结起来需要以上5步。

 

异常:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSessionFactory' defined in class path resource [org/mybatis/spring/boot/autoconfigure/MybatisAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.apache.ibatis.session.SqlSessionFactory]: Factory method 'sqlSessionFactory' threw exception; nested exception is java.io.FileNotFoundException: class path resource [mapping/*.xml] cannot be opened because it does not exist

原因是application.yml的mapper-location没有配置,或配置不正确,原因是上把mapper-locations写成config-location: classpath:/mapper/*.xml,正确的写法是:mapper-locations: classpath:/mapper/*.xml

异常:Web server failed to start. Port 8080 was already in use.

结束任务java.exe进程,重新启动程序。

异常:Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.example.springbootmybatis.repository.StudentRepository.findById] with root cause

原因:在mapper.xml中没有指定为命名空间是错误的,必须是接口的命名空间全称+接口名,正确如下:

namespace="com.example.springbootmybatis.repository.StudentRepository"这个必须为全称,如果光写成命名空间是错误的namespace="com.example.springbootmybatis.repository"

错误提示:

has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0 at java.lang.ClassLoader.defineClass1(Native Method)

a more recent version of the Java Runtime (class file version 55.0), .......file versions up to 52.0

55版本代表是jdk11,而52版本是jdk1.8或jdk8

运行cmd查看java -version查看java版本,如果是1.8的话,在环境变量设计jdk的路径为11版本,重启计算机。


template might not exist or might not be accessible by any of the configured Template Resolvers

org.thymeleaf.exceptions.TemplateInputException: Error resolving template [/student/index], template might not exist or might not be accessible by any of the configured Template Resolv
ers

主要问题是视图映射路径有误(在idea里编译运行时正常,发布后提示错误):

正确的如下:

 可见不要随便加绝对路径。

jpa getById()出现返回类型给api方法时出现异常:

ERROR 6676 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.example.springbootjpa.entity.Student$HibernateProxy$ruEXYU94["hibernateLazyInitializer"])] with root cause

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.example.springbootjpa.entity.Student$HibernateProxy$ruEXYU94["hibernateLazyInitializer"])

分析:主要原因是getById(id)或getOne(id)(已经过时弃用),因为它返回的是一个引用,简单点说就是一个代理对象,无论找到与否,总会有返回值,另外实体对象中可能存在空值,所以出现异常。

解决办法:一种办法是使用findById(id).get()替代,另一种办法是:在实体或bean类上面加上注解

异常:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'bookController': Unsatisfied dependency expressed through field 'bookRepository'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'bookRepository' defined in com.example.springbootjpa.repository.BookRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not a managed type: class com.example.springbootjpa.entity.Book

主要原因是没有在实体上加注解

@Entity

另外注意bookName不加column,会以表字段book_name生成

JPA的注解来定义实体的时候,使用@Id来注解主键属性即可。如果数据库主键是自增长的,需要在增加一个注解@GeneratedValue,即:

 

PS:@GeneratedValue注解的strategy属性提供四种值:

–AUTO: 主键由程序控制,是默认选项,不设置即此项。

–IDENTITY:主键由数据库自动生成,即采用数据库ID自增长的方式,Oracle不支持这种方式。

–SEQUENCE:通过数据库的序列产生主键,通过@SequenceGenerator 注解指定序列名,mysql不支持这种方式。

–TABLE:通过特定的数据库表产生主键,使用该策略可以使应用更易于数据库移植。

 

Spring Data JPA 可以理解为 JPA 规范的再次封装抽象,底层还是使用了 Hibernate 的技术实现。

Spring Data JPA是在实现了JPA规范的基础上封装的一套 JPA 应用框架,虽然ORM框架都实现了JPA规范,但是在不同的ORM框架之间切换仍然需要编写不同的代码,而使用Spring Data JPA能够方便大家在不同的ORM框架之间进行切换而不需要更改代码。Spring Data JPA旨在通过将统一ORM框架的访问持久层的操作,来提高开发人的效率。

如图:

3、Spring Data JPA 相关接口:

Repository:仅仅只是一个标识,没有任何方法,方便Spring自动扫描识别

CrudRepository:继承Repository,实现一组CRUD相关方法

PagingAndStortingRepository:继承CrudRepository,实现一组分页排序相关方法

JpaRepository:继承PagingAndStortingRepository,实现一组JPA规范方法

4、Spring Data JPA 自定义接口约定命名规则:

关键字 例子 对应的JPQL语句
And findByLastnameAndFirstname … where x.lastname = ?1 and x.firstname = ?2
Or findByLastnameOrFirstname … where x.lastname = ?1 or x.firstname = ?2
Is,Equals findByFirstname,findByFirstnameIs,findByFirstnameEquals … where x.firstname = ?1
Between findByStartDateBetween … where x.startDate between ?1 and ?2
LessThan findByAgeLessThan … where x.age < ?1
LessThanEqual findByAgeLessThanEqual … where x.age ?1
GreaterThan findByAgeGreaterThan … where x.age > ?1
GreaterThanEqual findByAgeGreaterThanEqual … where x.age >= ?1
After findByStartDateAfter … where x.startDate > ?1
Before findByStartDateBefore … where x.startDate < ?1
IsNull findByAgeIsNull … where x.age is null
IsNotNull,NotNull findByAge(Is)NotNull … where x.age not null
Like findByFirstnameLike … where x.firstname like ?1
NotLike findByFirstnameNotLike … where x.firstname not like ?1
StartingWith findByFirstnameStartingWith … where x.firstname like ?1 (parameter bound with appended %)
EndingWith findByFirstnameEndingWith … where x.firstname like ?1 (parameter bound with prepended %)
Containing findByFirstnameContaining … where x.firstname like ?1 (parameter bound wrapped in %)
OrderBy findByAgeOrderByLastnameDesc … where x.age = ?1 order by x.lastname desc
Not findByLastnameNot … where x.lastname <> ?1
In findByAgeIn(Collection ages) … where x.age in ?1
NotIn findByAgeNotIn(Collection age) … where x.age not in ?1
True findByActiveTrue() … where x.active = true
False findByActiveFalse() … where x.active = false
IgnoreCase findByFirstnameIgnoreCase

5、Spring JPA自定义接口解析步骤:

在进行方法名解析时会先去掉多余的前缀,比如find、findBy、read、readBy、get、getBy,然后对剩下部分进行解析,并且如果方法最后一个参数时 Sort 或 Pageable 类型,也会提取相关信息。

比如:findByNameLikeAndAgeGreaterThan

 

剔除findBy

判断nameLikeAndAgeGreaterThan(根据POJO规范,首字母变小写)是否为返回对象 User 的一个属性,如果是,则根据该属性进行查询,如果没有该属性,则进行下一步

从右往左截取第一个大写字母开头的字符串(此处为Than),然后检查剩下的字符串是否为 User 的一个属性,如果是,则根据该属性进行查询,否则重复第2步,直到找出 name 为 User 的属性

从已截取的部分后面开始,重新第 1 步开始(剔除条件语句),循环,直到把方法名处理完毕

通过获取的操作、条件和属性、带入参数值,生成查询。

 

二、Spring JPA 配置项

在SpringBoot中,Hibernate的相关配置都保存在HibernateProperties,它配置了ConfigurationProperties注解,会自动装载前缀为spring.jpa.hibernate的配置。

1、常用配置项

spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=update

# 是否开启JPA Repositories,缺省: true
spring.data.jpa.repositories.enabled=true

# JPA数据库类型,默认可以自动检测,也能通过设置spring.jpa.database-platform达到同样效果
spring.jpa.database=ORACLE

# 数据库平台,常见的值如:
# org.hibernate.dialect.Oracle10gDialect
# org.hibernate.dialect.MySQL5InnoDBDialect
#下文有详细介绍
spring.jpa.database-platform=org.hibernate.dialect.Oracle12cDialect

# 是否使用JPA初始化数据库,可以在启动时生成DDL创建数据库表,缺省为false
spring.jpa.generate-ddl = false

# 更细粒度的控制JPA初始化数据库特性,用来设定启动时DDL操作的类型,下文有详细介绍
# 内嵌数据库 hsqldb, h2, derby的缺省值为create-drop
# 非内嵌数据库的缺省值为none
spring.jpa.hibernate.ddl-auto = update

# Hibernate操作时显示真实的SQL, 缺省:false
spring.jpa.show-sql = true

# Hibernate 5 隐含命名策略类的全限定名
spring.jpa.hibernate.naming.implicit-strategy= org.hibernate.boot.model.naming.ImplicitNamingStrategyComponentPathImpl

# Hibernate 5 物理命名策略类的全限定名
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

# Use Hibernate's newer IdentifierGenerator for AUTO, TABLE and SEQUENCE.
spring.jpa.hibernate.use-new-id-generator-mappings=

# 额外设置JPA配置属性,通常配置项是特定实现支持的,如Hibernate常有下面的几条配置项
spring.jpa.properties.* =

# 将SQL中的标识符(表名,列名等)全部使用引号括起来
spring.jpa.properties.hibernate.globally_quoted_identifiers=true

# 日志记录执行的SQL
spring.jpa.properties.hibernate.show_sql = true

# 是否将格式化SQL日志
spring.jpa.properties.hibernate.format_sql = true

# 是否注册OpenEntityManagerInViewInterceptor. 绑定JPA EntityManager 到请求线程中. 默认为: true.
spring.jpa.open-in-view=true

(1)、spring.jpa.hibernate.ddl-auto 配置

该配置的主要作用是:自动创建、更新、验证数据库表结构,该参数的几种配置如下:

ddl-auto:create----每次运行该程序,没有表格会新建表格,表内有数据会清空

ddl-auto:create-drop----每次程序结束的时候会清空表

ddl-auto:update----每次运行程序,没有表格会新建表格,表内有数据不会清空,只会更新

ddl-auto:validate----运行程序会校验数据与数据库的字段类型是否相同,不同会报错
create会先删除表再建表,请慎用!

create: 每次加载 hibernate 时都会删除上一次生成的表,然后根据 modle 类再重新生成新表,哪怕两次没有任何改变也要这样执行。这也是导致数据库表数据丢失的一个重要原因。

create-drop :每次加载 hibernate 时根据 modle 类生成表,但是SessionFactory 一关闭,表就会自动删除。

update :最常用的属性,第一次加载hibernate 时,根据modle 类会自动建立表的架构(前提是先建立好数据库),以后加载hibernate 时根据 modle 类自动更新表结构,即使表结构改变了,但表中的行仍然存在,不会删除以前的行。要注意的是:当部署到服务器后,表结构不会马上建立起来。要等应用第一次运行起来才会。

validate:每次加载hibernate 时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。

声明:本站内容来源于原创和互联网,尊重作者版权,转载请注明来源网址,欢迎收藏,谢谢!