有些时候,我们需要自定义Repository实现一些特殊的业务场景。

1、自定义单个Repository

  1.1、首先提供一个片段接口和实现(接口的实现默认要使用Impl为后缀,实现本身不依赖spring-data,可以是常规的spring-bean,所以可以注入其他的bean,例如JdbcTemplate)。

/**
* @author caofanqi
*/
public interface StudentRepositoryCustomJdbc { List<Student> findStudentByJdbcName(String name); } /**
* 默认要以Impl结尾
* @author caofanqi
*/
public class StudentRepositoryCustomJdbcImpl implements StudentRepositoryCustomJdbc { @Resource
private JdbcTemplate jdbcTemplate; @Override
public List<Student> findStudentByJdbcName(String name) {
String sql = "SELECT * FROM cfq_jpa_student WHERE name = " + "'" + name + "'";
return jdbcTemplate.query(sql, BeanPropertyRowMapper.newInstance(Student.class));
} }

  1.2、自己的Repository继承自定义接口,就可以使用拓展的功能了。

/**
* 继承jpa的repository,和自己自定义的扩展
* @author caofanqi
*/
public interface StudentRepository extends JpaRepositoryImplementation<Student,Long>, StudentRepositoryCustomJdbc {
}

  1.3、测试如下:

    @BeforeEach
void setup(){
Student s1 = Student.builder().name("张三").age(23).build();
Student s2 = Student.builder().name("李四").age(24).build();
Student s3 = Student.builder().name("王五").age(25).build(); studentRepository.saveAll(Lists.newArrayList(s1,s2,s3));
} @Test
void testFindStudentByJdbcName(){
List<Student> list = studentRepository.findStudentByJdbcName("张三");
list.forEach(s -> System.out.println(s.getName()));
}

  1.4、控制台打印:

Hibernate: insert into cfq_jpa_student (age, name) values (?, ?)
Hibernate: insert into cfq_jpa_student (age, name) values (?, ?)
Hibernate: insert into cfq_jpa_student (age, name) values (?, ?)
张三

  1.5、自定义扩展可以有多个。自定义的优先级高于spring-data为我们提供的。

/**
* 继承jpa的repository,和自己自定义的扩展
* @author caofanqi
*/
public interface StudentRepository extends JpaRepositoryImplementation<Student,Long>, StudentRepositoryCustomJdbc,StudentRepositoryCustom<Student,Long> {
}
/**
* 自定义student功能
*
* @author caofanqi
*/
public interface StudentRepositoryCustom<T,ID> { Optional<T> findById(ID id); } /**
* 自定义实现repository功能
*
* @author caofnqi
*/
@Slf4j
public class StudentRepositoryCustomImpl<T,ID> implements StudentRepositoryCustom<T,ID> { @PersistenceContext
private EntityManager entityManager; @Override
public Optional<T> findById(ID id) {
log.info("自定义的findById");
T t = (T) entityManager.find(Student.class, id);
return Optional.of(t);
}
}

  

1.6、可以通过@EnableJpaRepositories的repositoryImplementationPostfix属性自定义后缀,默认是Impl。

/**
* 启动类
* @author caofanqi
*/
@SpringBootApplication
@EnableAsync
@EnableJpaRepositories(repositoryImplementationPostfix = "MyPostfix")
public class StudySpringDataJpaApplication { public static void main(String[] args) {
SpringApplication.run(StudySpringDataJpaApplication.class, args);
} }

2、自定义BaseRepository

  2.1、SpringDataJpa为我们提供的代理类其实是SimpleJpaRepository。  

  

  2.2、如果我们想要对所有的Repository的保存操作都进行记录日志,我们可以自定义BaseRepository,来充当代理类。(还可以是逻辑删除等场景)

    2.2.1、自定义baseRepository

/**
* 自定义base Repository
*
* @author caofanqi
*/
@Slf4j
public class MyRepositoryImpl<T,ID> extends SimpleJpaRepository<T,ID> { private final EntityManager entityManager; MyRepositoryImpl(JpaEntityInformation entityInformation, EntityManager entityManager) {
super(entityInformation, entityManager);
this.entityManager = entityManager;
} @Override
public <S extends T> S save(S entity) {
S save = super.save(entity);
log.info("保存了:{}",save);
return save;
} }

  2.2.2、告知Spring-Data-Jpa使用我们自定义的baseRepository

/**
* 启动类
* @author caofanqi
*/
@SpringBootApplication
@EnableAsync
@EnableJpaRepositories(
/*queryLookupStrategy = QueryLookupStrategy.Key.CREATE_IF_NOT_FOUND*/
/* ,repositoryImplementationPostfix = "MyPostfix",*/
repositoryBaseClass = MyRepositoryImpl.class)
public class StudySpringDataJpaApplication { public static void main(String[] args) {
SpringApplication.run(StudySpringDataJpaApplication.class, args);
} }

  2.2.3、再次测试testSave方法,如下

  

3、entityManager执行原生复杂sql返回DTO

  使用方法派生查询和@Query注解查询时,我们可以使用投影来面向对象编程,但是使用entityManager执行原生sql复杂sql时,怎么返回实体呢?如下:

  3.1、DTO

