失效的起因

起因是jpa中的@DynamicUpdate注解竟然失效了,也可能是我之前理解的不对.
我之前是这样理解的:我传了一个对象给save方法更新.这个时候如果对象中的字段为null那么就不会更新到数据库中

然后事实是数据库中那个字段被更新为null了!!!

百度了一下,看到了其中一个解释,我觉得应该是对的----先从数据库查询一遍实体,然后把需要更新的内容set进去,再更新,这个时候jpa会判断对象中哪些值和数据库中的不一样,然后把这些值更新进去.

但是这样看来这个@DynamicUpdate岂不是没啥用,和我自己写sql没啥区别,其实不然,是我们理解错了它原本的含义

那么我们可以根据官方文档的解释来定义它

@DynamicUpdate的真正解释

先上一波官方文档
https://docs.jboss.org/hibernate/stable/orm/javadocs/

对于更新,此实体是否应在使用动态sql生成时,仅在预处理sql语句中引用已更改的列。
请注意,对于重新附加分离的实体,如果未启用select-before-update,则无法执行此操作。

可能看了也不是很懂,那么直接上demo把

先说明一下@DynamicUpdate注解用在实体类上

有 数据库 表tbl_foo和对应的实体类Foo,如下:

id	name	col3	col4	col5
1	毕加索	1770	奥地利	男
class Foo{
    private Integer id;
    private String name;
    private String col3;
    private String col4;
    private String col5;
    getter...
    setter...

在Service中更新id=1记录的name属性,代码如下:

Foo foo = fooDao.findById(1);
foo.setName("贝多芬");
fooDao.save(foo);

两种情况:

  • 在entity类中未使用@DynamicUpdate注解或使用了@DynamicUpdate(false),那么Hibernate底层执行的sql如:
update tbl_foo set name=?, col3=?, col4=?, col5=? where id=?
  • 在entity类中使用了@DynamicUpdate注解(或@DynamicUpdate(true)),Hibernate底层执行的sql如:
update tbl_foo set name=? where id=?

以上两种情况对数据库更新的结果是等效的,但是使用@DynamicUpdate性能会好一些。因为不使用@DynamicUpdate时,即使没有改变的字段也会被更新。如果进行频繁的更新操作,并且每次只更新少数字段,那么@DynamicUpdate对性能的优化效果还是很好的。

看到这里大家心里已经明白了七八分把

下面来说说我之前的误解

我们常有一种需求,web层用对象接收前端要修改的属性值(不修改的值为空),我们希望直接调用dao的update方法进行选择更新。

web层使用对象接收前端要修改的属性值,可等效看做执行如下代码:

Foo foo = new Foo();
foo.setId(1);
foo.setName("贝多芬");

这时服务层直接使用这个对象进行更新

fooDao.update(foo);

我们期待的结果是只更新name字段:

id	name	col3	col4	col5
1	贝多芬	1770	奥地利	男

看到网上有些文章说在实体类加上@DynamicUpdate,就可以满足我们的以上需求,但是很遗憾,不然!

反而得到这样的结果是:

id	name	col3	col4	col5
1	贝多芬			

只要完全理解了api-doc中对@DynamicUpdat的说明,就很容易知道得到这个结果的原因了。@DynamicUpdate的动态更新的含义是,比较更新要使用的实体类中的字段值与从数据库中查询出来的字段值,判断其是否有修改。看这个例子,数据库中id=1的记录所有字段都是非空的,但是实体类中只有name有值,也就是所有字段都变了,只是其他字段被更新为了新的空值

jpa的id定义(使用数据库自增)

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

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

  • AUTO: 主键由程序控制,是默认选项,不设置即此项。
  • IDENTITY:主键由数据库自动生成,即采用数据库ID自增长的方式,Oracle不支持这种方式。
  • SEQUENCE:通过数据库的序列产生主键,通过@SequenceGenerator注解指定序列名,mysql不支持这种方式。
  • TABLE:通过特定的数据库表产生主键,使用该策略可以使应用更易于数据库移植。
@DynamicInsert属性:设置为true,表示insert对象的时候,生成动态的insert语句,如果这个字段的值是null就不会加入到insert语句中,默认false。 比如希望数据库插入日期或时间戳字段时,在对象字段为空定的情况下,表字段能自动填写当前的sysdate。 @DynamicUpdate属性:设置为true,表示update对象的时候,生成动态的update语句,如果这个字段的值是null就不会被加入到update语句中,默认false。 比如只想更新某个属性,但是却把整个属性都更
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> <version>2.4.2</version> </dependency> 构建的数据库tb_us.
参考:https://blog.csdn.net/xiao_xuwen/article/details/53579353 及参考了很多。貌似目前大部分都是先去数据库查一下,然后把不为null的值对应的覆盖下,然后保存。 没找到其他更好的办法,但是为了稍微写的优雅点,调用的方便点,修改如下: 自己定义了repository类,覆盖重写了默认的save方法。另外判断加了是否有dynamicupd...
原文地址:https://yan-sa.iteye.com/blog/1913684 由于我在action层使用注解多例@Scope("prototype"),而在dao层默认为单例...... 我把sessionFactory写在了一个通用的basedao实现类中, 而在dao实现类中直接继承了basedao实现类,同时继承了sessionFactory... 本人能力有限,...
下面的代码,我们使用 Spring JPA 作为数据库访问层,并且用 @Table 和 @Column 定义了表和列名,但是 Hibernate 给出的 SQL 语句并没有使用我们定义的名称: @Entity @Table(name = "Node") @Data public class Node { @GeneratedValue @Column(name = "ID") private int id; @Column(
Spring Data JPA中的@DynamicUpdate注解     @DynamicUpdate属于类级别的注解,一般使用JPA entity 类.如下 @Entity @DynamicUpdate public class User { // Existing data and methods
@DynamicInsert属性(默认为false): 如果将其设置为true,表示insert对象的时候,生成动态的insert语句,如果这个字段的值是null就不会加入到insert语句当中。 比如希望数据库插入日期或时间戳字段时,在对象字段为空的情况下,表字段能自动填写当前的sysdate。 @DynamicUpdate属性(默认为false): 如果将其设置为true,表示upda...
@DynamicInsert属性:设置为true,表示insert对象的时候,生成动态的insert语句,如果这个字段的值是null就不会加入到insert语句中,默认false。 比如希望数据库插入日期或时间戳字段时,在对象字段为空定的情况下,表字段能自动填写当前的sysdate。 @DynamicUpdate属性:设置为true,表示update对象的时候,生成动态的update语句,如果...
@DynameicUpdate的原理是只更新发生改变的字段值,没有改变的字段值不进行更新; 容易踩坑的点 如果使用的实体类中有字段值为Null ,而数据库中该值是非空值,那么会将该字段更新为Null值 解决办法是 实体类接收完整的字段。不然很容易踩坑 想每次操作更改数据表的时候更改update字段 首先修改该字段的属性 Alter Table product_category MODIFY COLUMN update_time TIMESTAMP NOT null DEFAULT CURRENT_TIMESTAMP on UPDA...
springMVC实现 MultipartFile 多文件上传,StandardMultipartHttpServletRequest上传文件,在请求中上传文件,比如上传图片 执笔写惊鸿丶: StandardMultipartHttpServletRequest 这种postman怎么传的文件,接收参数都没有 springboot的视图解析器例如从controller跳转到html 何以为春: 谢谢,原来是@RestController的问题。因为后者会把内容转成字符串。 python读取excel数据写入mysql CSDN-Ada助手: MySQL入门 技能树或许可以帮到你:https://edu.csdn.net/skill/mysql?utm_source=AI_act_mysql