关于jpa:JPA大坑-无法像mybaits一样在currentat字段自动生成创建时间

JPA大坑 ,无奈像mybaits一样在current_at字段,主动生成创立工夫mybatis jpa下实体类的保留 mybatis在mybatis我的项目中,咱们个别会应用它的插件plus以裁减它的根本查问性能。另一方面,在阿里巴巴开发手册的标准中也提到,在数据库表创立的时候,个别会有一个create_time和update_time字段,它们的建表语句往往如下: 'create_time' timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,'update_time' timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP创建者则是心愿在行insert的时候会主动生成create_time,同时在其它行进行批改后,执行update操作会自动更新update_time字段。这样简化了开发,只有存储业务字段就能够了,开发者不必管工夫字段的生成。 jpa下实体类的保留新我的项目应用jpa,我也想当然的在表下create_at字段设置 NOT NULL DEFAULT CURRENT_TIMESTAMP,后果调save(entity)保留实体类的时候,发现基本没有像我想的那样在创立工夫字段保留insert的工夫,所有生成工夫字段都为null…打印sql语句才发现,原先调jpa的save办法,默认jpa会把所有字段都insert,为空的话就会本人设置null insert到表中,导致字段设置NOT NULL DEFAULT CURRENT_TIMESTAMP生效,所有的创立工夫字段都得本人set以后工夫这个与业务无关的字段,忘了的话就会报错了,效率低容易出错。最初发现还得在相应的实体类字段写如下正文才能够实现与mybaits雷同的成果,交由数据库去实现创立工夫的创立。 @Column(name = "create_at",insertable = false,updatable = false,columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP") private Date createAt; @Column(name = "update_at",insertable = false,updatable = false,columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP") private Date updateAt;columnDefinition和前面的设置,就等于在数据库中设置DEFAULT CURRENT_TIMESTAMP 和ON UPDATE CURRENT_TIMESTAMP了,这样设置就会让createTime成为创立工夫,updateTime成为更新工夫,数据库会主动去保护他。 然而还有一个问题,jpa调用save办法时,会把这两个字段笼罩掉。所以这里须要insertable = false,updatable = false,这样jpa更新插入时就不会去更新这个字段了,而是齐全由数据库保护。参考文档:https://blog.csdn.net/weixin_30666401/article/details/96759783

January 31, 2022 · 1 min · jiezi

关于jpa:JPA-实体脏检查与存储同步Dirty-Flush

引言问题起源于对新我的项目-数字外围的代码审查,在审阅账户模块后,发现补录、更新等接口没有调用JPA的仓库save办法进行数据长久化,但更新仍然失效,随查阅材料文献,开启了对本议题的探索。 指标:没有调用save办法,更新是怎么失效的? 试一试在查阅大量材料后,理解到与JPA长久化上下文Persistence Context无关,一起试试吧。 试验筹备初始化spring-boot我的项目,依赖spring-data-jpa,并开启spring-data的show-sql配置以便调试。 spring: jpa: show-sql: true建设客户信息实体: /** * 客户信息表 */@Entity@Table(name = "CUSTOMER")public class Customer { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; /** * 客户姓名 */ private String name; /** * 客户手机号 */ private String phone; @Override public String toString() { return "Customer{" + "id=" + id + ", name='" + name + '\'' + ", phone='" + phone + '\'' + '}'; }}配置DataJpaTest启用JPA测试环境,不启动整个spring-context,能够缩小单元测试执行耗时。 /** * 客户信息仓库测试 */@DataJpaTest // 主动配置JPA测试@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) // 不启用内嵌数据库代替public class CustomerRepositoryTest { private static final Logger logger = LoggerFactory.getLogger(CustomerRepositoryTest.class);}复现更新场景更新办法如下,构建一条Hello Kitty!测试数据,并对保留后的实体信息进行批改,但不调用save。 ...

January 15, 2022 · 4 min · jiezi

关于jpa:spring-data-jpa使用native-sql进行分页查询时需要使用countQuery

