不了解spring data jpa的建议先看我之前的文章
本篇的源码地址:
https://github.com/pony-maggie/spring-boot-jpa-advance
自定义SQL查询
mybatis擅长大量自定义查询的场景,spring data jpa虽然优势不在这里,但是也支持自定义SQL查询。它主要是通过@Query注解支持的。
1 |
|
@Query 注解中编写更新类语句, 但必须使用 @Modifying 进行修饰. 以通知 SpringData, 这是一个 UPDATE 或 DELETE 操作
@Transactional表示开启事务,如果不加的话会下面的异常:
1 |
|
然后我们在controller里加入测试接口进行测试。
http://localhost:8080/student/byAge?age=16
http://localhost:8080/student/modifyNameById?name=zhangsan&id=3
复杂查询如何实现
有些业务场景下我们需要复杂一些的查询,比如指定某些条件进行分页,关联查询等。spring data jpa给我们提供了JpaSpecificationExecutor用来支持这样的场景。
JpaSpecificationExecutor提供了以下接口
1 |
|
传进去的参数Specification是个接口,我们主要的工作就是实现这个接口。我这里实现了一个:
1 |
|
然后我们在service里调用测试下,
1 |
|
打印的SQL如下:
1 |
|
可以看出我们通过自定义Specification实现了一个id大于3的分页查询操作。所以利用Specification我们可以自定义各种复杂的查询,甚至可以把各种复杂的查询组合起来使用。
大家可以下载源码自己测试看看效果。
关于事务
JpaRepository提供的增删改查接口方法默认都是支持事务的,我们不需要再单独声明。这是因为JpaRepository都有一个默认实现SimpleJpaRespositry,它的定义如下:
1 |
|
如果我们再service层调用的DAO方法不是自定义的,那么spring会通过动态代理机制调用SimpleJpaRespositry中的方法。
对于自定义的SQL如果要支持事务只要在方法上加上注解@Transactional即可。比如前面自定义SQL查询中的例子。
除了DAO层,有时候我们需要在service层引入事务,比如有个service方法会执行两步DAO层的操作(删除和插入),我们的业务场景需要这两个步骤要么都成功,要么都失败。
1 |
|
1 |
|
我写了两个方法演示,一个是带事务注解,一个不带,两个方法都会抛出异常,带事务的方法抛出异常后会进行回滚,而不带事务的方法不会回滚。
这里需要注意一定是遇到运行时异常才会进行回滚
原理概述
spring在启动的时候会实例化一个Repositories,它会去扫描所有的class,然后找出由我们定义的、继承自org.springframework.data.repository.Repository的接口,然后遍历这些接口,针对每个接口依次创建如下几个实例:
- SimpleJpaRespositry——用来进行默认的DAO操作,是所有Repository的默认实现
- JpaRepositoryFactoryBean——装配bean,装载了动态代理Proxy,会以对应的DAO的beanName为key注册到DefaultListableBeanFactory中,在需要被注入的时候从这个bean中取出对应的动态代理Proxy注入给DAO
- JdkDynamicAopProxy——动态代理对应的InvocationHandler,负责拦截DAO接口的所有的方法调用,然后做相应处理,比如findByUsername被调用的时候会先经过这个类的invoke方法
参考
http://www.luckyzz.com/java/spring-data-jpa/
https://blog.csdn.net/J080624/article/details/84581231