1、问题背景
个人比较喜欢Spring data JPA,这次的问题是在实体类中使用List类型作为字段,JPA也提供了操作的方法,即使用@ElementCollection注解,网上对于JPA的知识比较零散,毕竟是不如Mybatis使用起来那么简单。
下面进入正题,来看下我的实体类中的字段:
@ElementCollection(fetch = FetchType.LAZY)//定义基本类型或可嵌入类的实例集合 @OrderColumn(name="position")//如果使用的是List,你需要多定义一个字段维护集合顺序 private List<String> part;其实JPA内部对于集合类型的字段是使用另一张表进行维护。简单来说,省去了你自己去定义另一张表来进行一对多关系的维护。
所以,我想更新这张表的这条字段就不能像更新普通字段(String,int)一样了,那不一样在哪里呢?
JPA更新字段的手段有两种,一种是通过设置主键进行save()保存,一种是通过@Query注解。
如果使用第二种,在前面已经说了其实是对另一张表的操作,所以我们只需要对另一张表增删改查就好了。
但这样个人觉得有点没发挥JPA的个性,所以我想使用第一种。
但是使用第一种方法有两个问题:
- 实体类的部分字段LAZY懒加载会不会导致更新后这部分字段为NULL?
- JPA为什么能够知道我们调用save()方法是updata更新而不是insert新增?
请看下面的测试用例。
2、测试用例
下面看下定义的实体类,主要由主键id,字段name,以及集合part组成,集合为Lazy懒加载。
@Entity @Table(name = "name_href") public class NameHref { @Id @GeneratedValue() private int id; @Column(name = "name") private String name; private String href; @ElementCollection(fetch = FetchType.LAZY) @OrderColumn(name="position") private List<String> part; ......当我们定义集合part为Lazy懒加载,正常来说使用JPA获取实体后是取不到part的值的,(执行get方法会报错)所以更新字段后part的值到底是不是为NULL,我们来看单元测试:
@Autowired NameHrefRepository nameHrefRepository; @Test public void getHref() { NameHref nameHref = new NameHref(); nameHref.setId(-1); String name = "博客园"; nameHref.setName(name); nameHref.setHref("http://www.cnblogs.com"); ArrayList<String> objects = new ArrayList<>(); objects.add("安卓"); objects.add("苹果"); nameHref.setPart(objects); nameHrefRepository.save(nameHref); NameHref byName = nameHrefRepository.findAllByName(name); byName.setHref("http://www.baidu.com"); nameHrefRepository.save(byName); }这段代码是先新建一个实体保存到数据库然后再获取该实体,修改部分字段,使用save()方法保存。执行完后我们查看数据库字段:href属性已经被成功修改,而且声明为LAZY的集合part也还在。说明save()方法正确执行了updata操作。那JPA究竟如何执行的,看下SQL记录:
Hibernate: select namehref0_.id as id1_20_, namehref0_.href as href2_20_, namehref0_.name as name3_20_ from name_href namehref0_ where namehref0_.name=? Hibernate: select namehref0_.
