SpringDataJpa详解(二)

1.qbe查询

Probe:具有填充字段的域对象的实际实体类,即查询条件封装类[必填]

ExampleMatcher:如何匹配特定字段的匹配规则,可以重复使用多个示例。

Example:由探针和ExampleMatcher组成,用于创建查询。

限制:

1.不支持or

2.仅支持正则表达式等

@ToString
@NoArgsConstructor
@Setter
@Getter
@Entity
@Table(name = "tb_user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private long id;
    @Column(name = "name")
    private String name;
    //注意映射的值~!
    @Enumerated(EnumType.STRING)
    @Column(name = "gender")
    private Gender gender;
}

@AllArgsConstructor
@Getter
public enum Gender {
    MAIL("男性"),FMAIL("女性");
    private String name;
}


public interface UserRepository extends JpaRepository<User,Long> {
}

    @Test
    public void test3(){
        //需要忽略掉主键,否则会查询
        ExampleMatcher matcher=ExampleMatcher.matching().withMatcher("name", ExampleMatcher.GenericPropertyMatcher.of(ExampleMatcher.StringMatcher.STARTING))
                //类似于条件的构建,有很多的with
                .withIgnorePaths("id");
        User user=new User();
        user.setName("peace");
        Example<User> ex= Example.of(user,matcher);
        System.out.println(this.userRepository.findAll(ex));
    }

2.JpaSpecificationExecutor的使用方法

Root<T>root:代表了可以查询操作的实体对象的根

CriteriaQuery<?> query:代表一个specific的顶层查询对象

CriteriaBuilder:用来构建CritiaQuery的构建器对象,起始相当于条件或者条件组合

@ToString
@Setter
@Getter
@Entity
@Table(name = "tb_stu")
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id",unique = true,nullable = false)
    private Long id;
    @Column(name = "name",columnDefinition = "姓名")
    private String name;
    @Column(name = "age",columnDefinition = "年龄")
    private Integer age;
    @Column(name = "gender",columnDefinition = "性别")
    private Character gender;
}

//JpaSpecificationExecutor接口不能单独使用,需要配置Jpa中其他接口一起使用
public interface StuRepo extends JpaRepository<Student,Long>,JpaSpecificationExecutor<Student> ,UdStuRepository{
    @Query(value = "from Student where name= :username ")
    Student findBJpql(String username);

    @Query(value = "select * from tb_stu where name= ?",nativeQuery = true)
    List<Student> findBySql(String username);

    @Query(value = "update Student set name=:username where id=:id")
    @Modifying//说明当前语句是更新语句
    void updateByJpql(String username,long id);


}

    @Test
    public void test5() {
        Specification<Student> spec = new Specification<Student>() {
            /**
             * 定义了查询条件
             * @param root select * from t_users 封装了查询条件对象
             * @param query 定义了一个基本的查询,查询了那些字段,排序是什么
             * @param criteriaBuilder 创建一个查询条件
             * @return
             */
            @Override
            public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                Predicate pre = criteriaBuilder.equal(root.get("name").as(String.class), "111");
//                return pre;
                //注意这种写法!返回的行以及对行的操作!
                return query.where(pre).getRestriction();
            }
        };
        Optional<Student> student = this.stuRepo.findOne(spec);
        System.out.println(student.get());
    }

自定义Repository

@ToString
@Setter
@Getter
@Entity
@Table(name = "tb_stu")
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id",unique = true,nullable = false)
    private Long id;
    @Column(name = "name",columnDefinition = "姓名")
    private String name;
    @Column(name = "age",columnDefinition = "年龄")
    private Integer age;
    @Column(name = "gender",columnDefinition = "性别")
    private Character gender;
}

@Repository(value = "UdStuRepository")
public interface UdStuRepository {
    public Student findUserById(Long id);
}


//自定义方法注意命名
public class UdStuRepositoryImpl implements UdStuRepository {
    @PersistenceContext(name = "entityManagerFactory")
    private EntityManager em;

