失效的起因
起因是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
:通过特定的数据库表产生主键,使用该策略可以使应用更易于数据库移植。