问题发现:应用data jpa的native sql进行分页查问时,发现一个sql grammar语法报错,再三查看确认本人的sql写的没有问题,sql大抵为 select * from (select * from table1 where ) as table2 where的一个子查问构造,报错为 from (select *) from table1 where ) as table2 where左近有语法错误,比照发现多了一个)右括号。最初发现是分页查问的count查问导致的。 题外话:在应用spring data jpa的@Query的native sql进行分页查问时,能够在办法最初一个参数传入pageable做分页查问,当然也能够在native sql中应用limit offset做分页查问,第一种形式会转换为第二种形式执行。 但分页查问不仅仅返回查问分页的数据,同样会返回符合条件的总个数,也就是totalElements以及totalPages。那么肯定会有一个count查问来干这个事,如果你没写count查问(我就没写),jpa会本人帮你生成一个,但jpa生成的不肯定是你想要的,问题发现中的语法错误就是jpa帮咱们生成的count查问。正确的是: select count(*) from (select * from table1 where ) as table2 where生成的是: select count(* from (select *) from table1 where ) as table2 wherejpa生成的count查问右括号匹配到了第二个*,也就导致了语法错误。。。。。 拓展:对于count的执行问题jpa有逻辑如下:SimpleJpaRepository(crudRepository的默认实现)下的咱们能够看到第一张图中在做分页是传入的第三个参数就是计数查问,而在第二张图中当查问到的数据是少于pageSize时,也就是总数能够在以后查到的第一页算出时,是不须要去执行后续的count查问的,也算是个简略的优化。官网注解的话是: The construction of {@link Page} omits a count query if the total can be determined based on the result size and {@link Pageable}.总结:而在应用办法名规定或者qbc进行分页查问时是不会呈现上述问题的,查问sql和计数sql都是统一生成的。而应用natvie sql时jpa会依据你写的sql语句改写count(看起来只是做了一些简略的字符串匹配),于是呈现了上述问题。在应用native sql进行分页查问时记得应用countQuery ...

November 25, 2021 · 1 min · jiezi

关于jpa:Spring-Data-JPA-报-HOUROFDAY-0-1异常的解决过程和方案

在进行数据查问时,控制台报了Caused by: com.mysql.cj.exceptions.WrongArgumentException: HOUR_OF_DAY: 0 -> 1异样,查问得悉:这是因为查mysql库,转换类型为datetime类型的字段引起的。 网上的解决方案有多种,大多数都是通过设置时区来解决的,但遗憾的是通过测试我发现即便在将数据跑在时区正确的数据库上,在执行起来我这依然出错。 最初发现我的问题呈现在夏令时上。 夏令时记得小时候过过几个夏令时,大略的意思就是在某一天把表调快1个小时,而后再到某一天把表再调慢1个小时。这间接造成的问题的是:xxxx年xx月xx日会对应上两个工夫戳。比方咱们假如把表调慢的那一天是2021年10月4日的12点。具体的操作是过后钟第一次通过2021年10月4日12点时,咱们把表调到2021年10月4日11点。所以在2021年10月4日11点至12点,咱们会从新过一次。 对于工夫这块,已经回达到一个工夫戳为负的问题,也有那么点意思:https://segmentfault.com/q/1010000038248983,赶趣味的能够看看。 那么问题来了,比咱们记录用户的出世工夫,准确到分钟。如果这个人录入的是2021年10月4日11点20分,那咱们的零碎没有方法来精确的判断这个工夫是第一个11点20分,还是过1小时后的第二个11点20分。 夏令时,还给咱们带来的另一个问题。有些工夫是对应不上工夫戳的。再比方咱们设置在2021年5月1日0时,将表调快1时,则在历史上不会呈现2021年5月1日0时至1时的工夫,所以如果咱们统计出世工夫点,用户写的是:2021年5月1日0时30分,则该数据必须是个假数据。 排查夏令时讲完后,咱们讲下排查过程。其实并不是所有的数据在查问时,都会报这种异样,所以要把那个非凡的点找进去,这里给一种最笨的展现办法: boolean last = false; int page = 0; Pageable pageable = PageRequest.of(page, 1); while (!last) { try { Page<Resident> residents = this.residentRepository.findAll(specification, pageable); page++; pageable = PageRequest.of(page, 1); last = residents.isLast(); } catch (Exception e) { last = true; e.printStackTrace(); this.logger.info("当前页" + pageable.getPageNumber()); } }最终控制台打印信息:2021-11-04 13:25:38.562 INFO 4226 --- [nio-8081-exec-7] c.y.s.service.ResidentServiceImpl : 当前页1089 而后咱们去数据表中把这条记录查出来: ...

