学习Spring-Data-Jpa(十四)---自定义Repository
2024-10-21 13:44:07
有些时候,我们需要自定义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
最新文章
- 许愿墙的搭建基于mysql
- myeclipse 开发环境下,提示 String cannot be resolved to a type
- bzoj3594: [Scoi2014]方伯伯的玉米田--树状数组优化DP
- iOS开发——iOS学习路线
- HDU 1180 (BFS搜索)
- sql server R2 下载地址收藏
- java中数据流的简单介绍
- C#避免过长的IF和Switch分支的方法
- 用Vue中遇到的问题和处理方法(一)
- Elasticsearch 5.0 安装 Search Guard 5 插件 (五)
- Shell:进程的层级关系
- CSS学习(一)
- 4.hadoop的安装与配置
- [转载]URI、 URL 和 URN 的区别
- 利用GSEA对基因表达数据做富集分析
- <;转>;jmeter(十九)HTTP属性管理器
- Servlet----------ServletConfig
- python读取grib grib2气象数据
- jQuery中.bind() .live() .delegate() .on()区别
- 51Nod 1684 子集价值 (平方和去括号技巧)
热门文章
- 为何一个@LoadBalanced注解就能让RestTemplate拥有负载均衡的能力?【享学Spring Cloud】
- 6. 运行Spark SQL CLI
- Harbor配置自签名证书,docker login+web https访问,helm chart推送应用
- .net core中的Session以及HttpContext对象使用小结
- Linux Shell/Bash wildcard通配符、元字符、转义符使用
- writeAsBytes writeAsString
- 深入理解JVM(三) -- 对象的内存布局和访问定位
- 【转载】C#中List集合使用GetRange方法获取指定索引范围内的所有值
- JAVA基础之HttpServletResponse响应
- GO实现Cron解析和定时任务