Spring提供的一套对JPA操作更加高级的框架,是在JPA规范下专门用来进行持久化的解决方案
策略策略策略策略a@MappedSuperclass:标记这个基类存储表的共同字段,继承类直接继承即可@Entity:标记这个实体类是与数据库表映射的@Table:标记这个实体的表信息@Id:标记该属性是主键列@GeneratedValue:标记该主键的生成策略IDENTITY == 自增 == MySQL支持SEQUENCE == 序列 == Oracle支持AUTO == 程序自动帮我们选择策略TABLE == 序列 == JPA提供的一个机制,通过数据库表形式帮助主键自增 = 所有表共用一个自增字段=如下图@Query:自定义SQL语句 = 查询、修改、删除语句value:JPQL、SQL语句nativeQuery:默认false,JPQL语句查询,true本地SQL语句查询@Modify:用于标识 修改、删除的方法@Column:标记该列的信息@OneToMany:一对多的注解,一般标识在list属性上@JoinColumn:一对多,多对一,主表主键与关联表外键的定义@ManyToOne:多对一的注解,一般标识在JavaBean属性上@NotFound:没有找到记录时的行为,默认是抛出异常
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!--hibernate对JPA规范的支持包-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.4.30.Final</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.6.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!--监控sql日志 == SQL可以携带参数,如果用JPA自带的SQL打印是没携带参数的-->
<dependency>
<groupId>org.bgee.log4jdbc-log4j2</groupId>
<artifactId>log4jdbc-log4j2-jdbc4.1</artifactId>
<version>1.16</version>
</dependency>
</dependencies>
application.yml == 注意mysql的驱动名以及数据库的连接URL
server:
port: 8080
spring:
datasource:
username: root
password: root
# url: jdbc:mysql://localhost:3306/lrc_blog_test2?useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
url: jdbc:log4jdbc:mysql://localhost:3306/lrc_blog_test2?useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
# driver-class-name: com.mysql.cj.jdbc.Driver
driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
jpa:
show-sql: true
database-platform: org.hibernate.dialect.MySQL8Dialect
database: mysql
hibernate:
# ddl-auto: create
application.yml
server:
port: 8080
spring:
datasource:
username: root
password: root
url: jdbc:mysql://localhost:3306/lrc_blog_test?useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
show-sql: true
database-platform: org.hibernate.dialect.MySQLDialect
database: mysql
open-in-view: true
Book.java
@Getter
@Setter
@ToString
@Entity
@Table(name = "book")
public class Book implements Serializable {
private static final long serialVersionUID = 2095940921263481761L;
/** 主键 - 记录插入自动填充主键处理{@path application.yml} */
@Id
@Column(name = "id")
private String id;
@Column(name = "create_time")
private String createTime;
@Column(name = "update_time")
private String updateTime;
/** 记录是否被逻辑删除:0未删除 1逻辑删除 - 逻辑处理值定义{@path application.yml}*/
@Column(name = "is_del")
private Integer isDel;
/** 书籍状态;-1违规 0发布且公开 1发布且私密 - 默认0 */
@Column(name = "status")
private String status;
/** 书名 */
@Column(name = "name")
private String name;
/** 作者 */
@Column(name = "author")
private String author;
/** 作者国籍 */
@Column(name = "country")
private String country;
/** 下载地址 */
@Column(name = "download_url")
private String downloadUrl;
/** 文件类型 */
@Column(name = "file_type")
private String fileType;
/** 阅读感受 */
@Column(name = "reading_feeling")
private String readingFeeling;
/** 书籍分享者 - 昵称 */
@Column(name = "sharer")
private String sharer;
/** 书籍是否违规:0未违规 1违规 - 违规不可显示 */
@Column(name = "is_violation")
private Integer isViolation;
//书籍状态
public final static String STATUS_VIOLATION = "-1";
public final static String STATUS_PUBLISH_PUBLIC = "0";
public final static String STATUS_PUBLISH_PRIVATE = "1";
}
BookDao.java
@Repository
public interface BookDao extends JpaRepository<Book, String> {
}
JPATest.java
@SpringBootTest
public class JPATest {
@Autowired
BookDao bookDao;
@Test
public void test1() {
List<Book> books = bookDao.findAll();
books.stream().forEach(System.out::println);
}
}
通过方法名,JPA自动识别JPQL语句
SysUserDao.java
@Repository
public interface SysUserDao extends JpaRepository<SysUser, String> {
public SysUser findByIdAndNickName(String id, String nickName);
}
Test.java
@Test
public void test8() {
SysUser sysUser = sysUserDao.findByIdAndNickName("d32478155b6530951cf6b3da56848d5c", "嗯嗯");
System.out.println(sysUser);
}
@Repository
public interface BookDao extends JpaRepository<Book, String>, JpaSpecificationExecutor<Book> {
//JPA根据方法名进行生成SQL
public List<Book> findByNameLike(String name);
//手动写JPQL语句 第一个参数为:?1 第二个参数为:?2 以此类推
@Query("from Book where name like ?1")
public List<Book> findByNamexxx(String name);
//手动写JPQL语句 使用 :参数名 用来填充JPQL的参数
@Query("from Book where name like :name")
public List<Book> findByNamexxx2(String name);
}
test.java
@Test
public void test4() {
List<Book> books = bookDao.findByNameLike("%大脑%");
books.stream().forEach(System.out::println);
System.out.println("\n=========\n");
books = bookDao.findByNamexxx("%大脑%");
books.stream().forEach(System.out::println);
System.out.println("\n=========\n");
books = bookDao.findByNamexxx2("%大脑%");
books.stream().forEach(System.out::println);
}
BookDao.java
@Repository
public interface BookDao extends JpaRepository<Book, String>, JpaSpecificationExecutor<Book> {
@Query(value = "select * from book where name like :name ", nativeQuery = true)
public List<Book> findByNamexxx2(String name);
@Query(value = "select * from book where name like ?1 ", nativeQuery = true)
public List<Book> findByNamexxx3(String name);
}
BookDao.java
@Test
public void test5() {
List<Book> books = bookDao.findByNamexxx2("%大脑%");
books.stream().forEach(System.out::println);
}
@Test
public void test6() {
List<Book> books = bookDao.findByNamexxx3("%大脑%");
books.stream().forEach(System.out::println);
}
dao接口条件继承JpaRepository、JpaSpecificationExecutor这两个接口当需要代码级别控制SQL查询条件,则使用JpaSpecificationExecutor里面的方法查询条件类Specification == toPredicate(Root , CriteriaQuery, CriteriaBuilder)参数1:查询的根对象,查询对象的任务属性都可从此获取参数2:顶层查询对象,用于自定义查询方式(我们很少用)参数3:查询构造器,封装很多的SQL查询条件【like、between等】
关键类Specification:生成where查询条件Sort:记录排序,即order by部分Pageable:分页部分,即limit关键字
BookDao.java
@Repository
public interface BookDao extends JpaRepository<Book, String>, JpaSpecificationExecutor<Book> {
}
Test.java
@Test
public void test9() {
List<SysUser> sysUsers = sysUserDao.findAll(new Specification<SysUser>() {
@Override
public Predicate toPredicate(Root<SysUser> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
Path<Object> nickName = root.get("nickName");
Path<Object> id = root.get("id");
Predicate predicate = criteriaBuilder.equal(nickName, "嗯嗯");
Predicate predicate2 = criteriaBuilder.equal(id, "d32478155b6530951cf6b3da56848d5c");
Predicate and = criteriaBuilder.and(predicate2, predicate);
return and;
}
});
sysUsers.forEach(System.out::println);
}
Test.java
@Test
public void test10() {
//查询条件
Specification<SysUser> whereConditions = new Specification<SysUser>() {
@Override
public Predicate toPredicate(Root<SysUser> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
Path<Object> nickName = root.get("nickName");
Path<Object> id = root.get("id");
Predicate predicate = criteriaBuilder.like(nickName.as(String.class), "%嗯%");
Predicate predicate2 = criteriaBuilder.equal(id, "d32478155b6530951cf6b3da56848d5c");
return criteriaBuilder.or(predicate, predicate2);
}
};
//查询后的记录排序问题
Sort sort = Sort.by(Sort.Direction.DESC, "createTime", "id", "nickName");
List<SysUser> sysUsers = sysUserDao.findAll(whereConditions, sort);
sysUsers.forEach(System.out::println);
}
Test.java
@Test
public void test11() {
//查询条件
Specification<SysUser> whereConditions = new Specification<SysUser>() {
@Override
public Predicate toPredicate(Root<SysUser> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
Path<Object> nickName = root.get("nickName");
Path<Object> id = root.get("id");
Predicate predicate = criteriaBuilder.like(nickName.as(String.class), "%嗯%");
Predicate predicate2 = criteriaBuilder.like(id.as(String.class), "%5%");
return criteriaBuilder.or(predicate, predicate2);
}
};
//查询后的记录排序问题
Sort sort = Sort.by(Sort.Direction.DESC, "createTime");
//分页信息+排序信息
Pageable pageable = PageRequest.of(2, 2, sort);
Page<SysUser> page = sysUserDao.findAll(whereConditions, pageable);
List<SysUser> sysUsers = page.getContent();
sysUsers.forEach(System.out::println);
}
推荐极力不推荐推荐返回值形式1. JavaBean对象2. Object[]:纯列值数组3. Map:列名Key=》列值Value映射模式
BaseDB.java
@Getter
@Setter
@MappedSuperclass
public class BaseDB {
private static final long serialVersionUID = 3253505422347170166L;
/** 主键 - 记录插入自动填充主键处理{@path application.yml} */
@Id
private String id;
@Column(name = "create_time")
private String createTime;
@Column(name = "update_time")
private String updateTime;
/** 记录是否被逻辑删除:0未删除 1逻辑删除 - 逻辑处理值定义{@path application.yml}*/
@Column(name = "is_del")
private Integer isDel;
}
SysUser.java
@Getter
@Setter
@Entity
@Table(name = "sys_user")
public class SysUser extends BaseDB{
@Column(name = "nick_name")
String nickName;
@Column(name = "login_name")
String loginName;
@Override
public String toString() {
return "SysUser{" +
"id='" + getId() + '\'' +
", nickName='" + nickName + '\'' +
", loginName='" + loginName + '\'' +
'}';
}
}
SysUserDao.java
@Repository
public interface SysUserDao extends JpaRepository<SysUser, String> {
@Query(value = "select * from sys_user limit 5", nativeQuery = true)
public List<SysUser> getPage();
/**
* @return Object[] 里面存储该条数据记录的所有列值
*/
@Query(value = "select * from sys_user limit 5", nativeQuery = true)
public List<Object[]> getPage2();
/**
* @return org.springframework.data.jpa.repository.query.AbstractJpaQuery.TupleConverter.TupleBackedMap
*/
@Query(value = "select * from sys_user limit 5", nativeQuery = true)
public List<Map> getPage3();
}
Test.java
@Test
public void test3() {
System.out.println("\n============JavaBean形式-推荐=========\n");
List<SysUser> sysUsers = sysUserDao.getPage();
sysUsers.forEach(System.out::println);
System.out.println("\n==========Object[]纯列值形式-不推荐===========\n");
List<Object[]> sysUsers2 = sysUserDao.getPage2();
sysUsers2.stream()
.map(Arrays::toString)
.forEach(System.out::println);
System.out.println("\n==========Map形式-推荐===========\n");
List<Map> sysUsers3 = sysUserDao.getPage3();
sysUsers3.stream()
.map(HashMap::new)
.forEach(System.out::println);
}
@Repository
@Transactional //增删改需要添加事务支持
public interface BookDao extends JpaRepository<Book, String>, JpaSpecificationExecutor<Book> {
@Query("update Book set name = ?2 where id = ?1")
@Modifying //update需要添加这个注解
@Rollback(false) //执行完不回滚 == 如果你加了前两个注解不能修改数据成功,则添加这个注解上去
public void udpateBookName(String id, String name);
@Query("delete from Book where id = :id and name = :name")
@Modifying
@Rollback(false) //执行完不回滚 == 如果你加了前两个注解不能修改数据成功,则添加这个注解上去
public void deleteByIdName(String id, String name);
}
}
@Test
public void test5() {
bookDao.udpateBookName("0015ac644213f7db45d63e09c6403395", "测试2");
bookDao.deleteByIdName("0015ac644213f7db45d63e09c6403395", "测试");
}
SysUser.java
@Getter
@Setter
@Entity
@Table(name = "sys_user")
public class SysUser extends BaseDB implements Serializable {
@Column(name = "nick_name")
String nickName;
@Column(name = "login_name")
String loginName;
@OneToMany(targetEntity = ArticleComment.class,fetch = FetchType.EAGER)
@JoinColumn(name = "user_id", referencedColumnName = "id")
@NotFound(action= NotFoundAction.IGNORE)
List<ArticleComment> articleComments;
@Override
public String toString() {
return "SysUser{" +
"id='" + getId() + '\'' +
", nickName='" + nickName + '\'' +
", loginName='" + loginName + '\'' +
", createTime='" + getCreateTime() + '\'' +
'}';
}
}
ArticleComment.java
@Getter
@Setter
@Entity
@Table(name = "article_comment")
public class ArticleComment extends BaseDB implements Serializable {
/** 版本号 */
private static final long serialVersionUID = -6282048873013965389L;
@ManyToOne(targetEntity = SysUser.class, fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinColumn(name ="user_id", referencedColumnName = "id")
@NotFound(action= NotFoundAction.IGNORE)
private SysUser sysUser;
/** 评论所属文章 - article表的id - 逻辑外键关联 */
@Column(name = "article_id")
private String articleId;
/** 父评论id - article_comment表的id - 是否是子评论,为空则不是子评论 - 逻辑外键关联 */
@Column(name = "parent_comment_id")
private String parentCommentId;
/** 评论者 - 用户id - user表的id - 逻辑外键关联 */
//@Column(name = "user_id")
//private String userId;
/** 此条评论回复给谁 - 用户ID */
@Column(name = "replier_id")
private String replierId;
/** 评论内容 */
@Column(name = "comment_content")
private String commentContent;
/** 当前评论被点赞数 */
@Column(name = "like_num")
private Integer likeNum;
/** 当前评论不喜欢数 */
@Column(name = "not_like_num")
private Integer notLikeNum;
@Override
public String toString() {
return "ArticleComment{" +
"id='" + getId() + '\'' +
", articleId='" + articleId + '\'' +
", parentCommentId='" + parentCommentId + '\'' +
", replierId='" + replierId + '\'' +
", commentContent='" + commentContent + '\'' +
", likeNum=" + likeNum +
", notLikeNum=" + notLikeNum +
'}';
}
}
SysUserDao.java
@Repository
public interface SysUserDao extends JpaRepository<SysUser, String>, JpaSpecificationExecutor<SysUser> {
@Query(value = "select * from sys_user limit 5", nativeQuery = true)
public List<SysUser> getPage();
/**
* @return Object[] 里面存储该条数据记录的所有列值
*/
@Query(value = "select * from sys_user limit 5", nativeQuery = true)
public List<Object[]> getPage2();
/**
* @return org.springframework.data.jpa.repository.query.AbstractJpaQuery.TupleConverter.TupleBackedMap
*/
@Query(value = "select * from sys_user limit 5", nativeQuery = true)
public List<Map> getPage3();
public SysUser findByIdAndNickName(String id, String nickName);
}
ArticleCommentDao.java
@Repository
public interface ArticleCommentDao extends JpaRepository<ArticleComment, String>, JpaSpecificationExecutor<ArticleComment> {
}
@Test
@Transactional //懒加载的话,找不到代理的异常,如果立即加载则可以不加
public void test13() {
List<SysUser> sysUsers = sysUserDao.getPage();
sysUsers.forEach(sysUser -> {
List<ArticleComment> articleComments = sysUser.getArticleComments();
System.out.println(articleComments.size() + ":" + articleComments);
});
}
@Test
@Rollback(value = false)
@Transactional
public void test16() {
ArticleComment articleComment = articleCommentDao.getOne("1346e1060e95de36d8d8a7bbc8925dfb");
SysUser sysUser = articleComment.getSysUser();
System.out.println(sysUser);
}
主表已含有外键记录
Test.java
@Test
public void test12() {
SysUser sysUser = sysUserDao.findById("c08d391e02bc11eb9416b42e99ea3e69").get();
ArticleComment articleComment = new ArticleComment();
articleComment.setId(UUID.fastUUID().toString(true));
articleComment.setCommentContent("test==articleComment");
articleComment.setSysUser(sysUser);
articleCommentDao.save(articleComment);
}
主表未含有外键记录
@Test
@Rollback(value = false)
@Transactional
public void test15() {
SysUser sysUser = new SysUser();
sysUser.setId(UUID.fastUUID().toString(true));
sysUser.setNickName(String.valueOf("爱你test"));
ArticleComment articleComment = new ArticleComment();
articleComment.setId(UUID.fastUUID().toString(true));
articleComment.setSysUser(sysUser);
articleComment.setCommentContent(String.valueOf("test==articleComment"));
sysUserDao.save(sysUser);
articleCommentDao.save(articleComment);
}
Role.java
@Getter
@Setter
@Entity
@Table(name = "role")
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id2;
@Column(name = "role_name")
String roleName;
@ManyToMany(targetEntity = User.class, fetch = FetchType.EAGER)
@JoinTable(name = "user_role_rel",
//当前表与中间表的关系
joinColumns = {@JoinColumn(name = "role_id", referencedColumnName = "id2")},
//另一个表与中间表的关系
inverseJoinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id1")})
List<User> roles;
}
User.java
@Getter
@Setter
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id1;
@Column(name = "user_name")
String userName;
@ManyToMany(targetEntity = Role.class, fetch = FetchType.EAGER)
@JoinTable(name = "user_role_rel",
//当前表与中间表的关系
joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id1")},
//另一个表与中间表的关系
inverseJoinColumns = {@JoinColumn(name = "role_id", referencedColumnName = "id2")})
List<Role> roles;
}
Test.java
@Test
@Rollback(value = false)
@Transactional
public void test17() {
User user = new User();
user.setUserName("lrc2");
Role role = new Role();
role.setRoleName("游客2");
//中间表关系维护 == 如果不加中间表的数据为空
role.setRoles(Arrays.asList(user));
userDao.save(user);
roleDao.save(role);
}
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/weixin_39651356/article/details/125329448
内容来源于网络,如有侵权,请联系作者删除!