November 4, 2021 · 1 min · jiezi

关于jpa:SpringBoot-整合-Spring-Data-JPA

学习应用 Spring Data JPAJPA 简介JPA(Java Persistence API)是 Java 长久化 API,是 Sun 公司提出的基于 ORM 的 Java 长久化标准。 ORM(Object Relational Mapping)的全称是对象关系映射,支流 Java ORM 框架有 Mybatis,Hibernate 等。Spring Data JPASpring Data JPA 是 Spring Data 框架的一个模块,可简化 JPA 的实现。此外,Spring Data JPA 还能够帮忙咱们简化长久层的开发。对于简略查问,Spring Data JPA 能够依据办法名称进行解析,并主动生成查问语句进行查问;对于简单查问,Spring Data JPA 同样反对原生的 SQL。 Spring Data JPA 实际创立 SpringBoot 我的项目,利用 JPA 实现简略 CRUD。 1. 引入依赖POM 文件如下: <?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.2.5.RELEASE</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 project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <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>2. 配置 JPA 和 MySQLapplication.yml 配置文件如下: ...

October 14, 2021 · 3 min · jiezi

关于jpa:JPA一对多多对多配置

单向一对多@Data@Entity@Table(name = "banner")public class Banner { @Id private Integer id; private String name; @OneToMany(fetch = FetchType.LAZY) @JoinColumn(name = "bannerId", referencedColumnName = "id") private List<BannerItem> items;}下面为双方配置,@JoinColumn注解外面name示意多方中配置的外键名称,referencedColumnName为外键对应的双方主键。 @Data@Entity@Table(name = "banner_item")public class BannerItem { @Id private Integer id; private String img; private Integer bannerId; private String name;}下面为双方配置,没有什么非凡的。 双向一对多@Data@Entity@Table(name = "banner")public class Banner { @Id private Integer id; private String name; @OneToMany(fetch = FetchType.LAZY, mappedBy="banner") private List<BannerItem> items;}双向时双方不须要@JoinColumn注解,须要在@OneToMany上增加mappedBy属性指明多方的映射属性。 @Data@Entity@Table(name = "banner_item")public class BannerItem { @Id private Integer id; private String img; private Integer bannerId; private String name; @ManyToOne @JoinColumn(name="bannerId") private Banner banner;}多方的注解应用@ManyToOne,标注在映射双方的属性上,同时须要加上@JoinColumn注解指明外键。 ...

September 9, 2021 · 1 min · jiezi

关于jpa:如何使用JPA的UUID主键生成策略

数据实体类@Entity@Table(name = "ip_user")@GenericGenerator(name = "jpa-uuid", strategy = "uuid") // name = "system-uuid"也能够public class User implements Serializable { @Id@GeneratedValue(generator = "jpa-uuid") //system-uuid同样@Column(length = 32)private String userId;...} 留神@GenericGenerator(name = "jpa-uuid", strategy = "uuid") 和 @GeneratedValue(generator = "jpa-uuid") 两个注解是生成策略外围注解。 留神@GenericGenerator(name = "system-uuid", strategy = "uuid") 和 @GeneratedValue(generator = "system-uuid") 两个注解是生成策略外围注解。 数据库字段执行save办法后不须要给user.id字段设置值,jpa会主动生成uuid并作为它的主键增加到表中。

April 22, 2021 · 1 min · jiezi

关于jpa:Spring-Data-JPA中的mappedBy

JPA,在@OneToMany里退出mappedBy属性防止生成两头表 mappedBy 单向关系不须要设置该属性,双向关系必须设置,防止单方都建设外键字段。数据库中1对多的关系,关联关系总是被多方保护的即外键建在多方,咱们在双方对象的@OneToMany(mappedby="")把关系的保护交给多方对象的属性去保护关系。对于mappedBy温习下:a) 只有OneToOne,OneToMany,ManyToMany上才有mappedBy属性,ManyToOne不存在该属性;b) mappedBy标签肯定是定义在the owned side(被领有方的),他指向theowning side(领有方);c) 关系的领有方负责关系的保护,在领有方建设外键。所以用到@JoinColumnd)mappedBy跟JoinColumn/JoinTable总是处于互斥的一方 这里的保护关联关系,拿多对多来说就是两头表,在不设置cascade的状况下,两头表由负责保护关联关系的一方保护 参考链接:https://www.cnblogs.com/hyl82...http://www.mamicode.com/info-...https://www.cnblogs.com/power...

