发布:2023/12/7 15:45:16作者:大数据 来源:大数据 浏览次数:510
1、application.yml配置文件:
1 2 3 4 5 6 7 |
mybatis: mapper-locations: classpath:/mapper/*.xml type-aliases-package: com.example.springbootmybatis.entity //下面的是错误配置,会导致找不到mapper,下面的配置是配置文件的映射,而不是mapper的映射 mybatis: config-location: classpath:/mapper/*.xml type-aliases-package: com.example.demo.entity |
在Mybatis的mapper.xml文件中resultType的type或者paramterType会返回自定义entity,此时可以用全类名名来指定这些实体。可以使用type-aliases-package
中指定entity扫描包类让mybatis自定扫描到自定义的entity。这样就不用全名指定了,只用类型即可。
1 2 |
<!--配置别名 xml--> <property name="typeAliasesPackage" value="com.ivan.edu.model,com.ivan.edu.vo"></property> |
mybatis配置打印sql语句
1 2 3 |
mybatis: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl |
1 2 |
<?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"> |
2、repository/UserRepository.java接口
3、resources/mapper/UserRepositoryMapper.xml动态代理实现类需要此文件
4、cotroller/UserController.java 控制类,注入UserRepository接口@Autowired
5、启动类application上加入@MapperScan("com.example.demo.repository")
1 2 3 4 5 6 7 8 9 |
@MapperScan("com.example.demo.repository") @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } |
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中没有指定为命名空间是错误的,必须是接口的命名空间全称+接口名,正确如下:
1 2 3 4 5 6 7 8 |
<?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="<strong>com.example.springbootmybatis.repository.StudentRepository</strong>"> <select id="findById" parameterType="Integer" resultType="Student"> select * from student where id = #{id} </select> </mapper> |
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里编译运行时正常,发布后提示错误):
1 |
modelAndView.setViewName("/student/index"); |
正确的如下:
1 |
modelAndView.setViewName("student/index"); |
可见不要随便加绝对路径。
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类上面加上注解
1 |
@JsonIgnoreProperties(value={"hibernateLazyInitializer","handler","fieldHandler"}) |
或
1 |
@JsonIgnoreProperties(value={"hibernateLazyInitializer"}) |
异常:
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生成
1 2 |
@Column(name = "bookname") private String bookName; |
JPA的注解来定义实体的时候,使用@Id来注解主键属性即可。如果数据库主键是自增长的,需要在增加一个注解@GeneratedValue,即:
1 2 3 |
@GeneratedValue(strategy=GenerationType.IDENTITY) @Id private Integer id; |
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
1 2 3 4 |
@Repository public interface BookRepository extends JpaRepository<Book,Integer> { List<Book> findByBookName(String bookName);//不用写代码自动实现 } |
剔除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 时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。
© Copyright 2014 - 2024 柏港建站平台 ejk5.com. 渝ICP备16000791号-4