/**
* entityManager使用的结果映射,需要一个无参构造函数与set方法,这一点与投影不一样
* @author caofanqi
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class StudentAgeAndAgeCountDTO { private Integer age; private Long ageCount; }

  3.2、查询方法

    public List<StudentAgeAndAgeCountDTO> findCountGroupByAge(){

        /*
*sql可以是更复杂的
*/
String sql = "SELECT age,count(*) AS ageCount FROM cfq_jpa_student GROUP BY age "; Query nativeQuery = entityManager.createNativeQuery(sql);
nativeQuery.unwrap(NativeQuery.class)
//设置类型
.addScalar("age", StandardBasicTypes.INTEGER)
.addScalar("ageCount",StandardBasicTypes.LONG)
//设置返回bean
.setResultTransformer(Transformers.aliasToBean(StudentAgeAndAgeCountDTO.class));
return nativeQuery.getResultList(); }

  3.3、测试及结果 

 

源码地址:https://github.com/caofanqi/study-spring-data-jpa

学习Spring-Data-Jpa(十四)---自定义Repository的更多相关文章

  1. 学习Spring Data JPA

    简介 Spring Data 是spring的一个子项目,在官网上是这样解释的: Spring Data 是为数据访问提供一种熟悉且一致的基于Spring的编程模型,同时仍然保留底层数据存储的特​​殊 ...

  2. Spring Data Jpa的四种查询方式

    一.调用接口的方式 1.基本介绍 通过调用接口里的方法查询,需要我们自定义的接口继承Spring Data Jpa规定的接口 public interface UserDao extends JpaR ...

  3. Spring Data - Spring Data JPA 提供的各种Repository接口

    Spring Data Jpa 最近博主越来越懒了,深知这样不行.还是决定努力奋斗,如此一来,就有了一下一波复习 演示代码都基于Spring Boot + Spring Data JPA 传送门: 博 ...

  4. Spring Data JPA 提供的各种Repository接口作用

    各种Repository接口继承关系: Repository : public interface UserRepository extends Repository<User, Integer ...

  5. 学习-spring data jpa

    spring data jpa对照表 Keyword Sample JPQL snippet And findByLastnameAndFirstname - where x.lastname = ? ...

  6. Spring Data Jpa 查询返回自定义对象

    转载请注明出处:http://www.wangyongkui.com/java-jpa-query. 今天使用Jpa遇到一个问题,发现查询多个字段时返回对象不能自动转换成自定义对象.代码如下: //U ...

  7. 在spring data jpa中使用自定义转换器之使用枚举转换

    转载请注明http://www.cnblogs.com/majianming/p/8553217.html 在项目中,经常会出现这样的情况,一个实体的字段名是枚举类型的 我们在把它存放到数据库中是需要 ...

  8. Spring Data JPA 教程(翻译)

    写那些数据挖掘之类的博文 写的比较累了,现在翻译一下关于spring data jpa的文章,觉得轻松多了. 翻译正文: 你有木有注意到,使用Java持久化的API的数据访问代码包含了很多不必要的模式 ...

  9. Spring Data JPA —— 快速入门

    一.概述 JPA : Java Persistence API, Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中. Spring D ...

随机推荐

  1. aspnetcore identity result.Succeeded SignInManager.IsSignedIn(User) false?

    登陆返回的是 result.Succeeded 为什么跳转到其他页面SignInManager.IsSignedIn(User)为false呢? result.Succeeded _signInMan ...

  2. 【Python爬虫案例学习】Python爬取淘宝店铺和评论

    安装开发需要的一些库 (1) 安装mysql 的驱动:在Windows上按win+r输入cmd打开命令行,输入命令pip install pymysql,回车即可. (2) 安装自动化测试的驱动sel ...

  3. Python解析 算数表达式求值 栈的使用

    使用Python实现一种算数表达式求值的算法,模拟这种使用栈的方式,这是由E.W.Dijkstra在20世纪60年代发明的一种非常简单的算法.代码模拟仅仅表现一种编程思想,代码的逻辑并不完全: if ...

  4. IDEA设置虚拟机参数

    第一步:打开“Run->Edit Configurations”菜单 第二步:选择“VM Options”选项,输入你要设置的VM参数 第三步:点击“OK”.“Apply”后设置完成

  5. java之spring之初始spring

    1.Spring 在多个框架中起到润滑剂的作用,桥梁的作用,纽带的作用. 2.Spring是一个容器,也是一个对象工厂.帮助程序员创建对象,管理对象. 3.Spring的体系结构: 4.学习sprin ...

  6. maven引入外部包的方法1

    最近一个项目需要用到两个外部包文件 ctgclient-8.1.0.3.jar ctgserver-8.1.0.3.jar 方便maven打包,修改pom.xml配置(basedir为pom.xml所 ...

  7. canvas实现酷炫气泡效果

    canvas实现动画主要是靠设置定时器(setinterval())和定时清除画布里的元素实现,canvas动画上手很简单,今天可以自己动手来实现一个酷炫气泡效果. 气泡炸裂效果(类似水面波纹) 代码 ...

  8. 在Linux系统上安装Spring boot应用

    Unix/Linux 服务 systemd 服务 操作过程 1. 安装了JDK的centOS7虚拟机 注意下载linux版本JDK的时候不能直接通过wget这种直接链接下载,否则会解压不成功,应该打开 ...

  9. 【RAC】 RAC For W2K8R2 安装--dbca创建数据库(七)

    [RAC] RAC For W2K8R2 安装--dbca创建数据库(七) 一.1  BLOG文档结构图 一.2  前言部分 一.2.1  导读 各位技术爱好者,看完本文后,你可以掌握如下的技能,也可 ...

  10. 使用FMXlinux 开发linux 桌面应用

    自从delphi 10.2 开始正式支持linux  开发来,大家一直关心为什么官方没有使用FMX来支持LInux 的桌面开发? 其实原因无非就几点: 1.Linux 大部分是应用还是服务端的,桌面应 ...