December 11, 2020 · 1 min · jiezi

关于jpa:JPA中使用Sort排序时遇到的问题

JPA中应用Sort排序时遇到的问题org.springframework.data.jpa.repository.JpaRepository中能够应用Sort定义排序规定,但在应用时我发现了一些小问题 失常基于Pageable中的Sort字段排序 Sort sort = new Sort(Direction.ASC, "seqNum");Pageable pageable = new PageRequest(0, size, sort);然而,问题来了他报错了!!!起因是这两个类的构造方法被定义为了公有或者爱护的办法我从网上查了好多相干材料,但他们用的时候貌似都能够间接实例化进去,甚至官网上也是这么用的,但我却不能这样用 (好气)为了解决这个问题,我看了下这两个类的源码,好在类外面定义了相干的静态方法可能应用所以能够通过调用这些写好的静态方法而不必实例化就能达到雷同的成果 Sort sort = Sort.by(Sort.Direction.DESC,"blogs.size");Pageable pageable = PageRequest.of(0,size,sort);PS:起因是springboot版本太新导致的

December 1, 2020 · 1 min · jiezi

关于jpa:Spring-Data-JPA使用看这一篇就够了

简介首先理解Spring Date JPA是什么? SpringData:其实SpringData就是Spring提供了一个操作数据的框架。而SpringData JPA只是SpringData框架下的一个基于JPA规范操作数据的模块。SpringData JPA:基于JPA的规范数据进行操作。简化操作长久层的代码。只须要编写接口就能够。 JPA是Spring Data下的子项目,JPA是Java Persistence API的简称,中文名为Java长久层API,是JDK 5.0注解或XML形容对象-关系表的映射关系,并将运行期的实体对象长久化到数据库中 你能够了解为JPA和Mybatis是起雷同作用的,都是长久层的框架,然而因为当初Mybatis的广泛应用,当初理解和应用JPA的人较少. 但在我应用的过程中,也发现其一些劣势. 整合1.导入jar包<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId></dependency>2.yml配置文件spring: datasource: url: jdbc:mysql://localhost:3306/mytest type: com.alibaba.druid.pool.DruidDataSource username: root password: root driver-class-name: com.mysql.jdbc.Driver //驱动 jpa: hibernate: ddl-auto: update //自动更新 show-sql: true //日志中显示sql语句这里留神:jpa:hibernate:ddl-auto: update是hibernate的配置属性,其次要作用是:主动创立、更新、验证数据库表构造。该参数的几种配置如下:1.·create:每次加载hibernate时都会删除上一次的生成的表,而后依据你的model类再从新来生成新表,哪怕两次没有任何扭转也要这样执行,这就是导致数据库表数据失落的一个重要起因。2.·create-drop:每次加载hibernate时依据model类生成表,然而sessionFactory一敞开,表就主动删除。3.·update:最罕用的属性,第一次加载hibernate时依据model类会主动建设起表的构造(前提是先建设好数据库),当前加载hibernate时依据model类自动更新表构造,即便表构造扭转了但表中的行依然存在不会删除以前的行。要留神的是当部署到服务器后,表构造是不会被马上建设起来的,是要等利用第一次运行起来后才会。4.·validate:每次加载hibernate时,验证创立数据库表构造,只会和数据库中的表进行比拟,不会创立新表,然而会插入新值。我在首次创立时会设为create,创立好后改为validate. 3.实体类既然上边的参数能够帮忙咱们主动的去通过实体类来创立保护表,那么实体类该怎么写呢,又是怎么建设与表的映射 简略的创立一个实体类:get/set办法由注解实现 @Entity@Getter@Setter@Table(name = "person")public class Person { @Id @GeneratedValue private Long id; @Column(name = "name", length = 20) private String name; @Column(name = "agee", length = 4) private int age;}创立好实体类并标注好注解后启动主启动类,应该就会在你配置的数据库中主动生成表. ...

November 7, 2020 · 3 min · jiezi