    @Override
    public Student findUserById(Long id) {
        System.out.println("UDRepository");
        return em.find(Student.class,id);
    }
}

通常的封装方式为

3.实体监听器

自定义实体监听器:

https://blog.csdn.net/weixin_37968613/article/details/88554236

使用步骤:

【1】在对应注解中使用@EntityListener来引入监听器

【2】在对应的属性上引入@CreateBy

【3】实现AuditorAware接口告诉Jpa当前用户是谁

【4】enableJpaRepository上开启功能

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "tb_traveler")
@EntityListeners(AuditingEntityListener.class)
public class Traveler {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;
    @Column(name = "name")
    private String name;
    @Column(name = "address")
    private String address;
    @CreatedBy
    @Column(name = "createUserid")
    private String createUserid;
    @LastModifiedBy
    @Column(name = "lastModifiedUserid")
    private String lastModifiedUserid;
    @CreatedDate
    @Column(name = "createTime")
    private LocalDateTime createTime;
    @LastModifiedDate
    @Column(name = "lastModifiedTime")
    private LocalDateTime lastModifiedTime;
}

public interface TravelerRepository extends JpaRepository<Traveler,Long> {
}

public class MyAuditorAware implements AuditorAware<String> {
    @Override
    public Optional<String> getCurrentAuditor() {
        //两种方式
        //1.和SecurityContextHolder获取
        //2.通过request里卖弄获取或者session里面取得
        ServletRequestAttributes servletRequestAttributes=(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        String ip=servletRequestAttributes.getRequest().getRemoteAddr();
        return Optional.ofNullable(ip);
    }
}

    @Test
    public void test4(){
        Traveler t=new Traveler();
        t.setName("hello");
        t.setAddress("zhengzhou");
        this.travelerRepository.save(t);
    }

MappedSuperclass:

https://www.cnblogs.com/zqyanywn/p/7753596.html

1.标注为@MappedSuperclass的类将不是一个完整的实体类,他将不会映射到数据库表,但是他的属性都将映射到其子类的数据库字段中。

2.标注为@MappedSuperclass的类不能再标注@Entity或@Table注解,也无需实现序列化接口。

@EntityListeners(AuditingEntityListener.class)
@MappedSuperclass
public abstract class AbstractAutitable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;
    @CreatedDate
    @Column(name = "createTime")
    private LocalDateTime createTime;
    @LastModifiedDate
    @Column(name = "lastModifiedTime")
    private LocalDateTime lastModifiedTime;
    @CreatedBy
    @Column(name = "createBy")
    private String createBy;
    @LastModifiedBy
    @Column(name = "lastModifidBy")
    private String lastModifidBy;
}

编写需要自定义实体监听器需要注意的地方

3.乐观锁的使用

-- 悲观锁
select * from user where id=1 for update;
update user set name='jack' where id=1;
-- 乐观锁
select uid,name,version from user where id=1;
update user set name='jack',version=version+1 where id=1 and version=1;

spring data jpa通过aop动态维护这个version值,从而更优雅地实现乐观锁。

实现原理关键源码

@EnbaleSpringDataWebSupport对web的支持,不怎么用

@PageableDefault改变默认的page和size

主从表的使用@MapKey

https://blog.csdn.net/wwwcomy/article/details/84922934

Druid配置,在阅读的时间需要查看配置类,按名知意的可以查看源码:

package com.alibaba.druid.spring.boot.autoconfigure;

然后点击对应的类来获取信息

对@Transactional注解的支持

事务隔离级别:

该注解需要注意的:

1.@Transactional只能被应用到public方法上,如果不是该访问权限,不会生效

2.用Spring事务管理器,由Spring来负责数据库打开、提交、回滚。遇到不受检查的例外会回滚。

3.建议在具体的类上使用@Transactional注解,如果你在使用基于类的代理是,事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装。

4.事务有两种配置方法,aspectj也能配置!

声明式事务:

猜你喜欢

转载自blog.csdn.net/qq_29164145/article/details/90746384