🤵♂️ 个人主页:@香菜的个人主页,加 ischongxin ,备注csdn
✍🏻作者简介:csdn 认证博客专家,游戏开发领域优质创作者,华为云享专家,2021年度华为云年度十佳博主
🐋 希望大家多多支持,我们一起进步!😄
如果文章对你有帮助的话,
欢迎评论 💬点赞👍🏻 收藏 📂加关注+
目录
[2、spring data 的特点](#2、spring data 的特点)
[3.1 jpa简单使用](#3.1 jpa简单使用)
[4.1 自己实现一个repo](#4.1 自己实现一个repo)
[4.2 实现代理接口](#4.2 实现代理接口)
[4.3 测试](#4.3 测试)
[4.4 看下结果](#4.4 看下结果)
好久不写,也是真写不下去,不知道为啥,总是开始想写,一会就失去了动力。
今天无论如何整一篇吧,总结下JPA的原理,也为以后做同样的设计做个初稿。
1、jpa的使用
CSDN之前写了两篇Spring data JPA 的使用,可以参考下怎么用的,好用且简单,传送门
https://blog.csdn.net/perfect2011/article/details/130803614
https://blog.csdn.net/perfect2011/article/details/131049080
2、spring data 的特点
强大的存储库和自定义对象映射抽象
从存储库方法名称派生动态查询
实现域基类提供基本属性
无论是哪种持久化存储, 数据访问对象通常都会提供对单一域对象的CRUD (创建、读取、更新、删除)操作、查询方法、排序和分页方法等。Spring Data则提供了基于这些层面的统一接口(CrudRepository,PagingAndSortingRepository)以及对持久化存储的实现。
3、jpa的简单使用
为了能够简单实现JPA,也为了能说明技术特点,还是写一个简单的JPA使用,具体的实现代码可以看上面两个链接
3.1 jpa简单使用
entity定义
import jakarta.persistence.*;
import lombok.Data;
import java.io.Serializable;
@Entity
@Data
@Table(name = "t_user")
public class UserEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(name = "username")
private String userName;
@Column(name = "password")
private String password;
}
repo的定义
import com.alicp.jetcache.anno.CacheType;
import com.alicp.jetcache.anno.Cached;
import com.xin.jetcachetest.entity.UserEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface UserRepo extends JpaRepository<UserEntity, Integer>, JpaSpecificationExecutor<UserEntity> {
UserEntity findAllByUserName(String userName);
}
项目中使用
import com.xin.jetcachetest.cache.UserRepo;
import com.xin.jetcachetest.entity.UserEntity;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@Resource
UserRepo userRepo;
@GetMapping("/user")
public UserEntity getUser(){
UserEntity allByUserName = userRepo.findAllByUserName("admin");
return allByUserName;
}
}
简单总结要点:
- 1、有entity定义
- 2、创建访问repo 实现相关的接口
- 3、在其他地方使用
4、简单实现-原理
整个JPA的使用还是很简单的,这里的技术实现是怎么样的,主要
实现方式,在以后的工作中可以使用类似的开发技术方案,我关注的两个点
1.接口是怎么有实现的?
2.动态sql 是怎么做到的?
这两者的基础都是Java的动态代理,下面来个简单实现,万变不离其宗,我们来接管这个接口的实现。
4.1 自己实现一个repo
这里直接选择了一个CrudRepository 进行实现,同时也只实现了一个findById接口,在内容里加了一个打印
很简单,这里只是作为demo,没有真正的实现接口
4.2 实现代理接口
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class RepoProxy implements InvocationHandler {
private Object target;
private XinRepository xinRepository;
public RepoProxy() {
xinRepository = new XinRepository();
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Method method1 = xinRepository.getClass().getMethod(method.getName(), method.getParameterTypes());
return method1.invoke(xinRepository,args);
}
}
这里的重点是将代理方法的调用直接转接到XinRepository中调用,相当于狸猫换太子
4.3 测试
直接通过动态代理创建代理类。
import com.xin.jetcachetest.cache.UserRepo;
import java.lang.reflect.Proxy;
public class Aain {
public static void main(String[] args) {
UserRepo userRepo = (UserRepo) Proxy.newProxyInstance(UserRepo.class.getClassLoader(), new Class[]{UserRepo.class}, new RepoProxy());
userRepo.findById(1);
}
}
4.4 看下结果
总结
原理很简单,将接口生成动态代理,然后在代理中将方法转换到对应的实现中。
UserRepo 继承相关的接口
XinRepository 也要实现UserRepo 继承的接口,也就是保持接口中方法一致
RepoProxy 代理所有的接口方法,转入实现类XinRepository中
使用JDK动态代理创建代理类。